////////////////////////////////////////////////////////
//  
// Adapted TF2
//
////////////////////////////////////////////////////////

#include <math.h>
#include <iostream>
#include "PUtils.h"
using namespace std;

#ifdef WIN32
#pragma optimize("",off)
#endif

#define INTEGRAL_PRINT_THRESHOLD 9999

#include "PF2.h"

//Standard ROOT ctors

PF2::PF2() :
    TF2() {
    projector = NULL;    
    epsilon   = 0.000001; //ROOT std.
};

PF2::PF2(const char *name, const char *formula, Double_t xmin, Double_t xmax, Double_t ymin, Double_t ymax) :
    TF2(name, formula, xmin, xmax, ymin, ymax) {
    projector = NULL;
    epsilon   = 0.000001; //ROOT std.
};

#if 0
PF2::PF2(const char *name, void *fcn, Double_t xmin, Double_t xmax, Double_t ymin, Double_t ymax, Int_t npar) :
    TF2(name, fcn, xmin, xmax, ymin, ymax, npar) {
    projector = NULL;
    epsilon   = 0.000001; //ROOT std.
};
#endif

PF2::PF2(const char *name, Double_t (*fcn)(Double_t *, Double_t *), 
	 Double_t xmin, Double_t xmax, Double_t ymin, Double_t ymax, Int_t npar) :
    TF2(name,fcn,xmin,xmax,ymin,ymax,npar) {
    projector = NULL;
    epsilon   = 0.000001; //ROOT std.
};

PF2::PF2(const char *name, Double_t (*fcn)(const Double_t *, const Double_t *), 
	 Double_t xmin, Double_t xmax, Double_t ymin, Double_t ymax, Int_t npar) :
    TF2(name,fcn,xmin,xmax,ymin,ymax,npar) {
    projector = NULL;
    epsilon=0.000001; //ROOT std.
};

PF2::PF2(const char *name, ROOT::Math::ParamFunctor f, Double_t xmin, Double_t xmax, Double_t ymin, Double_t ymax, Int_t npar) :
    TF2(name, f, xmin, xmax, ymin, ymax, npar) {
    projector = NULL;
    epsilon   = 0.000001; //ROOT std.
};  

PF2::PF2(const PF2 &f2) :
    TF2(f2) {
    projector = NULL;
    epsilon   = 0.000001; //ROOT std.
};


//Pluto ctor
PF2::PF2(const char *name, Double_t xmin, Double_t xmax, Double_t ymin, Double_t ymax) :
    TF2(name,"x+y", xmin, xmax, ymin, ymax) {
    SetTitle(name);
    projector = new PProjector();
    epsilon   = 0.000001; //ROOT std.
    vf = makeStaticData()->GetBatchValue("_f"); 
    vx = makeStaticData()->GetBatchValue("_x"); 
    vy = makeStaticData()->GetBatchValue("_y"); 
}

Bool_t PF2::Add(const char *command) {
    if (!projector) {
	Warning("Add", "No PProjector, wrong ctor called?");
	return kFALSE;
    }
    return projector->AddCommand(command);
};

Bool_t PF2::Add(TH1 *histo, const char *command) {
    if (!projector) {
	Warning("Add", "No PProjector, wrong ctor called?");
	return kFALSE;
    }
    return projector->AddHistogram(histo, command, 0);
};

Bool_t PF2::Add(TH2 *histo, const char *command) {
    if (!projector) {
	Warning("Add", "No PProjector, wrong ctor called?");
	return kFALSE;
    }
    return projector->AddHistogram(histo, command, 0);
};

Bool_t PF2::Add(TH3 *histo, const char *command) {
    if (!projector) {
	Warning("Add", "No PProjector, wrong ctor called?");
	return kFALSE;
    }
    return projector->AddHistogram(histo, command, 0);
};

Bool_t PF2::Add(TGraph *graph, const char *command) {
    if (!projector) {
	Warning("Add", "No PProjector, wrong ctor called?");
	return kFALSE;
    }
    return projector->AddTGraph(graph, command);
};

Bool_t PF2::Add(TGraph2D *graph, const char *command) {
    if (!projector) {
	Warning("Add", "No PProjector, wrong ctor called?");
	return kFALSE;
    }
    return projector->AddTGraph2D(graph, command);
};

Double_t PF2::EvalPar(const Double_t *x, const Double_t *params) {
    if (!projector) return TF2::EvalPar(x, params);

    //Extension via batch script:
    *vx = x[0];
    *vy = x[1];

    Int_t num = 0;
    if (projector->Modify(NULL, NULL, &num, 0))
	return *vf;
    return 0;
}


void PF2::GetRandom2(Double_t &xrandom, Double_t &yrandom) {
    //  Check if integral array must be build
    Int_t i, j, cell;
    Double_t dx = (fXmax-fXmin)/fNpx;
    Double_t dy = (fYmax-fYmin)/fNpy;
    Int_t ncells = fNpx*fNpy;
    if (fIntegral.empty()) {	
	MakeIntegral();	
    }
    
    // return random numbers
    Double_t r, ddx, ddy, dxint;
    r     = PUtils::sampleFlat();
    cell  = TMath::BinarySearch(ncells, fIntegral.data(), r);
    dxint = fIntegral[cell+1] - fIntegral[cell];
    if (dxint > 0) ddx = dx*(r - fIntegral[cell])/dxint;
    else           ddx = 0;
    ddy = dy * PUtils::sampleFlat();
    j   = cell/fNpx;
    i   = cell%fNpx;
    xrandom = fXmin +dx*i +ddx;
    yrandom = fYmin +dy*j +ddy;
}

Bool_t PF2::MakeIntegral(void) {
    //Copied from ROOT

    Int_t i, j, cell;
    Double_t dx = (fXmax-fXmin)/fNpx;
    Double_t dy = (fYmax-fYmin)/fNpy;
    Int_t ncells = fNpx*fNpy;
    
    if (fIntegral.empty()) {
	int print_twentypercent = ncells/5, print_cpc = 1, 
	    print_ipc = print_cpc*print_twentypercent;
	if (ncells>INTEGRAL_PRINT_THRESHOLD) Info("MakeIntegral","Generating array, this can take a while....");
	
	fIntegral.resize(ncells+1);
	fIntegral[0] = 0;
	Double_t integ;
	Int_t intNegative = 0;
	cell = 0;

	for (j=0; j<fNpy; j++) {
	    for (i=0; i<fNpx; i++) {
		integ = Integral(fXmin+i*dx,fXmin+i*dx+dx,fYmin+j*dy,fYmin+j*dy+dy,epsilon);
		if (cell == print_ipc) {
		    if (ncells>INTEGRAL_PRINT_THRESHOLD) Info("MakeIntegral","...%i%% done",print_cpc*20);
		    print_cpc++;
		    print_ipc = print_cpc*print_twentypercent;
		}
		if (integ < 0) {intNegative++; integ = -integ;}
		fIntegral[cell+1] = fIntegral[cell] + integ;
		cell++;
	    }
	}
	if (intNegative > 0) {
	    Warning("MakeIntegral","function:%s has %d negative values: abs assumed",GetName(),intNegative);
	}
	if (fIntegral[ncells] == 0) {
	    Error("MakeIntegral","Integral of function is zero");
	    return kFALSE;
	}
	for (i=1;i<=ncells;i++) {  // normalize integral to 1
	    fIntegral[i] /= fIntegral[ncells];
	}
	if (ncells>INTEGRAL_PRINT_THRESHOLD) Info("MakeIntegral","...done (%i bins)",ncells);
    }	
    return kTRUE;
}


#if 0 
//ROOT5
Bool_t PF2::MakeIntegral(void) {
    //Copied from ROOT

    Int_t i,j,cell;
    Double_t dx   = (fXmax-fXmin)/fNpx;
    Double_t dy   = (fYmax-fYmin)/fNpy;
    Int_t ncells = fNpx*fNpy;
 
    if (fIntegral == 0) {
	int print_twentypercent = ncells/5, print_cpc = 1, 
	    print_ipc = print_cpc*print_twentypercent;
	if (ncells>INTEGRAL_PRINT_THRESHOLD) Info("MakeIntegral","Generating array, this can take a while....");

	fIntegral = new Double_t[ncells+1];
	fIntegral[0] = 0;
	Double_t integ;
	Int_t intNegative = 0;
	cell = 0;

	for (j=0;j<fNpy;j++) {
	    for (i=0;i<fNpx;i++) {
		integ = Integral(fXmin+i*dx,fXmin+i*dx+dx,fYmin+j*dy,fYmin+j*dy+dy,epsilon);
		if (cell == print_ipc) {
		    if (ncells>INTEGRAL_PRINT_THRESHOLD) Info("MakeIntegral","...%i%% done",print_cpc*20);
		    print_cpc++;
		    print_ipc = print_cpc*print_twentypercent;
		}
		if (integ < 0) {intNegative++; integ = -integ;}
		fIntegral[cell+1] = fIntegral[cell] + integ;
		cell++;
	    }
	}
	if (intNegative > 0) {
	    Warning("MakeIntegral","function:%s has %d negative values: abs assumed",GetName(),intNegative);
	}
	if (fIntegral[ncells] == 0) {
	    Error("MakeIntegral","Integral of function is zero");
	    return kFALSE;
	}
	for (i=1;i<=ncells;i++) {  // normalize integral to 1
	    fIntegral[i] /= fIntegral[ncells];
	}
	if (ncells>INTEGRAL_PRINT_THRESHOLD) Info("MakeIntegral","...done (%i bins)",ncells);
    }	
    return kTRUE;
};
#endif

Double_t PF2::Integral(Double_t ax, Double_t bx, Double_t ay, Double_t by, Double_t epsilon)
{
    //Copied from ROOT
    // Return Integral of a 2d function in range [ax,bx],[ay,by]
    //
   Double_t a[2], b[2];
   a[0] = ax;
   b[0] = bx;
   a[1] = ay;
   b[1] = by;
   Double_t relerr  = 0;
   Int_t n = 2;
   Int_t minpts = 2*2+2*n*(n+1)+1; //ie 17
   Int_t maxpts = 20*fNpx*fNpy;

   Int_t nfnevl,ifail;

   Double_t result = IntegralMultiple(n,a,b,minpts,maxpts,epsilon,relerr,nfnevl,ifail);

   if (ifail > 0) {
      Warning("Integral","failed code=%d, minpts=%d, maxpts=%d, epsilon=%g, nfnevl=%d, relerr=%g ",ifail,minpts,maxpts,epsilon,nfnevl,relerr);
   }

   return result;
}


ClassImp(PF2)
 PF2.cc:1
 PF2.cc:2
 PF2.cc:3
 PF2.cc:4
 PF2.cc:5
 PF2.cc:6
 PF2.cc:7
 PF2.cc:8
 PF2.cc:9
 PF2.cc:10
 PF2.cc:11
 PF2.cc:12
 PF2.cc:13
 PF2.cc:14
 PF2.cc:15
 PF2.cc:16
 PF2.cc:17
 PF2.cc:18
 PF2.cc:19
 PF2.cc:20
 PF2.cc:21
 PF2.cc:22
 PF2.cc:23
 PF2.cc:24
 PF2.cc:25
 PF2.cc:26
 PF2.cc:27
 PF2.cc:28
 PF2.cc:29
 PF2.cc:30
 PF2.cc:31
 PF2.cc:32
 PF2.cc:33
 PF2.cc:34
 PF2.cc:35
 PF2.cc:36
 PF2.cc:37
 PF2.cc:38
 PF2.cc:39
 PF2.cc:40
 PF2.cc:41
 PF2.cc:42
 PF2.cc:43
 PF2.cc:44
 PF2.cc:45
 PF2.cc:46
 PF2.cc:47
 PF2.cc:48
 PF2.cc:49
 PF2.cc:50
 PF2.cc:51
 PF2.cc:52
 PF2.cc:53
 PF2.cc:54
 PF2.cc:55
 PF2.cc:56
 PF2.cc:57
 PF2.cc:58
 PF2.cc:59
 PF2.cc:60
 PF2.cc:61
 PF2.cc:62
 PF2.cc:63
 PF2.cc:64
 PF2.cc:65
 PF2.cc:66
 PF2.cc:67
 PF2.cc:68
 PF2.cc:69
 PF2.cc:70
 PF2.cc:71
 PF2.cc:72
 PF2.cc:73
 PF2.cc:74
 PF2.cc:75
 PF2.cc:76
 PF2.cc:77
 PF2.cc:78
 PF2.cc:79
 PF2.cc:80
 PF2.cc:81
 PF2.cc:82
 PF2.cc:83
 PF2.cc:84
 PF2.cc:85
 PF2.cc:86
 PF2.cc:87
 PF2.cc:88
 PF2.cc:89
 PF2.cc:90
 PF2.cc:91
 PF2.cc:92
 PF2.cc:93
 PF2.cc:94
 PF2.cc:95
 PF2.cc:96
 PF2.cc:97
 PF2.cc:98
 PF2.cc:99
 PF2.cc:100
 PF2.cc:101
 PF2.cc:102
 PF2.cc:103
 PF2.cc:104
 PF2.cc:105
 PF2.cc:106
 PF2.cc:107
 PF2.cc:108
 PF2.cc:109
 PF2.cc:110
 PF2.cc:111
 PF2.cc:112
 PF2.cc:113
 PF2.cc:114
 PF2.cc:115
 PF2.cc:116
 PF2.cc:117
 PF2.cc:118
 PF2.cc:119
 PF2.cc:120
 PF2.cc:121
 PF2.cc:122
 PF2.cc:123
 PF2.cc:124
 PF2.cc:125
 PF2.cc:126
 PF2.cc:127
 PF2.cc:128
 PF2.cc:129
 PF2.cc:130
 PF2.cc:131
 PF2.cc:132
 PF2.cc:133
 PF2.cc:134
 PF2.cc:135
 PF2.cc:136
 PF2.cc:137
 PF2.cc:138
 PF2.cc:139
 PF2.cc:140
 PF2.cc:141
 PF2.cc:142
 PF2.cc:143
 PF2.cc:144
 PF2.cc:145
 PF2.cc:146
 PF2.cc:147
 PF2.cc:148
 PF2.cc:149
 PF2.cc:150
 PF2.cc:151
 PF2.cc:152
 PF2.cc:153
 PF2.cc:154
 PF2.cc:155
 PF2.cc:156
 PF2.cc:157
 PF2.cc:158
 PF2.cc:159
 PF2.cc:160
 PF2.cc:161
 PF2.cc:162
 PF2.cc:163
 PF2.cc:164
 PF2.cc:165
 PF2.cc:166
 PF2.cc:167
 PF2.cc:168
 PF2.cc:169
 PF2.cc:170
 PF2.cc:171
 PF2.cc:172
 PF2.cc:173
 PF2.cc:174
 PF2.cc:175
 PF2.cc:176
 PF2.cc:177
 PF2.cc:178
 PF2.cc:179
 PF2.cc:180
 PF2.cc:181
 PF2.cc:182
 PF2.cc:183
 PF2.cc:184
 PF2.cc:185
 PF2.cc:186
 PF2.cc:187
 PF2.cc:188
 PF2.cc:189
 PF2.cc:190
 PF2.cc:191
 PF2.cc:192
 PF2.cc:193
 PF2.cc:194
 PF2.cc:195
 PF2.cc:196
 PF2.cc:197
 PF2.cc:198
 PF2.cc:199
 PF2.cc:200
 PF2.cc:201
 PF2.cc:202
 PF2.cc:203
 PF2.cc:204
 PF2.cc:205
 PF2.cc:206
 PF2.cc:207
 PF2.cc:208
 PF2.cc:209
 PF2.cc:210
 PF2.cc:211
 PF2.cc:212
 PF2.cc:213
 PF2.cc:214
 PF2.cc:215
 PF2.cc:216
 PF2.cc:217
 PF2.cc:218
 PF2.cc:219
 PF2.cc:220
 PF2.cc:221
 PF2.cc:222
 PF2.cc:223
 PF2.cc:224
 PF2.cc:225
 PF2.cc:226
 PF2.cc:227
 PF2.cc:228
 PF2.cc:229
 PF2.cc:230
 PF2.cc:231
 PF2.cc:232
 PF2.cc:233
 PF2.cc:234
 PF2.cc:235
 PF2.cc:236
 PF2.cc:237
 PF2.cc:238
 PF2.cc:239
 PF2.cc:240
 PF2.cc:241
 PF2.cc:242
 PF2.cc:243
 PF2.cc:244
 PF2.cc:245
 PF2.cc:246
 PF2.cc:247
 PF2.cc:248
 PF2.cc:249
 PF2.cc:250
 PF2.cc:251
 PF2.cc:252
 PF2.cc:253
 PF2.cc:254
 PF2.cc:255
 PF2.cc:256
 PF2.cc:257
 PF2.cc:258
 PF2.cc:259
 PF2.cc:260
 PF2.cc:261
 PF2.cc:262
 PF2.cc:263
 PF2.cc:264
 PF2.cc:265
 PF2.cc:266
 PF2.cc:267
 PF2.cc:268
 PF2.cc:269
 PF2.cc:270
 PF2.cc:271
 PF2.cc:272
 PF2.cc:273
 PF2.cc:274
 PF2.cc:275
 PF2.cc:276
 PF2.cc:277
 PF2.cc:278
 PF2.cc:279
 PF2.cc:280
 PF2.cc:281
 PF2.cc:282
 PF2.cc:283
 PF2.cc:284
 PF2.cc:285
 PF2.cc:286
 PF2.cc:287
 PF2.cc:288
 PF2.cc:289
 PF2.cc:290
 PF2.cc:291