#include <R.h>
#include <Rinternals.h>
#include <stdlib.h> // for NULL
#include <R_ext/Rdynload.h>
#include "mgcv.h"
#include "../inst/include/crs_nomad_native.h"

/* .C calls */
extern void RuniqueCombs(void *, void *, void *, void *);
extern void gsl_bspline(void *, void *, void *, void *, void *, void *, void *, void *, void *);
extern void gsl_bspline_deriv(void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *);

/* .Call calls */
extern SEXP smultinomadRSolve(SEXP);
extern SEXP snomadRInfo(SEXP);
extern SEXP snomadRSolve(SEXP);
extern SEXP crs_nomad_native_test_solve(SEXP);
extern SEXP crs_hat_diag(SEXP, SEXP, SEXP);
extern SEXP crs_uniquecombs_call(SEXP);
extern SEXP crs_gsl_bspline_call(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP);
extern SEXP crs_gsl_bspline_deriv_call(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP);
extern SEXP crs_prod_kernel_matrix(SEXP, SEXP, SEXP, SEXP);

static const R_CMethodDef CEntries[] = {
    {"RuniqueCombs",      (DL_FUNC) &RuniqueCombs,       4},
    {"gsl_bspline",       (DL_FUNC) &gsl_bspline,        9},
    {"gsl_bspline_deriv", (DL_FUNC) &gsl_bspline_deriv, 11},
    {NULL, NULL, 0}
};

static const R_CallMethodDef CallEntries[] = {
    {"glp_model_tmm",     (DL_FUNC) &glp_model_tmm,     7}, 
    {"mgcv_tmm",          (DL_FUNC) &mgcv_tmm,          5}, 
    {"smultinomadRSolve", (DL_FUNC) &smultinomadRSolve, 1},
    {"snomadRInfo",       (DL_FUNC) &snomadRInfo,       1},
    {"snomadRSolve",      (DL_FUNC) &snomadRSolve,      1},
    {"crs_nomad_native_test_solve", (DL_FUNC) &crs_nomad_native_test_solve, 1},
    {"crs_hat_diag",      (DL_FUNC) &crs_hat_diag,      3},
    {"crs_uniquecombs_call", (DL_FUNC) &crs_uniquecombs_call, 1},
    {"crs_gsl_bspline_call", (DL_FUNC) &crs_gsl_bspline_call, 6},
    {"crs_gsl_bspline_deriv_call", (DL_FUNC) &crs_gsl_bspline_deriv_call, 7},
    {"crs_prod_kernel_matrix", (DL_FUNC) &crs_prod_kernel_matrix, 4},
    {NULL, NULL, 0}
};

void R_init_crs(DllInfo *dll)
{
    R_registerRoutines(dll, CEntries, CallEntries, NULL, NULL);
    R_useDynamicSymbols(dll, FALSE);
    R_RegisterCCallable("crs", "crs_nomad_solve",
                        (DL_FUNC) crs_nomad_solve);
    R_RegisterCCallable("crs", "crs_nomad_solve_observed",
                        (DL_FUNC) crs_nomad_solve_observed);
    R_RegisterCCallable("crs", "crs_nomad_observer_poll",
                        (DL_FUNC) crs_nomad_observer_poll);
}
