#ifndef MARS_MFindSupercutsONOFF
#define MARS_MFindSupercutsONOFF

#ifndef MARS_MParContainer
#include "MParContainer.h"
#endif

#ifndef ROOT_TArrayD
#include <TArrayD.h>
#endif
#ifndef ROOT_TArrayI
#include <TArrayI.h>
#endif

#ifndef ROOT_TH1F
#include <TH1F.h>
#endif

#ifndef ROOT_TPostScript
#include <TPostScript.h>
#endif


class MFilter;
class MEvtLoop;
class MH3;
class MSupercutsCalcONOFF;

class MGeomCam;
class MHMatrix;


class MFindSupercutsONOFF : public MParContainer
{
 private:


     // TMP
    // There are quite some problems during the data preprocessing. 
    // For the time being, I will add some cuts to the functions 
    // DefineTrainTestMatrixThetaRange and for OFF, so that I can 
    // make a kind of preprocess on my own. This allows me 
    // to make a very silly preprocess with wolfgangs macro, which 
    // might be free of corrupted data, and then I can do on my own.


    // VARIABLES INITIALIZED IN CONSTRUCTOR

    Double_t fSizeCutLow;
    Double_t fSizeCutUp;

    Double_t fDistCutLow;
    Double_t fDistCutUp;
    
    Double_t fLengthCutLow;
    Double_t fLengthCutUp;
    
    Double_t  fWidthCutLow;
    Double_t  fWidthCutUp;

    Double_t  fLeakageMax;

    Double_t fConvMMToDeg;

    // ENDTMP


    Int_t fDegreeON;
    Int_t fDegreeOFF;


  TString fFilenameTrain;
  TString fFilenameTest;

  Int_t   fHowManyTrain;
  Int_t   fHowManyTest;

  Int_t   fHowManyTrainOFF;
  Int_t   fHowManyTestOFF;


  
  Double_t fAlphaSig; // Max alpha value were signal is expected

  // Background range (in alpha) is defined by the member variables 
  // fAlphaBkgMin and fAlphaBkgMax
  Double_t fAlphaBkgMin; 
  Double_t fAlphaBkgMax; 
  
  Int_t fThetaMin; // Cut in Theta value (in degrees)
  Int_t fThetaMax; // Cuts in Theta value (in degrees)
  TString fThetaRangeString;

 

  // Variables for binning of alpha plots
  
  Int_t fNAlphaBins;
  Double_t fAlphaBinLow;
  Double_t fAlphaBinUp;


  Bool_t  fUseOrigDistribution;


  Double_t fNormFactorTrain;
  Double_t fNormFactorTest;
  Double_t fSigmaLiMaTrain;
  Double_t fSigmaLiMaTest;
  Double_t fNexTrain; 
  Double_t fNexTest; 
  Double_t fGammaEfficiency; // Fraction of gammas that remain after cuts
  // Quantity that will have to be determined with MC

  Bool_t fTuneNormFactor; // If true, normalization factors are corrected using the estimated number of gammas and the gamma efficiency
  // fNormFactorTrain = fNormFactorTrain - Ngammas/EventsInTrainMatrixOFF


  // Boolean variable used to determine wether the normalization factor is 
  // computed from method 1) or 2)
  // 1) Using total number of ON and OFF events before cuts, and tuning the factor 
  //    correcting for "contamination" of gamma events in ON sample
  // 2) Using number of ON and OFF events after cuts in the background 
  //    region determined by variables fAlphaBkgMin-fAlphaBkgMax
 
  Bool_t fNormFactorFromAlphaBkg; // if kTRUE, method 2) is used



  // Boolean variable used to disable the usage ("serious" usage) of the 
  // quantities computed from fits. This will be useful in those cases 
  // where there is too few events to perform a decent fit to the 
  // alpha histograms. Default value will be kTRUE.
  
  Bool_t fUseFittedQuantities;

  // Boolean variable that controls wether the optimization of the 
  // parameters (MMinuitInterface::CallMinuit(..) in function FindParams(..))
  // takes place or not. kTRUE will skip such optimization.
  // This variable is useful to test the optmized parameters (previously found 
  // and stored in root file) on the TRAIN sample.

  Bool_t fSkipOptimization;



  // Boolean variable that allows the user to set some limits to the 
  // some of the Minuit parameters. For the time being, only the limits
  // for the parameters which do NOT depend in size, dist and theta are set, 
  // i.e. static limits. The value of this boolean variable is set in the 
  // constructor of the class.

  Bool_t fSetLimitsToSomeMinuitParams;

  // Limits for the Minuit parameters. For the time being the values are set in the constructor 
  // of the class. One MUST be very careful to set limits such that the expected final values 
  // (optimized values) are far away from the limits.

 
  
  Double_t fMinuitDistUPUpperLimit;
  Double_t fMinuitDistUPLowerLimit;
  Double_t fMinuitLengthUPUpperLimit;
  Double_t fMinuitLengthUPLowerLimit;
  Double_t fMinuitWidthUPUpperLimit;
  Double_t fMinuitWidthUPLowerLimit;
  
  Double_t fMinuitLeakage1UPUpperLimit;
  Double_t fMinuitLeakage1UPLowerLimit;



  Double_t fMinuitDistLOWUpperLimit;
  Double_t fMinuitDistLOWLowerLimit;
  Double_t fMinuitLengthLOWUpperLimit;
  Double_t fMinuitLengthLOWLowerLimit;
  Double_t fMinuitWidthLOWUpperLimit;
  Double_t fMinuitWidthLOWLowerLimit;
  


  // Boolean variable used to control decide wether to use theta information 
  // in the computation of teh dynamical cuts.
  Bool_t fNotUseTheta;


  // Boolean variable that allows to use/not use the dist info in the cuts parameterization
  // kTRUE for use it.
  // For the time being this variable is set in the constructor

  Bool_t fUseDist;



 // Boolean variable used to decide wether to use dynamical cuts or static cuts
  // kTRUE means that static cuts are used. 
  Bool_t fUseStaticCuts;

  
  // Boolean variable that allows the user to write the initial parameters 
  // into the root file that will be used to store the optimum cuts.
  // If fUseInitialSCParams = kTRUE , parameters are written.
  // In this way, the initial SC parameters can be applied on the data (train/test) 
  
  // The initial parameters are ONLY written to the root file if 
  // there is NO SC params optimization, i.e., if variable 
  // fSkipOptimization = kTRUE;
  
  // The default value is obviously kFALSE.

  Bool_t fUseInitialSCParams;

  
  TString  fFilenameParam;

  TString  fHadronnessName;
  TString  fHadronnessNameOFF;

  // name for the containers to store the 
  // supercuts applied to Train (ON/OFF) and Test(ON/OFF) samples

  TString  fTrainONSupercutsAppliedName;        
  TString  fTrainOFFSupercutsAppliedName;       

  TString  fTestONSupercutsAppliedName;        
  TString  fTestOFFSupercutsAppliedName;       

  

  // Name of Postscript file where, for each theta bin,  alpha ON and OFF distributions 
  //  after cuts (and hence, Nex and SigmaLiMa computations) will be stored
  // If fAlphaDistributionsPostScriptFilename is not defined, postscript file is not 
  // produced. It is an optional variable...

  // NOT WORKING YET !!!!
  TPostScript* fPsFilename; 
  TPostScript* fPsFilename2; 

  TString fPsFilenameString; // Name of the file where plots will be stored while the 
  // TPostScript option is not working 

  TString fAlphaDistributionsRootFilename;
  // Root file where histograms containing the ON alpha distribution and the 
  // OFF alpha distribution (non normalized) , AFTER CUTS, are stored.
  // Histograms containing the normalization factors, Nex and SigmaLiMa for 
  // each theta bin will be also stored there.
  // This name MUST be defined, since the histograms stored there will be used by 
  // function XXX to compute an overall Nex and sigmaLiMa combining all those histograms


  MSupercutsCalcONOFF *fCalcHadTrain;
  MSupercutsCalcONOFF *fCalcHadTest;
  MSupercutsCalcONOFF *fCalcHadTrainOFF;
  MSupercutsCalcONOFF *fCalcHadTestOFF;
  

  MHMatrix          *fMatrixTrain;
  MHMatrix          *fMatrixTest;
  MHMatrix          *fMatrixTrainOFF;
  MHMatrix          *fMatrixTestOFF;

  MGeomCam          *fCam;

  MEvtLoop *fObjectFit;

  MFilter  *fMatrixFilter; 

  // to comunicate with MINUIT -----------------
  // attention : dimensions must agree with those in 
  //             MMinuitInterface::CallMinuit()
  //char    fParName [80][100];
  TArrayD fVinit;
  TArrayD fStep;
  TArrayD fLimlo;
  TArrayD fLimup;
  TArrayI fFix;

  UInt_t     fNpar;

  TString    fMethod;

  Double_t fMin,   fEdm,   fErrdef;
  Int_t    fNpari, fNparx, fIstat;
  Int_t    fErrMinimize;
  //--------------------------------------------


public:
  MFindSupercutsONOFF(const char *name=NULL, const char *title=NULL);
  ~MFindSupercutsONOFF();

  void SetFilenameTraining(const TString &name, const Int_t howmany) 
      {fFilenameTrain = name;  fHowManyTrain = howmany; }

  void SetFilenameTest(const TString &name, const Int_t howmany)     
      {fFilenameTest     = name;  fHowManyTest  = howmany; }

  void SetFilenameParam(const TString &name)    {fFilenameParam  = name;}
  void SetHadronnessName(const TString &name)   {fHadronnessName = name;}
  void SetHadronnessNameOFF(const TString &name)   {fHadronnessNameOFF = name;}

  
  void SetSupercutsAppliedTreeNames();


  void SetAlphaDistributionsRootFilename(const TString &name) 
      {fAlphaDistributionsRootFilename = name;}

  Bool_t SetAlphaSig (Double_t alphasig);
  Bool_t SetAlphaBkgMin (Double_t alphabkgmin);
  Bool_t SetAlphaBkgMax (Double_t alphabkgmax);

  // Function that checks that the values of the member data 
  // fAlphaSig, fAlphaBkgMin and fAlphaBkgMax make sense
  // (ie, fAlphaSig < fAlphaBkgMin < fAlphaBkgMax)

  Bool_t CheckAlphaSigBkg();

  void SetDegreeON (Int_t d) {fDegreeON = d;}
  void SetDegreeOFF (Int_t d) {fDegreeOFF = d;}


  void SetUseFittedQuantities (Bool_t b)
      {fUseFittedQuantities = b;}


  void SetPostScriptFile(TPostScript* PsFile);
  void SetPostScriptFile2(TPostScript &PsFile);

  void SetPsFilenameString (const TString filename);


  void SetMatrixFilter(MFilter *filter)          {fMatrixFilter = filter;}

  


  Bool_t DefineTrainMatrix(const TString &name, MH3 &href,
                           const Int_t howmany, const TString &filetrain);
  Bool_t DefineTestMatrix(const TString &name, MH3 &href,
                          const Int_t howmany, const TString &filetest);



  Bool_t DefineTrainTestMatrix(const TString &name, MH3 &href,
			 const Int_t howmanytrain, const Int_t howmanytest, 
                         const TString &filetrain, const TString &filetest);



  Bool_t DefineTrainTestMatrixThetaRange(const TString &name, 
					 const Double_t whichfractiontrain, 
					 const Double_t whichfractiontest,  
					 Double_t ThetaMin, Double_t ThetaMax, 
					 const TString &filetrain, const TString &filetest);



  
  Bool_t DefineTrainTestMatrixOFFThetaRange(const TString &name, 
					    const Double_t whichfractiontrain, 
					    const Double_t whichfractiontest,  
					    Double_t ThetaMin, Double_t ThetaMax, 
					    const TString &filetrain, const TString &filetest);


  MHMatrix *GetMatrixTrain() { return fMatrixTrain; }
  MHMatrix *GetMatrixTest()  { return fMatrixTest;  }
  MHMatrix *GetMatrixTrainOFF() { return fMatrixTrainOFF; }
  MHMatrix *GetMatrixTestOFF()  { return fMatrixTestOFF;  }


  void SetUseOrigDistribution(Bool_t b);


  Bool_t ReadMatrix( const TString &filetrain, const TString &filetest);
  
  Bool_t ReadMatrixOFF( const TString &filetrainOFF, const TString &filetestOFF);


  Bool_t ReadMatrixTrain(const TString &filetrainON, const TString &filetrainOFF);
  Bool_t ReadMatrixTest(const TString &filetestON, const TString &filetestOFF);



  Bool_t ComputeNormFactorTrain ();
  Bool_t ComputeNormFactorTest ();

  Bool_t FindParams(TString parSCinit, TArrayD &params, TArrayD &steps);
  // Bool_t TestParams();

  // Function used to apply the supercuts on the TEST sample.
  // Two event loops (one after the other) 
  // are used to fill the 2 alpha distributions (ON and OFF) 
  // applying supercuts to the Test sample
  Bool_t TestParamsOnTestSample(); 
  

  // Function used to apply the supercuts on the TRAIN sample.
  // Two event loops (one after the other) 
  // are used to fill the 2 alpha distributions (ON and OFF) 
  // applying supercuts to the TRAIN sample
  Bool_t TestParamsOnTrainSample();
  


  Bool_t SetThetaRange(Double_t ThetaMin, Double_t ThetaMax);

  Bool_t SetSizeRange(Double_t SizeMin, Double_t SizeMax);

  Bool_t SetFilters(Double_t LeakageMax, Double_t DistMax, Double_t DistMin);



  void SetAlphaPlotBinining(Int_t nbins, Double_t binlow, Double_t binup)
    { fNAlphaBins = nbins; fAlphaBinLow = binlow; fAlphaBinUp = binup;}

  Double_t GetNormFactorTrain() {return fNormFactorTrain;}
  Double_t GetNormFactorTest() {return fNormFactorTest;}
  Double_t GetSigmaLiMaTrain() {return fSigmaLiMaTrain;}
  Double_t GetSigmaLiMaTest() {return fSigmaLiMaTest;}
  Double_t GetNexTrain() {return fNexTrain;}
  Double_t GetNexTest() {return fNexTest;}


  Double_t GetAlphaSig() {return fAlphaSig;}
  Double_t GetAlphaBkgMin () {return fAlphaBkgMin;}
  Double_t GetAlphaBkgMax () {return fAlphaBkgMax;}
  
  Bool_t GetUseFittedQuantities() {return fUseFittedQuantities;}
  Bool_t GetSkipOptimization() {return fSkipOptimization;}
  Bool_t GetUseInitialSCParams() {return fUseInitialSCParams;}

  Bool_t SetGammaEfficiency (Double_t gammaeff);
  Double_t GetGammaEfficiency() {return fGammaEfficiency;}
  
  

  // Double_t ComputeNormFactorFromAlphaBkg(TH1 *histON, TH1 *histOFF);
           
  void SetTuneNormFactor(Bool_t b) {fTuneNormFactor = b;}

  void SetNormFactorFromAlphaBkg (Bool_t b) {fNormFactorFromAlphaBkg = b;}

  void SetSkipOptimization(Bool_t b);

  void SetUseInitialSCParams(Bool_t b);

  void SetVariableNotUseTheta(Bool_t b) {fNotUseTheta = b;}
  Bool_t GetVariableNotUseTheta() { return fNotUseTheta;}

  void SetVariableUseStaticCuts(Bool_t b) {fUseStaticCuts = b;}
  Bool_t GetVariableUseStaticCuts() { return fUseStaticCuts;}

  

  


  ClassDef(MFindSupercutsONOFF, 1) // Class for optimization of the Supercuts
};

#endif



















