#include "StHbtMaker/CorrFctn/QinvCorrFctnOpposHemisphere.h"
#include <sstream>
#include <cstdio>
#include <TRandom3.h>

#ifdef __ROOT__
ClassImp(QinvCorrFctnOpposHemisphere)
#endif

//_________________
QinvCorrFctnOpposHemisphere::QinvCorrFctnOpposHemisphere(char *title,
							 int   nbins,
							 float QinvLo,
							 float QinvHi,
                                                         float mass,
                                                         StHbtPairCut *paircut) {
   // set up numerator
  //  title = "Num Qinv (MeV/c)";
  stringstream TitNum,TitDen,TitRat;
  TitNum.str("");TitDen.str("");TitRat.str("");
  TitNum<<title<<"_Num";
  TitDen<<title<<"_Den";
  TitRat<<title<<"_Rat";
  mNumerator = new StHbt1DHisto(TitNum.str().c_str(),
				TitNum.str().c_str(),
				nbins,QinvLo,QinvHi);
  // set up denominator
  //title = "Den Qinv (MeV/c)";
  mDenominator = new StHbt1DHisto(TitDen.str().c_str(),
				  TitDen.str().c_str(),
				  nbins,QinvLo,QinvHi);
  // set up ratio
  //title = "Ratio Qinv (MeV/c)";
  mRatio = new StHbt1DHisto(TitRat.str().c_str(),
			    TitRat.str().c_str(),
			    nbins,QinvLo,QinvHi);
  // this next bit is unfortunately needed so that we can have many histos of same "title"
  // it is neccessary if we typedef StHbt1DHisto to TH1d (which we do)
  mNumerator->Sumw2();
  mNumerator->SetDirectory(0);
  mDenominator->Sumw2();
  mDenominator->SetDirectory(0);
  mRatio->Sumw2();
  mRatio->SetDirectory(0);

  mRandy = new TRandom3((unsigned int)time(0)); // TODO: modify to c-stdlib rand function
                                                //       rand_r?

  mMass = mass;
  mPairCut = paircut;
  mPairCutFlag = true;
}

//_________________
QinvCorrFctnOpposHemisphere::~QinvCorrFctnOpposHemisphere() {
  delete mNumerator;
  delete mDenominator;
  delete mRatio;
}

//_________________
void QinvCorrFctnOpposHemisphere::Finish() {
  mRatio->Divide(mNumerator,mDenominator,1.0,1.0);
}

//_________________
void QinvCorrFctnOpposHemisphere::AddMixedPair(const StHbtPair* pair) {
  /*Empty*/
}
//_________________
void QinvCorrFctnOpposHemisphere::AddRealPair(const StHbtPair* pair) {
  double weight = 1.0;
  if (mPairCut->Pass(pair)) {
    double Qinv = fabs(pair->qInv());
    mNumerator->Fill(Qinv);
  }
  //
  // Calculate new pair
  //
  double rnd = mRandy->Rndm();
  StHbtTrack newTrack(rnd > 0.5 ?                // if rnd > 0.5 then
                      *pair->track1()->Track() : // track1 otherwise
                      *pair->track2()->Track()); // track2
  StHbtThreeVector trackP = newTrack.P();
  trackP *= -1.0; // invert momentum of the track
  newTrack.SetP(trackP);
  StHbtThreeVector trackPGlobal = newTrack.PGlobal();
  trackPGlobal *= -1.0; // invert momentum of the track
  newTrack.SetPGlobal(trackPGlobal);
  //
  // Re-calculate helix
  //
  // primary helix
  const StPhysicalHelixD &helix = newTrack.Helix();
  StPhysicalHelixD newHelix(trackP, helix.origin(),
                            mMagField*kilogauss, newTrack.Charge());
  newTrack.SetHelix(newHelix);
  // global helix
  const StPhysicalHelixD &helixGlobal = newTrack.HelixGlobal();
  StPhysicalHelixD newHelixGlobal(trackPGlobal, helixGlobal.origin(),
                                  mMagField*kilogauss, newTrack.Charge());
  newTrack.SetHelixGlobal(newHelixGlobal);

  //
  // Set new particle and pair
  //
  StHbtParticle newParticle(&newTrack, mMass);
  StHbtPair newPair(rnd > 0.5 ? pair->track2() : pair->track1(),
                    &newParticle);
  //
  // Check cut for the new pair and fill denominator
  //
  if (mPairCut->Pass(&newPair)) {
    double Qinv = fabs(newPair.qInv());
    mDenominator->Fill(Qinv, weight);
  }
}

//____________________________
StHbtString QinvCorrFctnOpposHemisphere::Report(){
  string stemp = "Qinv Correlation Function of Opposite Hemi-sphere Report:\n";
  char ctemp[100];
  sprintf(ctemp,"Number of entries in numerator:\t%E\n",mNumerator->GetEntries());
  stemp += ctemp;
  sprintf(ctemp,"Number of entries in denominator:\t%E\n",mDenominator->GetEntries());
  stemp += ctemp;
  sprintf(ctemp,"Number of entries in ratio:\t%E\n",mRatio->GetEntries());
  stemp += ctemp;
  //  stemp += mCoulombWeight->Report();
  StHbtString returnThis = stemp;
  return returnThis;
}
