#include <TROOT.h>
#include <TSystem.h>
#include <TChain.h>
#include <TFile.h>
#include <TString.h>
#include <iostream>

// #define MONITORS

//
// Constants for analyses
//
// event information
const int   mRefMult[2] = {0, 10000};
const float mImpPar[2]  = {0., 666.};


// track information
const double mChargedKaonMass = 0.493677;
const double mChargedPionMass = 0.13957018;
const int mPosCharge = +1;
const int mNegCharge = -1;
const int mTrackType = 1;

const double mTrackMom[2]       = {0.15, 1.55};  //General momentum of the track [GeV/c]
const double mTrackTransvMom[2] = {0.15, 1.55};  //General transverse momentum of the track [GeV/c]
const double mTrackEta[2]       = { -1., 1.};

// pair information
const double mPairKt[2] = {0.,1.5};      //Pair transverse momentum cut
const double mPairQinv[2] = {0., 0.8};   //Pair relative momentum

// histograms values
const int    mQinvBins = 80;                 //10 MeV/c^2 bin width
const double mQinvVal[2] = {0., 0.8};        //Redefine for each analysis

const char *defaultInFile = "O97Dst.root";
const char *defaultOutFile = "oSimAuAu200KaonO97Dst_1D.root";

//_________________
void simKaonHBT_O97Dst_1D_TEST(const Char_t *inFileList = defaultInFile,
			       const Char_t *oFileName = defaultOutFile) {

  std::cout << "********************************" << std::endl
	    << "*     simKaonHBT_O97Dst_1D     *" << std::endl
	    << "*            Start             *" << std::endl
	    << "********************************" << std::endl;

  //
  // Load libraries
  //
  std::cout << "Loading libraries..." << std::endl;
  gROOT->LoadMacro("$STAR/StRoot/StMuDSTMaker/COMMON/macros/loadSharedLibraries.C");
  loadSharedLibraries();
  gSystem->Load("libMinuit");
  gSystem->Load("StRefMultCorr");
  gSystem->Load("StFlowMaker");   // should be placed before HBT
  gSystem->Load("StHbtMaker");
  gSystem->Load("StarClassLibrary");
  gSystem->Load("libgsl");
  gSystem->Load("libgslcblas");
  gSystem->Load("StFemtoDstMaker");

  std::cout << "Libraries have been successfully loaded" << std::endl;

  //
  // Create chain
  //
  StChain* mChain = new StChain("StChain");
  mChain->SetDebug(0);
  StMuDebug::setLevel(0);

  //
  // Set StHbtMaker and StHbtManager
  //
  StHbtMaker *mHbtMaker = new StHbtMaker();
  mHbtMaker->SetDebug(0);
  StHbtManager *mHbtManager = mHbtMaker->HbtManager();

  //
  // Set StHbtReader
  //
  StHbtO97DstReader *O97Reader = new StHbtO97DstReader("", inFileList, "root", -1, true);
  Long64_t mNEvents = O97Reader->GetNEvents();
  mHbtManager->SetEventReader(O97Reader);

  //
  // Set basic event cut
  //
  nikEventCut *mBasicEventCut = new nikEventCut();
  mBasicEventCut->SetEventMult(mRefMult[0], mRefMult[1]);
  mBasicEventCut->SetImpactPar(mImpPar[0], mImpPar[1]);

  //
  // Set basic kaon single-particle cut
  //
  nikTrackCut *mBasicTrackCut = new nikTrackCut();
  mBasicTrackCut->SetCharge(mPosCharge);
  mBasicTrackCut->SetPdg(321);
  mBasicTrackCut->SetEta(mTrackEta[0], mTrackEta[1]);
  mBasicTrackCut->SetP(mTrackMom[0], mTrackMom[1]);

  //
  // Set basic kaon pair cut
  //
  nikTrackPairCut *mBasicPairCut = new nikTrackPairCut();

  int mLocalCharge, mMultBins, mMultLow, mMultHi, mEvents2Mix = 1, mCurrentPid;
  int mCentLo, mCentHi;

  //
  // StHbtAnalysis, cut, CF and monitor declarations
  //
  //  StHbtVertexMultAnalysis *mKaonMultAnalysis[2];
  StHbtAnalysis *mKaonMultAnalysis[2];
  
  //Cuts
  nikEventCut       *mKaonEventCut[2];
  nikTrackCut       *mKaonTrackCut[2];
  nikTrackPairCut   *mKaonPairCut[2];

  //CorrFctns
  QinvWeightCorrFctn *mKaonQinvMixCF[2];

#ifdef MONITORS
  fxtEventCutMonitor *mFxtKaonEventCutMonitorPass[2];
  fxtTrackCutMonitor *mFxtKaonTrackCutMonitorPass[2];
  fxtPairCutMonitor  *mFxtKaonPairCutMonitorPass[2];
  fxtEventCutMonitor *mFxtKaonEventCutMonitorFail[2];
  fxtTrackCutMonitor *mFxtKaonTrackCutMonitorFail[2];
  fxtPairCutMonitor  *mFxtKaonPairCutMonitorFail[2];
#endif


  for (int iCharge = 1; iCharge < 2; iCharge++) {

	switch(iCharge) {
	case 0:  mLocalCharge = mPosCharge;    break;
	case 1:  mLocalCharge = mNegCharge;    break;
	default: mLocalCharge = mPosCharge;    break;
	};

	//
	//Create analysis
	//
	/*
	mKaonMultAnalysis[iCharge] = new StHbtVertexMultAnalysis(20,
								 0.,
								 10.,
								 100,
								 0,
								 10000);
	*/
	mKaonMultAnalysis[iCharge] = new StHbtAnalysis();
	
	//
	// Create event cut
	//
	mKaonEventCut[iCharge] = new nikEventCut(*mBasicEventCut);

#ifdef MONITORS
	mFxtKaonEventCutMonitorPass[iCharge] = 
	  new fxtEventCutMonitor("eventKaonPass", Form("_%d", iCharge));
	mFxtKaonEventCutMonitorFail[iCharge] = 
	  new fxtEventCutMonitor("eventKaonFail", Form("_%d", iCharge));
	mKaonEventCut[iCharge]->AddCutMonitor(mFxtKaonEventCutMonitorPass[iCharge],
					      mFxtKaonEventCutMonitorFail[iCharge]);
#endif
	mKaonMultAnalysis[iCharge]->SetEventCut(mKaonEventCut[iCharge]);

	//
	// Create single-track cuts and add them to the analysis
	//
	mKaonTrackCut[iCharge] = new nikTrackCut(*mBasicTrackCut);

#ifdef MONITORS
	mFxtKaonTrackCutMonitorPass[iCharge] = 
	  new fxtTrackCutMonitor(Form("_trackKaonPass_%d", iCharge), mChargedKaonMass);
	mFxtKaonTrackCutMonitorFail[iCharge] = 
	  new fxtTrackCutMonitor(Form("_trackKaonFail_%d", iCharge), mChargedKaonMass);
	mKaonTrackCut[iCharge]->AddCutMonitor(mFxtKaonTrackCutMonitorPass[iCharge],
					      mFxtKaonTrackCutMonitorFail[iCharge]);
#endif
	mKaonMultAnalysis[iCharge]->SetFirstParticleCut(mKaonTrackCut[iCharge]);
	mKaonMultAnalysis[iCharge]->SetSecondParticleCut(mKaonTrackCut[iCharge]);

	//
	// Create pair cut
	//
	mKaonPairCut[iCharge] = new nikTrackPairCut(*mBasicPairCut);
#ifdef MONITORS
	mFxtKaonPairCutMonitorPass[iCharge] = 
	  new fxtPairCutMonitor(Form("_pairKaonPass_%d", iCharge));
	mFxtKaonPairCutMonitorPass[iCharge]->SetParticleMass(mChargedKaonMass);
	mFxtKaonPairCutMonitorFail[iCharge] = 
	  new fxtPairCutMonitor(Form("_pairKaonFail_%d", iCharge));
	mFxtKaonPairCutMonitorFail[iCharge]->SetParticleMass(mChargedKaonMass);
	mKaonPairCut[iCharge]->AddCutMonitor(mFxtKaonPairCutMonitorPass[iCharge],
					     mFxtKaonPairCutMonitorFail[iCharge]);
#endif
	mKaonMultAnalysis[iCharge]->SetPairCut(mKaonPairCut[iCharge]);

	//
	// Correlation function initialization
	//
	mKaonQinvMixCF[iCharge] = 
	  new QinvWeightCorrFctn(Form("hKaonQinvMix_%d", iCharge),
				 mQinvBins, mQinvVal[0], mQinvVal[1]);
	
	mKaonMultAnalysis[iCharge]->AddCorrFctn(mKaonQinvMixCF[iCharge]);

	//Set number of events to mix
	mKaonMultAnalysis[iCharge]->SetNumEventsToMix(mEvents2Mix);
	
	//Add analysis to the manager
	mHbtManager->AddAnalysis(mKaonMultAnalysis[iCharge]);
  } //for (int iCharge=0; iCharge<2; iCharge++)

  //
  // StChain initialization
  //
  mChain->Init();

  //
  //Start processing
  //
  Int_t   iRet = 0;
  Int_t   mNEventsProcessed = 0;
  Float_t mPercentCounter = 0.05;
  Float_t mProgress = 0.;

  // time left feature
  unsigned int mSubCounter = 1;             
  time_t       mStartTime, mStopTime, mDiffTime;
  float        mFrac;                          
  mStartTime = time(0);

  //
  // mNEvents = 15;
  //
  std::cout << "[MACRO]: total number of events = " << mNEvents << std::endl;

  //  mNEvents = 10;
  for (int iEvent = 0; iEvent < mNEvents; iEvent++) {
    mProgress = (Float_t)iEvent / (Float_t)mNEvents;
    mNEventsProcessed++;
    
    if(mProgress >= mPercentCounter) {
      mPercentCounter += 0.05;
      mStopTime = time(0);
      mDiffTime = difftime(mStopTime, mStartTime);
      mFrac = (float)mDiffTime*(float)(mNEvents - iEvent)/(float)iEvent;
      mSubCounter++;
      std::cout << Form("Processing progress: %4.2f%%. Time left: %.1f sec", mProgress*100., mFrac)
		<< std::endl;
    }

    mChain->Clear();
    iRet = mChain->Make(iEvent);
    if(iRet!=0) {
      std::cout << "expKaonHBT_pp200_1D[ERROR] - iRet: " << iRet << std::endl;
      break;
    }
  }

  mChain->Finish();

  //
  // Create output file
  //
  TFile *oFile = new TFile(oFileName, "RECREATE");

  // write hbt histograms to the file
  std::cout << "Writing histograms to the output file...";

#ifdef MONITORS
  for (int iCharge = 0; iCharge < 2; iCharge++) {
        mFxtKaonEventCutMonitorPass[iCharge]->VertexZ()->Write();
	mFxtKaonEventCutMonitorPass[iCharge]->VertexYvsVertexX()->Write();
	mFxtKaonEventCutMonitorPass[iCharge]->RefMult()->Write();
	mFxtKaonEventCutMonitorPass[iCharge]->VpdVzDiff()->Write();

	mFxtKaonEventCutMonitorFail[iCharge]->VertexZ()->Write();
	mFxtKaonEventCutMonitorFail[iCharge]->VertexYvsVertexX()->Write();
	mFxtKaonEventCutMonitorFail[iCharge]->RefMult()->Write();
	mFxtKaonEventCutMonitorFail[iCharge]->VpdVzDiff()->Write();

	mFxtKaonTrackCutMonitorPass[iCharge]->P()->Write();
	mFxtKaonTrackCutMonitorPass[iCharge]->Pt()->Write();
	mFxtKaonTrackCutMonitorPass[iCharge]->Rapidity()->Write();
	mFxtKaonTrackCutMonitorPass[iCharge]->PseudoRapidity()->Write();
	mFxtKaonTrackCutMonitorPass[iCharge]->PtVsMassSqr()->Write();
	mFxtKaonTrackCutMonitorPass[iCharge]->PvsInvBeta()->Write();

	mFxtKaonTrackCutMonitorFail[iCharge]->P()->Write();
	mFxtKaonTrackCutMonitorFail[iCharge]->Pt()->Write();
	mFxtKaonTrackCutMonitorFail[iCharge]->Rapidity()->Write();
	mFxtKaonTrackCutMonitorFail[iCharge]->PseudoRapidity()->Write();
	mFxtKaonTrackCutMonitorFail[iCharge]->PtVsMassSqr()->Write();
	mFxtKaonTrackCutMonitorFail[iCharge]->PvsInvBeta()->Write();

	mFxtKaonPairCutMonitorPass[iCharge]->Kt()->Write();
	mFxtKaonPairCutMonitorFail[iCharge]->Kt()->Write();
  } // for (int iCharge = 0; iCharge < 2; iCharge++)
#endif

  for (int iCharge = 1; iCharge < 2; iCharge++) {
    mKaonQinvMixCF[iCharge]->Numerator()->Write();
    mKaonQinvMixCF[iCharge]->Denominator()->Write();
  } // for (int iCharge = 0; iCharge < 2; iCharge++)

  std::cout << "\t[DONE]" << std::endl;

  //
  // Write the output file and close it
  //
  std::cout << "Saving the output file...";
  oFile->Write();
  oFile->Close();
  std::cout << "\t[DONE]" << std::endl;

  delete mChain;

  std::cout << "*********************************" << std::endl
	    << "*      expKaonHBT_auau200_1D    *" << std::endl
	    << "*              Finish           *" << std::endl
	    << "*********************************" << std::endl << std::endl;
}
