#ifndef TEST_PATTERNS_HEADER
#define TEST_PATTERNS_HEADER

#include "../core/data.table.h"
#include "tests.h"

/* unconditional tests. */
double ut_discrete(tabular dtx, tabular dty, double *pvalue, double *df,
    test_e test);
double ut_gaustests(tabular dtx, tabular dty, double *pvalue, double *df,
    test_e test);
double ut_micg(tabular dtx, tabular dty, double *pvalue, double *df);
double ut_dperm(tabular dtx, tabular dty, double *pvalue, double *df,
    test_e type, int B, double a);
double ut_gperm(tabular dtx, tabular dty, double *pvalue, test_e type, int B,
    double a, bool complete);

/* conditional tests. */
double ct_discrete(tabular dtx, tabular dty, tabular dtz, double *pvalue, double *df,
    test_e test);
double ct_gaustests(tabular dtx, tabular dt, double *pvalue, double *df,
    test_e test);
double c_micg_chisq(tabular dtx, tabular dty, tabular dtz, int *zptr, int llz,
    double *df, bool copy);
double ct_micg(tabular dtx, tabular dty, tabular dtz, double *pvalue,
    double *df);
double ct_dperm(tabular dtx, tabular dty, tabular dtz, double *pvalue, double *df,
    test_e type, int B, double a);
double ct_gperm(tabular dtx, tabular dt, double *pvalue, double *df, test_e type,
    int B, double a, bool complete);

/* round-robin tests. */
void rrd_discrete(tabular dtx, tabular dtz, test_e test, double *pvalue,
    double alpha, bool debugging);
void rrd_gaustests(tabular dt, test_e test, double *pvalue, double alpha,
    bool debugging);
double rrd_micg_chisq(tabular dtx, tabular dty, tabular sub, int *zptr, int llz,
    double *df, bool copy);
void rrd_micg(tabular dtx, tabular dtz, test_e test, double *pvalue,
    double alpha, bool debugging);
void rrd_dperm(tabular dtx, tabular dtz, test_e test, double *pvalue, double alpha,
    int nperms, double threshold, bool debugging);
void rrd_gperm(tabular dt, test_e test, double *pvalue, double alpha, int nperms,
    double threshold, bool complete, bool debugging);

/* all-subsets tests; the pure-C search returns this compound result (the
 * p-value range plus the separating set), which the R/C boundary marshals into
 * the SEXP the callers expect. */
typedef struct {
  double pvalue;       /* p-value of the returned test                       */
  double min_pvalue;   /* smallest p-value seen over all the subsets         */
  double max_pvalue;   /* largest p-value seen over all the subsets          */
  bool separated;      /* whether a separating subset was found              */
  const char **dsep;   /* owned array of borrowed separating-set names       */
  int ndsep;           /* size of the separating set                         */
} ast_result;

ast_result ast_discrete(tabular dtx, tabular dty, tabular dtz, int nf,
    int minsize, int maxsize, test_e test, double a, bool debugging);
ast_result ast_gaustests(tabular dt, int nf, int minsize, int maxsize, double a,
    bool debugging, test_e test);
ast_result ast_micg(tabular dtx, tabular dty, tabular dtz, int nf, int minsize,
    int maxsize, double a, bool debugging);
ast_result ast_dperm(tabular dtx, tabular dty, tabular dtz, int nf, int minsize,
    int maxsize, double a, test_e type, int nperms, double threshold,
    bool debugging);
ast_result ast_gperm(tabular dt, int nf, int minsize, int maxsize, double a,
    test_e type, int nperms, double threshold, bool complete, bool debugging);

ast_result ast_result_make(double pvalue, double min_pvalue, double max_pvalue,
    bool separated, const char **nodes, int nnodes);
void update_pvalue_range(double pvalue, double *min, double *max);

#endif
