#ifndef NETWORK_SCORES_HEADER
#define NETWORK_SCORES_HEADER

#include "../core/contingency.tables.h"
#include "../core/data.table.h"
#include "../math/reweighted.least.squares.h"
#include "../math/sparse.amat.h"

/* enum for scores, to be matched from the label string passed down from R. */
typedef enum {
  ENOSCORE       =   0, /* error code, no such score. */

  /* scores for discrete data. */
  LOGLIK         =   1, /* log-likelihood. */
  PRED_LOGLIK    =   2, /* predictive log-likelihood. */
  AIC            =   3, /* AIC. */
  BIC            =   4, /* BIC. */
  EBIC           =   5, /* extended BIC. */
  BDE            =   6, /* Bayesian Dirichlet equivalent score. */
  BDS            =   7, /* Bayesian Dirichlet sparse score. */
  BDJ            =   8, /* Bayesian Dirichlet with Jeffrey's prior. */
  K2             =   9, /* K2 score. */
  MBDE           =  10, /* Bayesian Dirichlet equivalent score, interventional data .*/
  FNML           =  11, /* Factorized Normalized Maximum Likelihood. */
  QNML           =  12, /* Quotient Normalized Maximum Likelihood. */
  NAL            =  13, /* Node-average likelihood. */
  PNAL           =  14, /* Penalized node-average likelihood. */

  /* scores for Gaussian data. */
  LOGLIK_G       = 100, /* log-likelihood. */
  PRED_LOGLIK_G  = 101, /* predictive log-likelihood. */
  AIC_G          = 102, /* AIC. */
  BIC_G          = 103, /* BIC. */
  EBIC_G         = 104, /* extended BIC. */
  BGE            = 105, /* Bayesian Gaussian equivalent score. */
  NAL_G          = 106, /* Node-average likelihood. */
  PNAL_G         = 107, /* Penalized node-average likelihood. */

  /* scores for zero-inflated count data. */
  LOGLIK_ZIHP    = 108, /* hyper-Poisson log-likelihood. */
  LOGLIK_ZINB    = 109, /* negative Binomial log-likelihood. */
  AIC_ZIHP       = 110, /* hyper-Poisson AIC. */
  BIC_ZIHP       = 111, /* hyper-Poisson BIC. */
  AIC_ZINB       = 112, /* negative Binomial AIC. */
  BIC_ZINB       = 113, /* negative Binomial BIC. */
  NAL_ZIHP       = 114, /* Node average likelihood, zero-inflated hyper-Poisson. */
  PNAL_ZIHP      = 115, /* Penalized node-average likelihood. */
  NAL_ZINB       = 116, /* Node average likelihood, zero-inflated negative binomial. */
  PNAL_ZINB      = 117, /* enalized node-average likelihood. */

  /* scores for conditional Gaussian data. */
  LOGLIK_CG      = 200, /* log-likelihood. */
  PRED_LOGLIK_CG = 201, /* predictive log-likelihood. */
  AIC_CG         = 202, /* AIC. */
  BIC_CG         = 203, /* BIC. */
  EBIC_CG        = 204, /* extended BIC. */
  NAL_CG         = 205, /* Node-average likelihood. */
  PNAL_CG        = 206, /* Penalized node-average likelihood. */

  CUSTOM         = 300  /* user-provided score function. */
} score_e;

score_e score_to_enum(const char *label);

/* enum for graph priors, to be matched from the label string passed down from R. */
typedef enum {
  ENOPRIOR  =  0, /* error code, no such graph prior. */
  UNIFORM   =  1, /* uniform prior. */
  VSP       =  2, /* variable selection prior. */
  CS        =  3, /* Castelo & Siebes prior. */
  MU        =  4, /* marginal uniform prior. */
} gprior_e;

gprior_e gprior_to_enum(const char *label);

/* score delta from score.delta.c */
SEXP score_delta(SEXP arc, SEXP network, SEXP data, SEXP score,
    SEXP score_delta, SEXP reference_score, SEXP op, SEXP extra, SEXP decomposable);
double score_delta_cs_core(SEXP arc, int fi, int ti, sparse_amat base, SEXP data,
    SEXP score, SEXP reference_score, const char *op, SEXP extra, double *new);
double robust_score_difference(double old1, double old2, double new1,
    double new2);

/* from graph.priors.c */
double graph_prior_prob(SEXP prior, SEXP target, SEXP beta,
    sparse_amat parents_sam, bool debugging);

/* from per.node.score.c */
SEXP per_node_score(SEXP network, SEXP data, SEXP score, SEXP targets,
    SEXP extra_args, SEXP debug);
void c_per_node_score(sparse_amat sam, SEXP data, SEXP score,
    SEXP targets, SEXP extra_args, bool debugging, double *res);

/* score functions exported to per.node.score.c and to other score functions */
double dlik(counts1d marginal);
double cdlik(counts2d joint);
double loglik_dnode_root(int *x, int llx, int nobs, double *nparams);
double loglik_dnode_parents(int *x, int llx, int *y, int lly, int nobs,
    double *nparams);
double loglik_dnode(SEXP target, sparse_amat sam, tabular dt, double *nparams,
    int *nparents, bool debugging);
double pdnode(int *x, int llx, int nobs, int *new_x, int new_nobs,
    double *nparams);
double cpdnode(int *x, int llx, int *y, int lly, int nobs, int *x2, int *y2,
    int new_nobs, double *nparams);
double predictive_loglik_dnode(SEXP target, sparse_amat sam, tabular dt, tabular newdt,
    double *nparams, bool debugging);
double glik(double *xx, int num, double *nparams);
double cglik(double *xx, int nrow, double **dd, int ncol, double *nparams);
double pgnode(double *x, int nobs, double *new_x, int new_nobs,
    double *nparams);
double cpgnode(double *x, int nobs, double *new_x, int new_nobs, double **dd,
    double **dd2, int ncol, double *nparams);
double predictive_loglik_gnode(SEXP target, sparse_amat sam, tabular dt, tabular newdt,
    double *nparams, bool debugging);
double c_fast_ccgloglik(double *xx, double **gp, int ngp, int nobs, int *config,
    int nconfig);
double loglik_gnode(SEXP target, sparse_amat sam, tabular dt, double *nparams,
    int *nparents, bool debugging);
double loglik_cgnode(SEXP target, sparse_amat sam, tabular dt, double *nparams,
    int *np, bool debugging);
double predictive_loglik_cgnode(SEXP target, sparse_amat sam, tabular dt, tabular newdt,
    double *nparams, bool debugging);
double dirichlet_node(SEXP target, sparse_amat sam, tabular dt, SEXP iss, int per_node,
    SEXP prior, SEXP beta, SEXP experimental, int sparse, bool debugging);
double wishart_node(SEXP target, sparse_amat sam, tabular dt, SEXP iss, SEXP nu,
    SEXP iss_w, SEXP prior, SEXP beta, bool debugging);
double custom_score_function(SEXP target, sparse_amat sam, SEXP data, SEXP custom_fn,
    SEXP custom_args, bool debugging);
double fnml_node(SEXP target, sparse_amat sam, tabular dt, bool debugging);
double qnml_node(SEXP target, sparse_amat sam, tabular dt, bool debugging);
double nal_dnode_root(int *x, int llx, int nobs, double k);
double nal_dnode_parents(int *x, int llx, int *y, int lly, int nobs, double k);
double nal_dnode(SEXP target, sparse_amat sam, tabular dt, double k, bool debugging);
double glik_incomplete(double *x, int nobs, double k);
double cglik_incomplete(double *x, int nobs, double **dd, int ncol, double k);
double nal_gnode(SEXP target, sparse_amat sam, tabular dt, double k, bool debugging);
double nal_cgnode(SEXP target, sparse_amat sam, tabular dt, double k, bool debugging);
double em_irls_node(SEXP target, sparse_amat sam, tabular dt, double *estimates,
    double *nparams, bool pnal, double k, bool debugging, int em_max_iter,
    double em_tol, bool one_step, glm_family_e family);

/* exports for the regret table of normalized maximum likelihood scores. */
#define MAX_REGRET_TABLE_N 1000
#define MAX_REGRET_TABLE_K 100
extern double *regret_table;

double nml_regret(double n, double k);
double *get_regret_table(int N, int K);

/* reparameteriazation functions for zero-inflated scores. */
void zihp_coefs_to_params(double *zinf_prob, double *zinf_coefs,
    double *intensity, double *inten_coefs, tabular data);
void zinb_coefs_to_params(double *zinf_prob, double *zinf_coefs,
    double *succ_prob, double *succ_coefs, tabular data);

#endif
