/* This is newlcj.h */
#include <gsl/gsl_rng.h>

enum DecRule {
	RULE1 = 11, RULE2 = 12, RULE3 = 13,
	RULES1_2 = 14, RULES1_3 = 15, RULES2_3 = 16,
	RULES1_2_3 = 17
	};

enum RKKKRule {RKKK1 = 1, RKKK2 = 2, RKKK3B1 = 3, RKKK3B2 = 4};

DecRule CheckValidDecisionRule(int x);


struct initialization_s {
        char header[1024]; // First tken in input (control) file. Printed in the output file.
        int nums;  // The number of stimuli 
        int numr;  // The number of responses
        int sdtev;  // Is SDT equal-variance model used here?
        int sdtuv;  // Is SDT unequal-variance model used here?
        int csdtev;  // Is CSDT equal-variance  model used here?
        int csdtuv;  // Is CSDT unequal-variance  model used here?
        int fsdt;  // Is FSDT model used here?
	// Dec_r chooses which decision rule (or combination of decision rules) to use.
        enum DecRule dec_r;
        int stdz;   // Choose standard scale
        int nallparams;            // How many total parameters are there?
        int nfree_modpars;       // How many free model parameters are there?
        int nunconstrained;     // How many total parameters are being optimized?
        double qracc;               // Accuracy for numerical integration [ qromo() ]
        mutable gsl_rng *random;  // Random number generator
        double simpx_mult;
        bool append_output;
        // How many MCMC samples to take.  (Note: this is passed up to bsr_analysis_guts.pyx.)
        int gf_samps;

	// These are indices of parameters:
        int s_mstart, s_mend;   // Signal means.
        int s_sdstart, s_sdend;  // Signal standard deviations.
        int c_mstart, c_mend;   // Criterion means.
	int  c_sdstart, c_sdend;  // Criterion standard deviations
	int pstart;  // Index base for PR1, PR2, PR3

	// These are counts of free parameters:
	// How many criterion means are free; how many criterion stdev; signal means; signal stdev.
        int free_cm, free_csd, free_sm, free_ssd;

        double *allparameters;
        double *constraints;
        double *solution;
        int **data;
        int **psd_mat;
        double **prop_mat;
	double **dprob_1_mat;
	double **dprob_2_mat;
	double **dprob_3_mat;
	double **dprob_mat;
        double **dcump_mat;
        double **e_mat;
        double **re_mat;
        // double **gfs_mat;
        FILE *outPtr;

	int numc() const { return numr - 1; }

	int nconstrained() const { return nallparams - nunconstrained; }

	// How many free parameters are used to define the decision rule? (see dec_r).
	int num_decision_probs() const;
};

struct eval_stats {
    double logp;
    double rmsd;
    double r;
    double rsq;
    int df;
    double b0;
    double b1;
    double c95b0;
    double c95b1;
    double k_l_div;
  double AICc;
};

// Functions
void print_model_type ( C struct initialization_s *lcjc_init);

void lawcjc_init ( const char *filenamei, const char *filenameo, struct initialization_s *out );

void lawcjc_start ( int nguesses, double **prmvecs, C struct initialization_s *isp );

int wprojct ( double *p, C struct initialization_s *isp );


// Args:
//   dont_add_fudge_factor: The numerical integrations do not work out well if any of the
//     sigmas are nearly zero.  Essentially, the problem is that the number of integration
//     steps goes to infinity, it takes forever and roundoff error dominate.   So, when
//     we are running the optimization, we need to keep the sigmas away from zero.
//     Thus, the fudge factor.    It falsely subtracts 0.1/sigma from log(P) and will
//     thus keep sigmas > 0.1 at the cost of some accuracy.    We need to do this while
//     running the optimizer but we don't want do this while printing log(P).
double wsdo_logp ( C double *prmvec, C struct initialization_s *isp, bool dont_add_fudge_factor );

void missing_entry( double **dpmat, C struct initialization_s *isp, int r_start, int r_end, double PRx );

double normal ( double x, double mu, double sigma );

double outerkernel ( double s,  void *infoptr, int nc );

double innerkernel ( double cj,  void *infoptr, int nc );


double eq3_wrap ( enum RKKKRule r123, int ie3, int je3, double *pp, C struct initialization_s *isp );

double eq3 ( enum RKKKRule r123, int j, int n, double *mu, double *sigma, double mus, double sigmas,
		C struct initialization_s *isp );

double eq3a_wrap ( enum RKKKRule r123, int ie3a, int je3a, double *pp, C struct initialization_s *isp );

double eq3a ( enum RKKKRule r123, int j, int n, double *mu, double *sigma, double mus, double sigmas,
		C struct initialization_s *isp );

void sdt ( int isdtx, double *pp, C struct initialization_s *isp );

double wsdo_l_f ( C struct initialization_s *isp );

void print_rule_prob1(C struct initialization_s *isp);

void wsdo_max_output ( C double *prmvec, C struct initialization_s *isp );

void wsdo_eval ( C struct initialization_s *isp, struct eval_stats *stp );

int w_block ( FILE *o1P, int b_start, int b_end, double *b );

void wsdo_mcmc_output ( int mcmc_num, double **mcmc_vecs, C struct initialization_s *isp );

void mat_out ( C struct initialization_s *isp, double **mn );
