// problems passing arguments by reference

// i had thought that one of the following methods had resulted in the
// shared copy being modified.  but, that was r.pixmap, when it was an
// IntegerMatrix -- so was actually a bug in my code (which should
// have called something like the C "NAMED()" macro, and then the C
// function "duplicate" to copy it if the result was > 0).

// but, the Rcpp_module.pdf document has this statement: "A free
// function that takes a pointer to the target class as its first
// parameter, followed by 0 or more (up to 65) parameters that can be
// handled by Rcpp::as and returning a type that can be handled by
// Rcpp::wrap or void."  i am not sure what a "free function" is.

// okay, define as a .method in the class, define the formal to be
// space2d*, and it all works.  see the "psps" and "vps" methods
// below.

// to run, first put the source in inc
// (inc <- <SINGLEQUOTE><SOURCE><SINGLEQUOTE>)
// then do something like:

#if 0

require(inline);
require(Rcpp);

cld <- cxxfunction(,plugin="Rcpp", includes=inc);

clm <- Module("test6_module", getDynLib(cld));
space2d <- clm$space2d;

## basic reference class aliasing (all normal)
x <- new(space2d);
y <- x;
print(x$get(1));
print(y$get(1));
print("change");
x$set(1,1);
print(x$get(1));
print(y$get(1));

print("ss");
x <- new(space2d);
print(x$get(1));
y <- clm$ss(x,1);
print(x$get(1));
print(y$get(1));

print("vs");
x <- new(space2d);
print(x$get(1));
clm$vs(x, 1);
print(x$get(1));

print("ll");
x <- new(space2d);
print(x$get(1));
y <- clm$ll(list(x), 1)
print(x$get(1));
print(y[[1]][[1]]$get(1));

print("vl");
x <- new(space2d);
print(x$get(1));
clm$vl(list(x), 1)
print(x$get(1));

print("imim");
x <- matrix(0,nrow=2,ncol=2)
print(x[2,2]);
y <- clm$imim(x,1)
print(x[2,2]);
print(y[2,2]);

print("vim");
x <- matrix(0,nrow=2,ncol=2)
print(x[2,2]);
clm$vim(x,1)
print(x[2,2]);

print("psps");
x <- new(space2d);
print(x$get(1));
y <- x$psps(1)
print(x$get(1));
print(y$get(1));
print("are x and y linked?")
y$set(1,2)
print(x$get(1));
print(y$get(1));

print("vps");
x <- new(space2d);
print(x$get(1));
x$vps(1)
print(x$get(1));


if (FALSE && "the following tests do not compile, so are commented out") {
    print("imrim");
    x <- matrix(0,nrow=2,ncol=2);
    print(x[2,2]);
    y <- clm$imrim(x,1);
    print(x[2,2]);
    print(y[2,2]);

    print("vrim");
    x <- matrix(0,nrow=2,ncol=2);
    print(x[2,2]);
    clm$vrim(x,1);
    print(x[2,2]);
}

#endif /* 0 */

#include <R.h>
#include <RcppCommon.h>
#include <Rcpp/S4.h>

#include <Rcpp.h>

class space2d {
public:
    std::vector<int> values;    // the actual bits
public:
    space2d() {
        values = std::vector<int>(16,0);
    }
    inline int get(int p) const {
        return values[p];   /* XXX there was a "1+" here */
    }
    inline void set(int p, int val) {
        values[p] = val;
    };
};

/////////////////////////////


Rcpp::List space2d2rlist(space2d space) {
    return Rcpp::List::create(Rcpp::Named("space2d",
                                          Rcpp::module_wrap<space2d>(space)));
}


space2d rlist2space2d(Rcpp::List list) {
    return list[0];
}


/////////////////////////////


space2d ss(space2d arg, int val) {
    arg.set(1, val);
    return arg;
}

void vs(space2d arg, int val) {
    arg.set(1, val);
}

Rcpp::List ll(Rcpp::List arg, int val) {
    space2d s2d = rlist2space2d(arg);

    s2d.set(1, val);
    return Rcpp::List::create(Rcpp::Named("space2d", space2d2rlist(s2d)));
}

void vl(Rcpp::List arg, int val) {
    space2d s2d = rlist2space2d(arg);
    s2d.set(1, val);
}

Rcpp::IntegerMatrix imim(Rcpp::IntegerMatrix arg, int val) {
    arg(1,1) = val;
    return arg;
}

void vim(Rcpp::IntegerMatrix arg, int val) {
    arg(1,1) = val;
}

#if defined(FAIL)
Rcpp::IntegerMatrix imrim(Rcpp::IntegerMatrix& arg, int val) {
    arg(1,1) = val;
    return arg;
}

void vrim(Rcpp::IntegerMatrix& arg, int val) {
    arg(1,1) = val;
}
#endif /* defined(FAIL) */

space2d* psps(space2d* arg, int val) {
    arg->set(1, val);
    return arg;
}

void vps(space2d* arg, int val) {
    arg->set(1, val);
}

RCPP_EXPOSED_CLASS(space2d)

using namespace Rcpp;
RCPP_MODULE(test6_module) {
    class_<space2d>("space2d")
        .constructor()
        .method("get", &space2d::get)
        .method("set", &space2d::set)
        .method("psps", &psps)
        .method("vps", &vps);
    function("ss", &ss);
    function("vs", &vs);
    function("ll", &ll);
    function("vl", &vl);
    function("imim", &imim);
    function("vim", &vim);
#if defined(FAIL)
    function("imrim", &imrim);
    function("vrim", &vrim);
#endif /* defined(FAIL) */
}
