#include <stdio.h>
#include <math.h>
#include <time.h>
#include <stdlib.h>
/* #include "/pack/fftw/include/fftw3.h"  */
#include <fftw3.h>
#include "/user/rw/Clib/mt19937ar.h"

#define pi 3.141592653589793238462643
#define ACCEPTSAMPLE 100
#define maxlinpar 10
#define MIN(A,B) ((A)<(B) ? (A) : (B))
#define MAX(A,B) ((A)>(B) ? (A) : (B))
#define MAX_NO_POINTS 1000
#define MAXorig 60
#define NOENVE 39

#define DEBUG 0

int NOPOINTS;

long Norig, Morig, N, M, NM, NMorig;

double divNM;

typedef double *Doublearray; 
typedef fftw_complex doublecomplex;
typedef struct {doublecomplex *x; fftw_plan pf; fftw_plan pb;} fftstruct;

FILE *acceptrates;

double logprior_sigma(double sigma);

void print_results(fftstruct *z, double *meany, double *meanlambda, double *ssy, double *sslambda, double *meanlinpred, int itr, int no_linpar, double sigma, double alpha, double alpha_low, double alpha_up, double beta[], double *residuals);

void parmread(int *newrun, int *itr, double *scale, double *betascale, double *sigmascale, double *alphascale, int *SUBSAMPLE, int *INTERMED_PRINT, int *startitr, int *no_linpar, double *sigma, double *alpha, double *alpha_low, double *alpha_up, double *Hz, double *Hbeta);

void calclinpred(double *beta, double *X, double *linpred, int no_linpar,int *is_observed, double *popdensity);

double logprior(double alpha, double alpha_up);

void initz(fftstruct *z, fftstruct *S, double *obsdata,  double *linpred, int * is_observed, double sigma, double divNM, double *cellareas);

void addGauss(fftstruct *surf, double scale);

void conddensity_grad(fftstruct *y, fftstruct *S,  double sigma,  fftstruct *gradz, double *logfbet, double *ssz, double *obsdata, int *is_observed, fftstruct *z, double divNM, double *linpred, double Hz, double *cellareas);

void initialize(fftstruct **y, fftstruct **z, fftstruct **gradz, fftstruct **gradzprop, fftstruct **zprop, fftstruct **yprop, Doublearray *expyprop, Doublearray *expy,  fftstruct **S, fftstruct **Sprop, Doublearray *meany, Doublearray *meanlambda, Doublearray *ssy, Doublearray *sslambda, Doublearray *obsdata, Doublearray *linpred, Doublearray *linpredprop, Doublearray *meanlinpred, int **is_observed, int newrun, Doublearray *X, Doublearray *beta, Doublearray *betaprop, int no_linpar, Doublearray *residuals, double **cellareas, double **popdensity);

double loglikelihood(double obsdata, double y, double sigma, double linpred, double cellarea);
int sqrteigen_values(fftstruct *S, double alpha);
double corrfct(double alpha, double h);
double geodist(int i, int j);
double min(int i, int j);
double trunc_dloglikelihood(double obsdata, double y,  double sigma, double linpred, double H, double cellarea);
void printvariables(double sigma2, double logfz, double sum_obsy, double sum_expy, fftstruct *y, fftstruct *gradz, fftstruct *z);

void update_grad(fftstruct *y, fftstruct *gradz, fftstruct *S, fftstruct *z, double divNM, double *obsdata, int *is_observed,  double sigma, double *linpred, double Hz, double *cellareas);

void conddensity_alpha(fftstruct *y, fftstruct *S,  double sigma, double *logfbet, double *obsdata, int *is_observed, fftstruct *z, double divNM, double *linpred, double *cellareas);

void betaproposal(double *beta, double *betaprop, double *X, double betascale, double *logq, double *logqprop, double *linpred, double *linpredprop, int *is_observed, double *logfbetprop, int no_linpar, double *obsdata, double sigma, fftstruct *y, double Hbeta, double *popdensity, double *cellareas);

void alphaproposal(double alpha, double *alphaprop, double alphascale, double *logq, double *logqprop);

void gauss_sim(double *u1, double *u2);

void sigmaproposal_rw(double sigma, double *sigmaprop,  double sigmascale, double u2, double *logq, double *logqprop, double *linpred, int *is_observed, double *logfbetprop, fftstruct *y, double *obsdata, double *cellareas);

double mytrunc(double mean, double H);

int index_orig(int i, int j);
int index(int i, int j);

void continue_wish();
int continue_sim();
void init_termmode();

/* procedures from DataRead */
void read_points_X_scale(Doublearray obsdata, Doublearray X, int *is_observed, int no_linpar, double *popdensity, double *cellareas);
int cellcoordx(double xmax, double point);
int cellcoordy(double ymax, double point);
double overlap(int i, int j, double llx, double lly, double urx, double ury);
void ys_print(FILE *timeout, fftstruct *y, double sigma, double lambdasum);
void no_points_y(Doublearray obsdata);

/* procedures from print */
void printvariables2(double sigma, fftstruct *y, Doublearray linpred);
void init_print(int newrun);
void close_print();
void print_y(fftstruct *y, double sigma, double *beta, int no_linpar, double alpha, double *linpred);
void partimeprint(double *beta, int no_linpar, double sigma, double alpha, double logfbet, double ssz);




/* needed for fftpack 
static doublecomplex *work;
static long lwork;
*/

/* needed for fftw  */
fftw_plan pzf, pzb, pgradzf, pgradzb, pyf, pyb, pSf, pSb, pSpropb, pSpropf, pgradzpropf, pgradzpropb, pypropf, pypropb;

void init_fftstruct(int M, int N, fftstruct **x);
void freework();
void transform(int M, int N, fftstruct *x, fftstruct *S);
void transformstar(int M, int N, fftstruct *x, fftstruct *S);
void transformb(int M, int N, fftstruct *x);
