////////////////////////////////////////////////////////////////////////////////////
//
//             _____ Control Plot program_____
//
//  Take as input root files with hillas parameters and generates several
//  control plots.
//  Output is a file with :
//       - Number of hits plot
//
//                 Ester Aliu   <aliu@ifae.es>
//                 Oscar Blanch <blanch@ifae.es>
//                 Javier Rico  <jrico@ifae.es>
////////////////////////////////////////////////////////////////////////////////////

#include <fstream>
#include <iostream>

#include "TString.h"

#include "MHillasSrcCalc.h"
#include "MHillasSrc.h"
#include "MSrcRotate.h"
#include "MSrcPosFromFile.h"
#include "MSrcTranslate.h"
#include "MParList.h"
#include "MTaskList.h"
#include "MHillas.h"
#include "MReadTree.h"
#include "MEvtLoop.h"
#include "MLog.h"
#include "MArgs.h"
#include "MWriteRootFile.h"
#include "MTime.h"
#include "MControlPlots.h"
#include "MIslands.h"
#include "MContinue.h"
#include "MF.h"

using namespace std;

Bool_t readDatacards(TString& filename);
void controlPlot();

//-----------------------------------------------------------------------------
// declaration of variables read from datacards
//-----------------------------------------------------------------------------

TString  inputFile;
TString  offFile;
TString  outputFile;
TString  filter;
TString  sizecut;
TString  distcut;
TString  widthcut;
TString  lengthcut;
TString  centercut;
ULong_t  nmaxevents=999999999;
Float_t  xsrcpos=0.;
Float_t  ysrcpos=0.;
Double_t mjdpos=0;

//-----------------------------------------------------------------------------
// constants
//-----------------------------------------------------------------------------

const TString defaultcard="controlplot.datacard";
const Float_t conver   = 189./0.6; // conversion factor degrees to mm

//-----------------------------------------------------------------------------

static void Usage()
{
  gLog <<endl;
  gLog << "Usage is:" << endl;
  gLog << "   controlPlot [-h] [-?] <datacards>" << endl << endl;
  gLog << "     <datacards>: datacards file name (dafault " << defaultcard <<")" << endl;
  gLog << "     -?/-h: This help" << endl << endl;
}

//-----------------------------------------------------------------------------
int main(int argc, char **argv)
{
  // evaluate arguments
  MArgs arg(argc, argv);
  if (arg.HasOnly("-?") || arg.HasOnly("-h") || arg.HasOnly("--help"))
    {
      Usage();
      return -1;
    }

  TString datacard  = arg.GetArgumentStr(0);
  if(!datacard.Length())
    datacard = defaultcard;

  if(!readDatacards(datacard))
    {
      cout << "Error reading datacards. Stoping" << endl;
      return -1;
    }

  controlPlot();
}

//-----------------------------------------------------------------------------
void  controlPlot()
{
  // containers
  MParList  plist;  
  MTaskList tlist;
  MIslands  islands;

  // include containers in parameter list
  plist.AddToList(&tlist);
	  	  
  MF cut(filter);
  MF cutS(sizecut);
  MF cutD(distcut);
  MF cutL(lengthcut);
  MF cutW(widthcut);
  MF cutC(centercut);

  // tasks
  MReadTree read("Parameters", inputFile);
  read.DisableAutoScheme();  

  MControlPlots controlplots(outputFile);
  controlplots.SetProduceFile(kFALSE);
  controlplots.SetMode(MControlPlots::kOn);
  
  MContinue applycutS(&cutS);
  applycutS.SetInverted(kTRUE);

  MContinue applycutD(&cutD);
  applycutD.SetInverted(kTRUE);

  MContinue applycutL(&cutL);
  applycutL.SetInverted(kTRUE);

  MContinue applycutW(&cutW);
  applycutW.SetInverted(kTRUE);

  MContinue applycutC(&cutC);
  applycutC.SetInverted(kTRUE);

  MContinue applycut(&cut);
  applycut.SetInverted(kTRUE);


  // include tasks in task list
  tlist.AddToList(&read);
  if(sizecut.Length())
    tlist.AddToList(&applycutS);
  if(distcut.Length())
    tlist.AddToList(&applycutD);
  if(lengthcut.Length())
    tlist.AddToList(&applycutL);
  if(widthcut.Length())
    tlist.AddToList(&applycutW);
  if(filter.Length())
    tlist.AddToList(&applycut);
  if(centercut.Length())
    tlist.AddToList(&applycutC);
  tlist.AddToList(&controlplots);

  // Eventloop
  MEvtLoop evtloop;
  evtloop.SetParList(&plist);
  if (!evtloop.Eventloop(nmaxevents))
    return;  
 
  tlist.PrintStatistics();
  
  // do off-data if input file was specified
  if(!offFile.Length())
    return;


  // containers
  MParList  plist2;  
  MTaskList tlist2;
  MIslands  islands2;

  // include containers in parameter list
  plist2.AddToList(&tlist2);
	  	  
  // tasks
  MReadTree read2("Parameters", offFile);
  read2.DisableAutoScheme();  
  tlist2.AddToList(&read2);

  controlplots.SetMode(MControlPlots::kOff);
  controlplots.SetProduceFile(kTRUE);
  controlplots.Reset();

  // include tasks in task list
  if(sizecut.Length())
    tlist2.AddToList(&applycutS);
  if(distcut.Length())
    tlist2.AddToList(&applycutD);
  if(lengthcut.Length())
    tlist2.AddToList(&applycutL);
  if(widthcut.Length())
    tlist2.AddToList(&applycutW);
  if(filter.Length())
    tlist2.AddToList(&applycut);
  if(centercut.Length())
    tlist2.AddToList(&applycutC);
  tlist2.AddToList(&controlplots);

  // Eventloop
  MEvtLoop evtloop2;
  evtloop2.SetParList(&plist2);
  if (!evtloop2.Eventloop(nmaxevents))
    return;  
 
  tlist2.PrintStatistics();
  
  // do off-data if input file was specified
  if(!offFile.Length())
    return;

}

//-----------------------------------------------------------------------
  
Bool_t readDatacards(TString& filename)
{
  ifstream ifun(filename.Data());
  if(!ifun)
    {
      cout << "File " << filename << " not found" << endl;
      return kFALSE;
    }

  TString word;
  
  while(ifun >> word)
    {
      // skip comments
      if(word[0]=='/' && word[1]=='/')
	{
	  while(ifun.get()!='\n'); // skip line
	  continue;
	}
      
      // number of events
      if(strcmp(word.Data(),"NEVENTS")==0)
	ifun >> nmaxevents;

      // input file name
      if(strcmp(word.Data(),"ONFILES")==0)
	{
	  if(inputFile.Length())
	    cout << "readDataCards Warning: overriding on-data file name" << endl;
	  ifun >> inputFile;
	}

      // off-data file name
      if(strcmp(word.Data(),"OFFFILES")==0)
	{
	  if(offFile.Length())
	    cout << "readDataCards Warning: overriding off-data file name" << endl;
	  ifun >> offFile;
	}

      // output file name
      if(strcmp(word.Data(),"HITSFILE")==0)
	{
	  if(outputFile.Length())
	    cout << "readDataCards Warning: overriding output file name" << endl;
	  ifun >> outputFile;
	}
      // exclusion cut
      if(strcmp(word.Data(),"FILTER")==0)
	{
	  if(filter.Length())
	    cout << "readDataCards Warning: overriding existing cut" << endl;
	  
	  char ch;
	  while((ch=ifun.get())!='\n')
	    filter.Append(ch);	  
	}
      if(strcmp(word.Data(),"SIZECUT")==0)
	{
	  if(sizecut.Length())
	    cout << "readDataCards Warning: overriding existing size cut" << endl;
	  char ch[10];
	  sizecut="(MHillas.fSize>";
	  ifun >> ch;
	  sizecut+=ch;
	  sizecut+=") && (MHillas.fSize<";
	  ifun >> ch;
	  sizecut+=ch;
	  sizecut+=")";
	}
      if(strcmp(word.Data(),"DISTCUT")==0)
	{
	  if(distcut.Length())
	    cout << "readDataCards Warning: overriding existing DIST cut" << endl;
	  char ch[10];
	  distcut="(MHillasSrc.fDist>";
	  ifun >> ch;
	  distcut+=ch;
	  distcut+="*";
	  distcut+=conver;
	  distcut+=") && (MHillasSrc.fDist<";
	  ifun >> ch;
	  distcut+=ch;
	  distcut+="*";
	  distcut+=conver;
	  distcut+=")";
	}
      if(strcmp(word.Data(),"WIDTHCUT")==0)
	{
	  if(widthcut.Length())
	    cout << "readDataCards Warning: overriding existing width cut" << endl;
	  char ch[10];
	  widthcut="(MHillas.fWidth>";
	  ifun >> ch;
	  widthcut+=ch;
	  widthcut+="*";
	  widthcut+=conver;
	  widthcut+=") && (MHillas.fWidth<";
	  ifun >> ch;
	  widthcut+=ch;
	  widthcut+="*";
	  widthcut+=conver;
	  widthcut+=")";
	}
      if(strcmp(word.Data(),"LENGTHCUT")==0)
	{
	  if(lengthcut.Length())
	    cout << "readDataCards Warning: overriding existing length cut" << endl;
	  char ch[10];
	  lengthcut="(MHillas.fLength>";
	  ifun >> ch;
	  lengthcut+=ch;
	  lengthcut+="*";
	  lengthcut+=conver;
	  lengthcut+=") && (MHillas.fLength<";
	  ifun >> ch;
	  lengthcut+=ch;
	  lengthcut+="*";
	  lengthcut+=conver;
	  lengthcut+=")";
	}
      if(strcmp(word.Data(),"CENTERCUT")==0)
	{
	  if(centercut.Length())
	    cout << "readDataCards Warning: overriding existing center cut" << endl;
	  char ch[10];
	  centercut="sqrt(MHillas.fMeanX*MHillas.fMeanX+MHillas.fMeanY*MHillas.fMeanY)<";
	  ifun >> ch;
	  centercut+=ch;
	  centercut+="*";
	  centercut+=conver;
	}
    }
  
  // check compulsory values
  if(!inputFile.Length())
    {
      cout << "No on-data file name specified" << endl;
      return kFALSE;
    }

  if(!offFile.Length())
    {
      cout << "No off-data file name specified" << endl;
      return kFALSE;
    }

  if(!outputFile.Length())
    {
      cout << "No output file name specified" << endl;
      return kFALSE;
    }

  MTime thetime(mjdpos);

  // Dump read values
  cout << "************************************************" << endl;
  cout << "* Datacards read from file " << filename << endl;
  cout << "************************************************" << endl;
  cout << "Maximum number of input events: " << nmaxevents << endl;
  cout << "Input file name(s): " << inputFile << endl;
  cout << "Input file name(s) for off data: " << offFile << endl;
  cout << "Output file name for # hits plot : " << outputFile << endl;
  if(filter.Length())
    cout << "Applying rejection cut: " << filter << endl;
  cout << "***********" << endl << endl;

  return kTRUE;
}
