#include <R.h>
#include <Rinternals.h>
#include <R_ext/Rdynload.h>

// Fortran subroutine declarations
void F77_NAME(treegrowth)(double *fixweight, int *maxdepth, int *minbucket, 
                         int *minsplit, double *alpha, int *msize, int *colnum, 
                         int *levelcount, double *xydata, int *datatype, 
                         double *beta1, double *beta2, int *beta1len, 
                         int *beta2len, int *nodenummat, double *allfval, 
                         int *prunind, double *Rsplitmat);

void F77_NAME(cvtreepruning)(int *prunind, int *msize, double *alpha, 
                            double *gamma, int *cv, int *maxdepth, 
                            int *nodenummat, double *allfval, 
                            double *allgammaval);

void F77_NAME(crossvalidation)(double *gamma, double *alpha, int *cv, 
                              double *d, int *msize, int *colnum, int *xval, 
                              int *timecount, int *maxdepth, double *beta1, 
                              double *beta2, int *beta1len, int *beta2len, 
                              int *minbucket, int *minsplit, double *weight, 
                              int *datatype, double *allgammaval, 
                              double *bestgammaval, double *r2cvval,
                              int *iseed);

void F77_NAME(gammatreepruning)(int *prunind, int *msize, double *bestgammaval, 
                               int *cv, int *maxdepth, int *nodenummat, 
                               double *allfval, int *prunenodenummat);

void F77_NAME(treepredict)(int *msize, int *timecount, int *maxdepth, 
                          int *colnum, int *prunenodenummat, double *d, 
                          double *predvec, int *datatnnodenum);

// Additional Fortran routines for longitree package
void F77_NAME(nodedata)(double *d, int *msize, int *colnum, int *node, int *level, int *maxdepth, int *nmat, int *ms, double *nd);
void F77_NAME(splitvec)(double *nd, int *ms, int *colnum, int *msize, int *maxdepth, int *datatype, int *nmat, int *splitvar, int *splitpoint, int *ndsize, double *splitnumber, int *splitvector);
void F77_NAME(threetreesbootstrap)(int *nrow, int *bootsize, int *ncol, double *d, int *timecount, double *bootdata, int *oridata);
void F77_NAME(threetreesboottreegrowth)(int *nodenummatboot, int *nodenummatori, double *allfval, int *prunind, int *bootdatasize,
                                       int *colnum, double *bootdata, int *datatype, double *weight, double *beta1, double *beta2,
                                       int *beta1len, int *beta2len, int *timecount, int *minbucket, double *d, int *msize,
                                       double *alpha, int *maxdepth, int *minsplit);
void F77_NAME(threetreesbootcvtreepruning)(int *prunind, int *bootdatasize, double *alpha, double *gamma, int *cv,
                                           int *maxdepth, int *nodenummatboot, double *allfval, double *allgammaval);
void F77_NAME(threetreesbootcrossvaridation)(double *gamma, double *alpha, int *cv, double *bootdata, int *bootdatasize,
                                             int *colnum, int *xval, int *timecount, int *maxdepth, double *beta1, double *beta2,
                                             int *beta1len, int *beta2len, int *minbucket, int *minsplit, double *weight,
                                             int *datatype, double *allgammaval, double *bestgammaval, int *cvsplitind,
                                             int *iseed);
void F77_NAME(threetreesbootgammatreepruning)(int *prunind, int *bootdatasize, int *msize, double *bestgammaval,
                                              int *cv, int *maxdepth, int *nodenummatboot, int *nodenummatori, double *allfval,
                                              int *prunenodenummatboot, int *prunenodenummatori);
void F77_NAME(threetreesboottreepredict)(int *msize, int *bootdatasize, int *timecount, int *maxdepth,
                                         int *prunenodenummatboot, int *prunenodenummatori, double *bootdata, double *d,
                                         int *colnum, double *predvec, int *datatnnodenum);
void F77_NAME(threetreestreechoice)(double *predvecmat, int *datatnnodenummat, int *msize, int *trees, int *timecount,
                                    double *d, int *colnum, int *mins, int *bettertreenum, double *bettertreelossval,
                                    double *bettertreemaxval);
void F77_NAME(threetreestreegrowth)(double *weight, int *maxdepth, int *minbucket, int *minsplit, double *alpha,
                                    int *msize, int *colnum, int *timecount, double *d, int *datatype, double *beta1, double *beta2,
                                    int *beta1len, int *beta2len, int *nodenummat, double *allfval, int *prunind, double *Rsplitmat);
void F77_NAME(threetreescvtreepruning)(int *prunind, int *msize, double *alpha, double *gamma, int *cv, int *maxdepth,
                                       int *nodenummat, double *allfval, double *allgammaval);
void F77_NAME(threetreesthreetreecv)(double *gamma, double *alpha, int *cv, double *d1, double *d2, double *d3,
                                     int *bootdatasize, int *colnum, int *xval, int *timecount, int *maxdepth,
                                     double *beta1, double *beta2, int *beta1len, int *beta2len, int *minbucket,
                                     int *minsplit, double *weight, int *datatype, double *allgammaval1, double *allgammaval2,
                                     double *allgammaval3, double *bestgammaval1, double *bestgammaval2, double *bestgammaval3,
                                     double *r2cvval1, double *r2cvval2, double *r2cvval3, double *r2cvvalthree,
                                     int *cvsplitind1, int *cvsplitind2, int *cvsplitind3, int *iseed);
void F77_NAME(threetreesgammatreepruning)(int *prunind, int *msize, double *bestgammaval, int *cv, int *maxdepth, int *nodenummat, double *allfval, int *prunenodenummat);
void F77_NAME(threetreestreepredict)(int *bootdatasize, int *timecount, int *maxdepth, int *colnum, int *prunenodenummat, double *d, double *predvec, int *datatnnodenum);
void F77_NAME(threetreesnodedata)(double *d, int *msize, int *colnum, int *node, int *level, int *nmat, int *ms, double *nd);
void F77_NAME(threetreessplitvec)(double *nd, int *ms, int *colnum, int *msize, int *maxdepth, int *datatype, int *nmat, int *splitvar, int *splitpoint, int *ndsize, double *splitnumber, int *splitvector);

// Registration table
static const R_FortranMethodDef FortranEntries[] = {
    {"treegrowth", (DL_FUNC) &F77_NAME(treegrowth), 18},
    {"cvtreepruning", (DL_FUNC) &F77_NAME(cvtreepruning), 9},
    {"crossvalidation", (DL_FUNC) &F77_NAME(crossvalidation), 21},
    {"gammatreepruning", (DL_FUNC) &F77_NAME(gammatreepruning), 8},
    {"treepredict", (DL_FUNC) &F77_NAME(treepredict), 8},
    {"nodedata", (DL_FUNC) &F77_NAME(nodedata), 9},
    {"splitvec", (DL_FUNC) &F77_NAME(splitvec), 12},
    {"threetreesbootstrap", (DL_FUNC) &F77_NAME(threetreesbootstrap), 7},
    {"threetreesboottreegrowth", (DL_FUNC) &F77_NAME(threetreesboottreegrowth), 20},
    {"threetreesbootcvtreepruning", (DL_FUNC) &F77_NAME(threetreesbootcvtreepruning), 9},
    {"threetreesbootcrossvaridation", (DL_FUNC) &F77_NAME(threetreesbootcrossvaridation), 21},
    {"threetreesbootgammatreepruning", (DL_FUNC) &F77_NAME(threetreesbootgammatreepruning), 11},
    {"threetreesboottreepredict", (DL_FUNC) &F77_NAME(threetreesboottreepredict), 11},
    {"threetreestreechoice", (DL_FUNC) &F77_NAME(threetreestreechoice), 11},
    {"threetreestreegrowth", (DL_FUNC) &F77_NAME(threetreestreegrowth), 18},
    {"threetreescvtreepruning", (DL_FUNC) &F77_NAME(threetreescvtreepruning), 9},
    {"threetreesthreetreecv", (DL_FUNC) &F77_NAME(threetreesthreetreecv), 33},
    {"threetreesgammatreepruning", (DL_FUNC) &F77_NAME(threetreesgammatreepruning), 8},
    {"threetreestreepredict", (DL_FUNC) &F77_NAME(threetreestreepredict), 8},
    {"threetreesnodedata", (DL_FUNC) &F77_NAME(threetreesnodedata), 8},
    {"threetreessplitvec", (DL_FUNC) &F77_NAME(threetreessplitvec), 12},
    {NULL, NULL, 0}
};

void R_init_longitree(DllInfo *dll) {
    R_registerRoutines(dll, NULL, NULL, FortranEntries, NULL);
    R_useDynamicSymbols(dll, FALSE);
}
