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

const Char_t *defaultInFile  = "/star/data01/pwg/pusheax/data/MuDst/pp500/st_physics_12085031_raw_1030004.MuDst.root";
const Char_t *defaultOutFile = "oFemtoDstMesons_pp500_2011.root";

class StFemtoDstInclusiveSelector;
StFemtoDstInclusiveSelector *mFemtoDstInclSelector = NULL;

//_________________
void FemtoDstMaker_mesons_pp500_y2011(const Char_t* inFileList = defaultInFile,
                                      const Char_t* outFileName = defaultOutFile,
                                      const Bool_t  isAuAu = false) {

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

  //Constants, cut and initial parameters
  Float_t cVtxZ[2] = {-70., 70.};
  Float_t cVtxR[2] = {0., 3.};
  Float_t cVtxXShift = 0.;
  Float_t cVtxYShift = 0.;
  Float_t cVtxVpdVzDiff[2] = {-7., 7.};
  Float_t cParticleMom[2] = {0.15, 1.65};
  Float_t cTrackDcaGlobal[2] = {-0.01, 3.};
  Int_t   cTrackNHits[2] = {15, 50};
  Int_t   cTrackNHitsFit[2] = {5, 50};
  Float_t cTrackEta[2] = {-1., 1.};
  Int_t   cTrackFlag[2] = {0, 1000};
  Bool_t  cZdcRefmultCorrection = true;   //Should be false for low energies

  //Inclusive cuts
  Bool_t  cSelectPions = true;
  Bool_t  cSelectKaons = true;
  Bool_t  cSelectTpcPions = true;
  Bool_t  cSelectTpcKaons = true;
  Bool_t  cSelectTofKaons = true;
  Bool_t  cSelectTofPions = true;


  Float_t cPionTpcNSigmaElectron[2] = {-2., 2.};
  Float_t cPionTpcNSigmaPion[2] = {-3., 3.};
  Float_t cPionTpcNSigmaKaon[2] = {-2., 2.};
  Float_t cPionTpcNSigmaProton[2] = {-3., 3.};

  Float_t cKaonTpcNSigmaElectron[2] = {-3., 3.};
  Float_t cKaonTpcNSigmaPion[2] = {-2., 2.};
  Float_t cKaonTpcNSigmaKaon[2] = {-3., 3.};
  Float_t cKaonTpcNSigmaProton[2] = {-3., 3.};

  Float_t cKaonTofMom[2] = {0.55, 1.65};
  Float_t cKaonMassSqr[2] = {0.16, 0.35};
  Float_t cKaonTpcMom[2] = {0.15, 0.75};

  Float_t cPionTofMom[2] = {0.55, 1.65};
  Float_t cPionMassSqr[2] = {-0.05, 0.09};
  Float_t cPionTpcMom[2] = {0.15, 0.75};

  //Load libraries
  std::cout << "Loading libraries..." << std::endl;
  gROOT->LoadMacro("$STAR/StRoot/StMuDSTMaker/COMMON/macros/loadSharedLibraries.C");
  loadSharedLibraries();
  gSystem->Load("libMinuit");
  gSystem->Load("StChain");
  gSystem->Load("StRefMultCorr");
  gSystem->Load("StFlowMaker");
  gSystem->Load("StHbtMaker");
  gSystem->Load("StFemtoDstMaker");
  gSystem->Load("libStFemtoDstMaker.so");
  std::cout << "Libraries have been successfully loaded" << std::endl;

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

  //Create MuDst reader
  int nMaxFileToRead = 1e9;
  std::cout << Form("Try to read file: %s", inFileList) << std::endl;
  StMuDstMaker *muDstMaker = 
      new StMuDstMaker(0, 0, "", inFileList, "MuDst", nMaxFileToRead);
  muDstMaker->SetStatus("*",0);
  muDstMaker->SetStatus("Event*",1);
  muDstMaker->SetStatus("MuEvent*",1);
  muDstMaker->SetStatus("PrimaryVertices*",1);
  muDstMaker->SetStatus("PrimaryTracks*",1);
  muDstMaker->SetStatus("GlobalTracks*",1);
  muDstMaker->SetStatus("BTofHeader*",1);
  muDstMaker->SetStatus("BTofHit*", 1);
  TChain *mCurrentTree = muDstMaker->chain();
  Long64_t mNEvents = mCurrentTree->GetEntries();
  std::cout << Form("Number of events in TTree: %d", mNEvents) << std::endl;

  //Heavy ion related makers
  StRefMultCorr *mRefMult = new StRefMultCorr("refmult");

  //StFemtoDstMaker initialization
  mFemtoDstInclSelector = new StFemtoDstInclusiveSelector(muDstMaker,
                                                          outFileName);

  mFemtoDstInclSelector->AddTriggerId(320000);      //Trigger selection for pp500 y2011
  mFemtoDstInclSelector->AddTriggerId(320001);
  mFemtoDstInclSelector->AddTriggerId(320011);
  mFemtoDstInclSelector->AddTriggerId(320021);
  mFemtoDstInclSelector->AddTriggerId(330021);
  mFemtoDstInclSelector->AddTriggerId(330600);
  mFemtoDstInclSelector->AddTriggerId(330601);
  mFemtoDstInclSelector->AddTriggerId(330501);
  mFemtoDstInclSelector->AddTriggerId(330503);
  mFemtoDstInclSelector->AddTriggerId(330524);
  mFemtoDstInclSelector->AddTriggerId(320501);
  mFemtoDstInclSelector->AddTriggerId(320503);
  mFemtoDstInclSelector->AddTriggerId(320504);
  mFemtoDstInclSelector->AddTriggerId(320514);
  mFemtoDstInclSelector->AddTriggerId(320524);
  mFemtoDstInclSelector->AddTriggerId(320600);
  mFemtoDstInclSelector->AddTriggerId(320601);
  mFemtoDstInclSelector->AddTriggerId(320500);

  mFemtoDstInclSelector->SetVtxZCut(cVtxZ[0], cVtxZ[1]);
  mFemtoDstInclSelector->SetVtxRCut(cVtxR[0], cVtxR[1]);
  mFemtoDstInclSelector->SetVtxShift(cVtxXShift, cVtxYShift);
  mFemtoDstInclSelector->SetVtxVpdVzDiffCut(cVtxVpdVzDiff[0], cVtxVpdVzDiff[1]);
  mFemtoDstInclSelector->SetParticleMomentum(cParticleMom[0], cParticleMom[1]);
  mFemtoDstInclSelector->SetTrackDcaGlobal(cTrackDcaGlobal[0], cTrackDcaGlobal[1]);
  mFemtoDstInclSelector->SetTrackNHits(cTrackNHits[0], cTrackNHits[1]);
  mFemtoDstInclSelector->SetTrackNHitsFit(cTrackNHitsFit[0], cTrackNHitsFit[1]);
  mFemtoDstInclSelector->SetTrackEta(cTrackEta[0], cTrackEta[1]);
  mFemtoDstInclSelector->SetTrackFlag(cTrackFlag[0], cTrackFlag[1]);
  mFemtoDstInclSelector->SetCollisionTypeAuAu(isAuAu);
  mFemtoDstInclSelector->SetAuAuZdcCoincidenceEnergy(cZdcRefmultCorrection);
  mFemtoDstInclSelector->SetMuDstMaker(muDstMaker);

  //Inclusive selection
  //Pions
  mFemtoDstInclSelector->SetSelectProtons(false);    
  mFemtoDstInclSelector->SetSelectKaons(cSelectKaons);
  mFemtoDstInclSelector->SetSelectPions(cSelectPions);
  mFemtoDstInclSelector->SetSelectTpcPions(cSelectTpcPions);
  mFemtoDstInclSelector->SetSelectTpcKaons(cSelectTpcKaons);
  mFemtoDstInclSelector->SetSelectTofPions(cSelectTofPions);
  mFemtoDstInclSelector->SetSelectTofKaons(cSelectTofKaons);

  mFemtoDstInclSelector->SetPionTpcMom(cPionTpcMom[0], cPionTpcMom[1]);
  mFemtoDstInclSelector->SetPionTpcNSigmaElectron(cPionTpcNSigmaElectron[0],cPionTpcNSigmaElectron[1]);
  mFemtoDstInclSelector->SetPionTpcNSigmaPion(cPionTpcNSigmaPion[0],cPionTpcNSigmaPion[1]);
  mFemtoDstInclSelector->SetPionTpcNSigmaKaon(cPionTpcNSigmaKaon[0],cPionTpcNSigmaKaon[1]);
  mFemtoDstInclSelector->SetPionTpcNSigmaProton(cPionTpcNSigmaProton[0],cPionTpcNSigmaProton[1]);
  mFemtoDstInclSelector->SetPionTofMom(cPionTofMom[0],cPionTofMom[1]);
  mFemtoDstInclSelector->SetPionMassSqr(cPionMassSqr[0],cPionMassSqr[1]);

  mFemtoDstInclSelector->SetKaonTpcMom(cKaonTpcMom[0], cKaonTpcMom[1]);
  mFemtoDstInclSelector->SetKaonTpcNSigmaElectron(cKaonTpcNSigmaElectron[0],cKaonTpcNSigmaElectron[1]);
  mFemtoDstInclSelector->SetKaonTpcNSigmaPion(cKaonTpcNSigmaPion[0],cKaonTpcNSigmaPion[1]);
  mFemtoDstInclSelector->SetKaonTpcNSigmaKaon(cKaonTpcNSigmaKaon[0],cKaonTpcNSigmaKaon[1]);
  mFemtoDstInclSelector->SetKaonTpcNSigmaProton(cKaonTpcNSigmaProton[0],cKaonTpcNSigmaProton[1]);
  mFemtoDstInclSelector->SetKaonTofMom(cKaonTofMom[0],cKaonTofMom[1]);
  mFemtoDstInclSelector->SetKaonMassSqr(cKaonMassSqr[0],cKaonMassSqr[1]);

  //Chain initialization and loop over events
  mChain->Init();
  Int_t iReturn = 0;
  Int_t mNEventsProcessed = 0;
  Float_t mPercentStep = 0.05;
  Float_t mPercentCounter = mPercentStep;
  Float_t mProgress = 0.;

  time_t mStartTime, mStopTime, mDiffTime;   // time
  float mFrac;                               // time
  mStartTime = time(0);                      // time

  for(Int_t iEvent=0; iEvent<mNEvents; iEvent++) {

    mProgress = (Float_t)iEvent/(Float_t)mNEvents;
    mNEventsProcessed++;

    if(mProgress >= mPercentCounter) {
      mPercentCounter += mPercentStep;
      mStopTime = time(0);
      mDiffTime = difftime(mStopTime, mStartTime);
      mFrac = (float)mDiffTime*(float)(mNEvents - iEvent)/(float)iEvent;
      std::cout << Form("Processing progress: %3.0f%%. ETA: %.1f sec", mProgress*100., mFrac)
          << std::endl;
    }

    mChain->Clear();
    iReturn = mChain->Make(iEvent);
    if(iReturn != 0) {
      std::cout << "Error has been occured. Event processing has been stopped"
          << std::endl;
      break;
    }
  } //for(Int_t iEvent=0; iEvent<mNEvents; iEvent++)

  mChain->Finish();
  delete mFemtoDstInclSelector;
  delete mChain;

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