#include "StHbtV0.hh"
#include "StHbtTTreeV0.h"
#include "phys_constants.h"
#include "StHbtTTreeEvent.h"

//_________________
StHbtV0::StHbtV0(const StHbtV0& v) { // copy constructor

  //V0
  mDecayLengthV0 = v.mDecayLengthV0;
  mDecayVertexV0 = v.mDecayVertexV0;
  mDcaV0Daughters = v.mDcaV0Daughters;
  mDcaV0ToPrimVertex = v.mDcaV0ToPrimVertex;
  mChi2V0 = v.mChi2V0;
  mClV0 = v.mClV0;
  mMomV0 = v.mMomV0;
  mAlphaV0 = v.mAlphaV0;
  mPtArmV0 = v.mPtArmV0;

  //Positive daughter
  mKeyPos = v.mKeyPos;
  mDcaPosToPrimVertex = v.mDcaPosToPrimVertex;
  mMomPos = v.mMomPos;
  mHelixPos = v.mHelixPos;
  mTrackTopologyMapPos[0] = v.mTrackTopologyMapPos[0];
  mTrackTopologyMapPos[1] = v.mTrackTopologyMapPos[1];
  mTpcHitsPos = v.mTpcHitsPos;
  //mNHitsFitPos = v.mNHitsFitPos;
  mNHitsPossiblePos = v.mNHitsPossiblePos;
  mNumDedxPos = v.mNumDedxPos;
  mChi2Pos = v.mChi2Pos;
  mClPos = v.mClPos;
  mDedxPos = v.mDedxPos;
  mErrDedxPos = v.mErrDedxPos;
  mLenDedxPos = v.mLenDedxPos;
  mNSigmaElectronPos = v.mNSigmaElectronPos;
  mNSigmaPionPos = v.mNSigmaPionPos;
  mNSigmaKaonPos = v.mNSigmaKaonPos;
  mNSigmaProtonPos = v.mNSigmaProtonPos;
  mTofBetaPos = v.mTofBetaPos;

  //Negative daughter
  mKeyNeg = v.mKeyNeg;  
  mDcaNegToPrimVertex = v.mDcaNegToPrimVertex;
  mMomNeg = v.mMomNeg;
  mHelixNeg = v.mHelixNeg;
  mTrackTopologyMapNeg[0] = v. mTrackTopologyMapNeg[0];
  mTrackTopologyMapNeg[1] = v.mTrackTopologyMapNeg[1];
  mTpcHitsNeg = v.mTpcHitsNeg;
  //mNHitsFitNeg = v.mNHitsFitNeg;
  mNHitsPossibleNeg = v.mNHitsPossibleNeg;
  mNumDedxNeg = v.mNumDedxNeg;
  mChi2Neg = v.mChi2Neg;
  mClNeg = v.mClNeg;
  mDedxNeg = v.mDedxNeg;
  mErrDedxNeg = v.mErrDedxNeg;
  mLenDedxNeg = v.mLenDedxNeg;
  mNSigmaElectronNeg = v.mNSigmaElectronNeg;
  mNSigmaPionNeg = v.mNSigmaPionNeg;
  mNSigmaKaonNeg = v.mNSigmaKaonNeg;
  mNSigmaProtonNeg = v.mNSigmaProtonNeg;
  mTofBetaNeg = v.mTofBetaNeg;

  mHiddenInfo = v.mHiddenInfo? v.mHiddenInfo->clone() : 0;

  UpdateV0();
}

//_________________
void StHbtV0::UpdateV0(){

  //Calc. derived memebers of the v0 class
  float MomNegAlongV0, MomPosAlongV0;
  float mPtotV0 = mMomV0.mag();
  float mPtotPos = mMomPos.mag();  //Only positive is needed for the mPtArmV0

  mMomV0  = mMomPos + mMomNeg;
  MomNegAlongV0 =  mMomNeg*mMomV0 / ::sqrt(::pow(mPtotV0,2));
  MomPosAlongV0 =  mMomPos*mMomV0 / ::sqrt(::pow(mPtotV0,2));
  mAlphaV0 = (MomPosAlongV0 - MomNegAlongV0) / (MomPosAlongV0 + MomNegAlongV0);
  mPtArmV0 = ::sqrt(mPtotPos*mPtotPos - MomPosAlongV0*MomPosAlongV0);
}

//_________________
float StHbtV0::eLambda() const {
  float mELambda= ::sqrt( ptotV0()*ptotV0() + M_LAMBDA*M_LAMBDA );
  return mELambda;
}

//_________________
float StHbtV0::eK0Short() const {
  float mEK0Short= ::sqrt( ptotV0()*ptotV0() + M_KAON_0_SHORT*M_KAON_0_SHORT );
  return mEK0Short;
}

//_________________
float StHbtV0::ePhi() const {
  float mEPhi = ::sqrt( ptotV0()*ptotV0() + M_PHI*M_PHI );
  return mEPhi;
}

//_________________
float StHbtV0::ePosProton() const {
  float mEPosProton = ::sqrt( ptotPos()*ptotPos() + M_PROTON*M_PROTON );
  return mEPosProton;
}

//_________________
float StHbtV0::eNegProton() const {
  float mENegProton = ::sqrt( ptotNeg()*ptotNeg() + M_PROTON*M_PROTON );
  return mENegProton;
}

//_________________
float StHbtV0::ePosPion() const {
  float mEPosPion = ::sqrt( ptotPos()*ptotPos() + M_PION_PLUS*M_PION_PLUS );
  return mEPosPion;
}

//_________________
float StHbtV0::eNegPion() const {
  float mENegPion = ::sqrt( ptotNeg()*ptotNeg() + M_PION_MINUS*M_PION_MINUS );
  return mENegPion;
}
  
//_________________
float StHbtV0::ePosKaon() const {
  float mEPosKaon = ::sqrt( ptotPos()*ptotPos() + M_KAON_PLUS*M_KAON_PLUS);
  return mEPosKaon;
}
  
//_________________
float StHbtV0::eNegKaon() const {
  float mENegKaon = ::sqrt( ptotNeg()*ptotNeg() + M_KAON_MINUS*M_KAON_MINUS);
  return mENegKaon;
}

//_________________
float StHbtV0::massPhi() const {
  float mMassPhi = ::sqrt(::pow( (ePosKaon()+eNegKaon()), 2) - ::pow(ptotV0(), 2) );
  return mMassPhi;
}

//_________________
float StHbtV0::massLambda() const {
  float mMassLambda = ::sqrt(::pow( (ePosProton()+eNegPion()), 2) - ::pow(ptotV0(), 2) );
  return mMassLambda;
}

//_________________
float StHbtV0::massAntiLambda() const {
  float mMassAntiLambda = ::sqrt(::pow( (ePosPion()+eNegProton()), 2) - ::pow(ptotV0(), 2) );
  return mMassAntiLambda;
}

//_________________
float StHbtV0::massK0Short() const {
  float mMassK0Short = ::sqrt(::pow( (ePosPion()+eNegPion()), 2) - ::pow(ptotV0(), 2) );
  return mMassK0Short;
}

//_________________
float StHbtV0::cTauPhi() const {
  float mCTauPhi = M_PHI*(mDecayLengthV0) / ::sqrt( ::pow((double)ptotV0(), 2) );
  return mCTauPhi;
}

//_________________
float StHbtV0::cTauLambda() const {
  float mCTauLambda = M_LAMBDA*(mDecayLengthV0) / ::sqrt( ::pow((double)ptotV0(), 2) );
  return mCTauLambda;
} 

//_________________
float StHbtV0::cTauK0Short() const {
  float mCTauK0Short = M_KAON_0_SHORT*(mDecayLengthV0) / ::sqrt( ::pow((double)ptotV0(), 2) );
  return mCTauK0Short;
}

//_________________
float StHbtV0::rapPhi() const {
  float mRapPhi = 0.5*::log( (ePhi() + mMomV0.z()) / (ePhi() - mMomV0.z()) ); 
  return mRapPhi;
}
  
//_________________
float StHbtV0::rapLambda() const {
  float mRapLambda = 0.5*::log( (eLambda() + mMomV0.z()) / (eLambda() - mMomV0.z()) );
  return mRapLambda;
}

//_________________
float StHbtV0::rapK0Short() const {
  float mRapK0Short = 0.5*::log( (eK0Short() + mMomV0.z()) / (eK0Short() - mMomV0.z()) );
  return mRapK0Short;
}

//_________________
float StHbtV0::pseudoRapV0() const {
  float mPseudoRap = 0.5*::log( (ptotV0() + mMomV0.z()) / (ptotV0() - mMomV0.z()) );
  return mPseudoRap;
}

//_________________
float StHbtV0::pseudoRapPos() const {
  float mPseudoRap = 0.5*::log( (ptotPos() + mMomPos.z()) / (ptotPos() - mMomPos.z()) );
  return mPseudoRap;
}

//_________________
float StHbtV0::pseudoRapNeg() const {
  float mPseudoRap = 0.5*::log( (ptotNeg() + mMomNeg.z()) / (ptotNeg() - mMomNeg.z()) );
  return mPseudoRap;
}

//_________________
float StHbtV0::dMLambda() const {
  return (massLambda() - M_LAMBDA);
}

//_________________
float StHbtV0::dMAntiLambda() const {
  return (massAntiLambda() - M_LAMBDA);
}

//_________________
float StHbtV0::dMK0Short() const {
  return (massK0Short() - M_KAON_0_SHORT);
}

//_________________
float StHbtV0::dMPhi() const {
  return (massPhi() - M_PHI);
}

//_________________
float StHbtV0::tofMassSqrPos() const {
  float mMSqr = -999.;
  if(mTofBetaPos > 0.) {
    mMSqr = mMomPos.mag2() * (1./(mTofBetaPos*mTofBetaPos) - 1.);
  }
  return mMSqr;
}

//_________________
float StHbtV0::tofMassSqrNeg() const {
  float mMSqr = -999.;
  if(mTofBetaNeg > 0.) {
    mMSqr = mMomNeg.mag2() * (1./(mTofBetaNeg*mTofBetaNeg) - 1.);
  }
  return mMSqr;
}

//_________________
#ifdef __ROOT__
#include "StStrangeMuDstMaker/StV0MuDst.hh"
StHbtV0::StHbtV0(StV0MuDst& v){ // from strangess micro dst structure
  mDecayLengthV0 = v.decayLengthV0();
  mDecayVertexV0 = StHbtThreeVector( v.decayVertexV0X(), v.decayVertexV0Y(), v.decayVertexV0Z() );
  mDcaV0Daughters = v.dcaV0Daughters();
  mDcaV0ToPrimVertex = v.dcaV0ToPrimVertex();
  mDcaPosToPrimVertex = v.dcaPosToPrimVertex();
  mDcaNegToPrimVertex = v.dcaNegToPrimVertex();
  mMomPos = StHbtThreeVector( v.momPosX(), v.momPosY(), v.momPosZ() );
  mMomNeg = StHbtThreeVector( v.momNegX(), v.momNegY(), v.momNegZ() ); 
#ifdef STHBTDEBUG
  std::cout << " hist pos ";
  std::cout << v.topologyMapPos().numberOfHits(kTpcId); 
  std::cout << " hist neg ";
  std::cout << v.topologyMapNeg().numberOfHits(kTpcId) << std::endl;
#endif
  mTpcHitsPos = (unsigned char)( v.topologyMapPos().numberOfHits(kTpcId) );
  mTpcHitsNeg = (unsigned char)( v.topologyMapNeg().numberOfHits(kTpcId) );
  mTrackTopologyMapPos[0] = (unsigned int)( v.topologyMapPos().data(0) );
  mTrackTopologyMapPos[1] = (unsigned int)( v.topologyMapPos().data(1) );
  mTrackTopologyMapNeg[0] = (unsigned int)( v.topologyMapNeg().data(0) );
  mTrackTopologyMapNeg[1] = (unsigned int)( v.topologyMapNeg().data(1) );
  mKeyPos = v.keyPos();
  mKeyNeg = v.keyNeg();
  mChi2V0 = v.chi2V0();
  mClV0 = v.clV0();
  mChi2Pos = v.chi2Pos();
  mClPos = v.clPos();
  mChi2Neg = v.chi2Neg();
  mClNeg = v.clNeg();
  mDedxPos = v.dedxPos();
  mErrDedxPos = v.errDedxPos();
  mLenDedxPos = v.lenDedxPos();
  mDedxNeg = v.dedxNeg();
  mErrDedxNeg = v.errDedxNeg();
  mLenDedxNeg = v.lenDedxNeg();
  mNumDedxPos = (unsigned char)v.numDedxPos();
  mNumDedxNeg = (unsigned char)v.numDedxNeg();
  mHiddenInfo =  0;

#ifdef STHBTDEBUG
  cout << " keyPos " << v.keyPos() << endl;
  cout << " keyNeg " << v.keyNeg() << endl;
#endif
  mMomV0 = StHbtThreeVector( v.momV0X(), v.momV0Y(), v.momV0Z() );
#ifdef STHBTDEBUG
  cout << " alpha  ";
  cout << v.alphaV0();
  cout << " ptArm  ";
  cout << v.ptArmV0() << endl;
#endif
  mAlphaV0 = v.alphaV0();
  mPtArmV0 = v.ptArmV0();
  mDedxPos = v.dedxPos();
  mDedxNeg = v.dedxNeg();
}

//_________________
StHbtV0::StHbtV0(const StHbtTTreeEvent* ev, const StHbtTTreeV0* v) {

  mDecayVertexV0 = StHbtThreeVector(v->mDecayVertexV0X,v->mDecayVertexV0Y,v->mDecayVertexV0Z);

  mPrimaryVertex.setX(ev->mVertexX);
  mPrimaryVertex.setY(ev->mVertexY);
  mPrimaryVertex.setZ(ev->mVertexZ);

  mDecayLengthV0 = v->mDecayLengthV0;
  mDcaV0Daughters = v->mDcaV0Daughters;
  mDcaV0ToPrimVertex = v->mDcaV0ToPrimVertex;
  mDcaPosToPrimVertex = v->mDcaPosToPrimVertex;
  mDcaNegToPrimVertex = v->mDcaNegToPrimVertex;

  mMomPos = StHbtThreeVector( v->mMomPosX, v->mMomPosY, v->mMomPosZ);
  mMomNeg = StHbtThreeVector( v->mMomNegX, v->mMomNegY, v->mMomNegZ);
  
  mTrackTopologyMapPos[0] = (unsigned int)v->mTrackTopologyMapPos[0];
  mTrackTopologyMapPos[1] = (unsigned int)v->mTrackTopologyMapPos[1];
  mTrackTopologyMapNeg[0] = (unsigned int)v->mTrackTopologyMapNeg[0];
  mTrackTopologyMapNeg[1] = (unsigned int)v->mTrackTopologyMapNeg[1];
  
  mKeyPos = v->mKeyPos;
  mKeyNeg = v->mKeyNeg;

  mTpcHitsPos = (unsigned char)v->mTpcHitsPos;
  mTpcHitsNeg = (unsigned char)v->mTpcHitsNeg;
  mNumDedxPos = (unsigned char)v->mNumDedxPos;
  mNumDedxNeg = (unsigned char)v->mNumDedxNeg;
  
  mChi2V0 = v->mChi2V0;
  mClV0 = v->mClV0;
  mChi2Pos = v->mChi2Pos;
  mClPos = v->mClPos;
  mChi2Neg = v->mChi2Neg;
  mClNeg = v->mClNeg;

  mDedxPos = v->mDedxPos;
  mErrDedxPos = v->mErrDedxPos;
  mLenDedxPos = v->mLenDedxPos;
  mDedxNeg = v->mDedxNeg;
  mErrDedxNeg = v->mErrDedxNeg;
  mLenDedxNeg = v->mLenDedxNeg;
  mHiddenInfo = 0;

  UpdateV0();
}

//_________________
void StHbtV0::SetnSigmaElectronPos(const float ns) {
  mNSigmaElectronPos = (fabs(ns * 100.f) > std::numeric_limits<short>::max()) ? 
    std::numeric_limits<short>::max() : (short)(GregsNint(ns * 100.f));
}

//_________________
void StHbtV0::SetnSigmaPionPos(const float ns) {
  mNSigmaPionPos = (fabs(ns * 100.f) > std::numeric_limits<short>::max()) ? 
    std::numeric_limits<short>::max() : (short)(GregsNint(ns * 100.f));
}

//_________________
void StHbtV0::SetnSigmaKaonPos(const float ns) {
  mNSigmaKaonPos = (fabs(ns * 100.f) > std::numeric_limits<short>::max()) ? 
    std::numeric_limits<short>::max() : (short)(GregsNint(ns * 100.f));
}

//_________________
void StHbtV0::SetnSigmaProtonPos(const float ns) {
  mNSigmaProtonPos = (fabs(ns * 100.f) > std::numeric_limits<short>::max()) ? 
    std::numeric_limits<short>::max() : (short)(GregsNint(ns * 100.f));
}

//_________________
void StHbtV0::SetnSigmaElectronPos(const double ns) {
  mNSigmaElectronPos = (fabs(ns * 100.f) > std::numeric_limits<short>::max()) ? 
    std::numeric_limits<short>::max() : (short)(GregsNint(ns * 100.f));
}

//_________________
void StHbtV0::SetnSigmaPionPos(const double ns) {
  mNSigmaPionPos = (fabs(ns * 100.f) > std::numeric_limits<short>::max()) ? 
    std::numeric_limits<short>::max() : (short)(GregsNint(ns * 100.f));
}

//_________________
void StHbtV0::SetnSigmaKaonPos(const double ns) {
  mNSigmaKaonPos = (fabs(ns * 100.f) > std::numeric_limits<short>::max()) ? 
    std::numeric_limits<short>::max() : (short)(GregsNint(ns * 100.f));
}

//_________________
void StHbtV0::SetnSigmaProtonPos(const double ns) {
  mNSigmaProtonPos = (fabs(ns * 100.f) > std::numeric_limits<short>::max()) ? 
    std::numeric_limits<short>::max() : (short)(GregsNint(ns * 100.f));
}

//_________________
void StHbtV0::SetnSigmaPionNeg(const float ns) {
  mNSigmaPionNeg = (fabs(ns * 100.f) > std::numeric_limits<short>::max()) ? 
    std::numeric_limits<short>::max() : (short)(GregsNint(ns * 100.f));
}

//_________________
void StHbtV0::SetnSigmaKaonNeg(const float ns) {
  mNSigmaKaonNeg = (fabs(ns * 100.f) > std::numeric_limits<short>::max()) ? 
    std::numeric_limits<short>::max() : (short)(GregsNint(ns * 100.f));
}

//_________________
void StHbtV0::SetnSigmaProtonNeg(const float ns) {
  mNSigmaProtonNeg = (fabs(ns * 100.f) > std::numeric_limits<short>::max()) ? 
    std::numeric_limits<short>::max() : (short)(GregsNint(ns * 100.f));
}

//_________________
void StHbtV0::SetnSigmaElectronNeg(const double ns) {
  mNSigmaElectronNeg = (fabs(ns * 100.f) > std::numeric_limits<short>::max()) ? 
    std::numeric_limits<short>::max() : (short)(GregsNint(ns * 100.f));
}

//_________________
void StHbtV0::SetnSigmaPionNeg(const double ns) {
  mNSigmaPionNeg = (fabs(ns * 100.f) > std::numeric_limits<short>::max()) ? 
    std::numeric_limits<short>::max() : (short)(GregsNint(ns * 100.f));
}

//_________________
void StHbtV0::SetnSigmaKaonNeg(const double ns) {
  mNSigmaKaonNeg = (fabs(ns * 100.f) > std::numeric_limits<short>::max()) ? 
    std::numeric_limits<short>::max() : (short)(GregsNint(ns * 100.f));
}

//_________________
void StHbtV0::SetnSigmaProtonNeg(const double ns) {
  mNSigmaProtonNeg = (fabs(ns * 100.f) > std::numeric_limits<short>::max()) ? 
    std::numeric_limits<short>::max() : (short)(GregsNint(ns * 100.f));
}

//_________________
int StHbtV0::GregsNint(float x) {
  
  // Round to nearest integer. Rounds half integers to the nearest
  // even integer

  int i;
  if (x >= 0) {
    i = (int)(x + 0.5);
    if ( (x+0.5) == float(i) && i & 1 ) i--;
  } 
  else {
    i = (int)(x - 0.5);
    if ( (x-0.5) == float(i) && i & 1) i++;
  }

  return i;
}

//_________________
int StHbtV0::GregsNint(double x) {
  
  // Round to nearest integer. Rounds half integers to the nearest
  // even integer

  int i;
  if (x >= 0) {
    i = (int)(x + 0.5);
    if ( (x+0.5) == double(i) && i & 1 ) i--;
  } 
  else {
    i = (int)(x - 0.5);
    if ( (x-0.5) == double(i) && i & 1) i++;
  }

  return i;
}

#endif 
