/***************************************************************************
 *
 * $Id: StHbtTrack.cc,v 1.19 2005/07/15 17:41:43 kopytin Exp $
 *
 * Author: Frank Laue, Ohio State, laue@mps.ohio-state.edu
 ***************************************************************************
 *
 * Description: part of STAR HBT Framework: StHbtMaker package
 * Implementation of methods
 *
 ***************************************************************************
 * $Log: StHbtTrack.cc,v $
 * Revision 1.19  2005/07/15 17:41:43  kopytin
 * initialized mHiddenInfo in StHbtTrack() to null
 *
 * Revision 1.18  2005/07/10 02:17:21  chajecki
 * Ftpc (Eeat+West) hits included in nHits()
 *
 * Revision 1.17  2005/06/17 21:41:12  chajecki
 * Two bugs fixed:
 * 1. wrong value of mNHits set in one of the constructors
 * StHbtTrack::StHbtTrack(const StTrack* ST, StHbtThreeVector PrimaryVertex)
 *
 * 2. since year 4 the StMuTrack::nHits() returns the total number of hits.
 * We're interested in TPC hits only so this value can be taken by
 *  StMuTrack::topologyMap().numberOfHits(kTpcId);
 * This change is backwards compatible so the code should work also
 * for data <=Y3
 *
 * Revision 1.16  2003/03/18 14:41:48  kisiel
 * Bugfix update for the theoretical part of the code. Reverts the changes to the Lednicky weight calculator, as the previuos one had problems with strong interaction
 *
 * Revision 1.15  2003/01/31 19:57:15  magestro
 * Cleared up simple compiler warnings on i386_linux24
 *
 * Revision 1.14  2003/01/21 17:26:33  magestro
 * Added condition to globalTrack() call so GlobalTracks branch in MuDst can be disabled
 *
 * Revision 1.13  2002/03/21 18:49:31  laue
 * updated for new MuDst reader
 *
 * Revision 1.12  2002/02/04 18:58:33  laue
 * *** empty log message ***
 *
 * Revision 1.11  2001/12/14 23:11:30  fretiere
 * Add class HitMergingCut. Add class fabricesPairCut = HitMerginCut + pair purity cuts. Add TpcLocalTransform function which convert to local tpc coord (not pretty). Modify StHbtTrack, StHbtParticle, StHbtHiddenInfo, StHbtPair to handle the hit information and cope with my code
 *
 * Revision 1.4  2001/06/21 19:15:48  laue
 * Modified fiels:
 *   CTH.hh : new constructor added
 *   StHbtEvent, StHbtKink, StHbtTrack : constructors from the persistent
 *                                   (TTree) classes added
 *   StHbtLikeSignAnalysis : minor changes, for debugging
 *   StHbtTypes: split into different files
 * Added files: for the new TTree muDst's
 *   StExceptions.cxx StExceptions.hh StHbtEnumeration.hh
 *   StHbtHelix.hh StHbtHisto.hh StHbtString.hh StHbtTFile.hh
 *   StHbtTTreeEvent.cxx StHbtTTreeEvent.h StHbtTTreeKink.cxx
 *   StHbtTTreeKink.h StHbtTTreeTrack.cxx StHbtTTreeTrack.h
 *   StHbtTTreeV0.cxx StHbtTTreeV0.h StHbtVector.hh
 *
 * Revision 1.3  2001/05/25 23:23:59  lisa
 * Added in StHbtKink stuff
 *
 *
 ****************************************************************************/

#include "StHbtMaker/Infrastructure/StHbtTrack.hh" 
#ifdef __ROOT__
#include "StHbtMaker/Infrastructure/StHbtTTreeEvent.h" 
#include "StHbtMaker/Infrastructure/StHbtTTreeTrack.h" 
#include "StEvent/StEnumerations.h"
#include "StHbtMaker/Infrastructure/StHbtAihongPid.h"
#include "StEventUtilities/StuProbabilityPidAlgorithm.h"
#endif

//________________
StHbtTrack::StHbtTrack() {
  mNHits = 0;    //Protection from the wrong charge assigning by default
  mP = StHbtThreeVector(0., 0., 0.);  //Make track global by default
  mHiddenInfo = NULL;
}

//________________
StHbtTrack::StHbtTrack(const StHbtTrack& t) { // copy constructor

  mTrackId = t.mTrackId;
  mFlag = t.mFlag;     
  mNHits = t.mNHits;
  //mNHitsFit = t.mNHitsFit;
  mNHitsPoss = t.mNHitsPoss;
  mNHitsDedx = t.mNHitsDedx;
  mNSigmaElectron = t.mNSigmaElectron;
  mNSigmaPion = t.mNSigmaPion;
  mNSigmaKaon = t.mNSigmaKaon;
  mNSigmaProton = t.mNSigmaProton;
  mPidProbElectron = t.mPidProbElectron;
  mPidProbPion = t.mPidProbPion;
  mPidProbKaon = t.mPidProbKaon;
  mPidProbProton = t.mPidProbProton;
  mdEdx = t.mdEdx;
  //mDCAxy = t.mDCAxy;
  //mDCAz = t.mDCAz; 
  mDCAxyGlobal = t.mDCAxyGlobal;
  mDCAzGlobal = t.mDCAzGlobal; 
  mChiSq = t.mChiSq;
  mP = t.mP;
  mPGlobal = t.mPGlobal;
  mHelix = t.mHelix;
  mHelixGlobal = t.mHelixGlobal;
  mMap[0] = t.mMap[0];
  mMap[1] = t.mMap[1];

#ifdef TPC_DNDX
  mdNdx = t.mdNdx;
  mDndxNSigmaElectron = t.mDndxNSigmaElectron;
  mDndxNSigmaPion = t.mDndxNSigmaPion;
  mDndxNSigmaKaon = t.mDndxNSigmaKaon;
  mDndxNSigmaProton = t.mDndxNSigmaProton;
#endif

  mTofBeta = t.mTofBeta;
  //mXfr = t.mXfr;
  //mYfr = t.mYfr;
  //mZfr = t.mZfr;
  //mTfr = t.mTfr;

  if (t.ValidHiddenInfo())
    mHiddenInfo = t.getHiddenInfo()->clone();
  else 
    mHiddenInfo = NULL;
};

//_________________
StHbtTrack::~StHbtTrack() {
  if(mHiddenInfo) {
    delete mHiddenInfo;
  }
}

//_________________
StHbtThreeVector StHbtTrack::P() const {

  if( TrackType() == 0 ) { //Global track
    return PGlobal();
  }
  else  { //Primary track
    return mP;
  }
}

//_________________
float StHbtTrack::Pt() const {
  if( TrackType() == 0 ) { //Global track
    return PtGlobal();
  }
  else  { //Primary track
    return mP.perp();
  }
}

//_________________
float StHbtTrack::Ptot() const {
  if( TrackType() == 0 ) { //Global track
    return PtotGlobal();
  }
  else  { //Primary track
    return mP.mag();
  }
}

//_________________
float StHbtTrack::Ptot2() const {
  if( TrackType() == 0 ) { //Global track
    return Ptot2Global();
  }
  else  { //Primary track
    return mP.mag2();
  }
}

//_________________
short StHbtTrack::NHitsFit() const {
  if( TrackType() == 0 ) { //Global track
    return (short) abs(mNHits);
  }
  else { //Primary track
    return ((short) abs(mNHits))+1;
  }
}

//_________________
short StHbtTrack::Charge() const {

  if(mNHits > 0) {
    return 1;
  }
  else if (mNHits < 0) {
    return -1;
  }
  else {
    return 0;
  }
}

//_________________
float StHbtTrack::TofMassSqr() const {
  float massSqr = -999.;
  if(mTofBeta > 0) {
    massSqr = mP.mag2() * (1./(mTofBeta*mTofBeta) - 1.);
  }
  return massSqr;
}

//________________
#ifdef __ROOT__
#include "StEventTypes.h"
#include "StEvent/StTpcDedxPidAlgorithm.h"
#include "StEventUtilities/StuRefMult.hh"
#include "StEvent/StEnumerations.h"
#include "StarClassLibrary/SystemOfUnits.h"   // has "tesla" in it
#include "StarClassLibrary/StParticleTypes.hh"

//________________
#include "StMuDSTMaker/COMMON/StMuDst.h"
#include "StMuDSTMaker/COMMON/StMuEvent.h"
#include "StMuDSTMaker/COMMON/StMuTrack.h"
#ifdef TPC_DNDX
#include "StBichsel/StdEdxModel.h"
#include "StMuDSTMaker/COMMON/StMuProbPidTraits.h"
#endif
StHbtTrack::StHbtTrack(const StMuDst* dst, const StMuTrack* t) {

  //added by gnigmat
#ifdef STHBTDEBUG
  std::cout << "StHbtTrack(const StMuDst* dst, const StMuTrack* t) -- copy track"
            << std::endl;
#endif

  StMuEvent* ev = dst->event();
  //mTrackType = t->type();   //0-global, 1-primary
  mTrackId = (unsigned short)t->id();
  mFlag = t->flag();
  if(t->charge() > 0) {
    mNHits = (char)( t->topologyMap().numberOfHits(kTpcId) + 
                     t->topologyMap().numberOfHits(kFtpcEastId) + 
                     t->topologyMap().numberOfHits(kFtpcWestId) );
  }
  else {
    mNHits = (-1)*(char)( t->topologyMap().numberOfHits(kTpcId) + 
                          t->topologyMap().numberOfHits(kFtpcEastId) + 
                          t->topologyMap().numberOfHits(kFtpcWestId) );
  }
  //mNHitsFit = (unsigned char)t->nHitsFit();
  mNHitsPoss = (unsigned char)t->nHitsPoss(); 
  mNHitsDedx = (unsigned char)t->nHitsDedx();

  mNSigmaElectron = (fabs(t->nSigmaElectron() * 100.) > std::numeric_limits<short>::max()) ? std::numeric_limits<short>::max() : (short)(GregsNint(t->nSigmaElectron() * 100.));
  mNSigmaPion = (fabs(t->nSigmaPion() * 100.) > std::numeric_limits<short>::max()) ? std::numeric_limits<short>::max() : (short)(GregsNint(t->nSigmaPion() * 100.));
  mNSigmaKaon = (fabs(t->nSigmaKaon() * 100.) > std::numeric_limits<short>::max()) ? std::numeric_limits<short>::max() : (short)(GregsNint(t->nSigmaKaon() * 100.));
  mNSigmaProton = (fabs(t->nSigmaProton() * 100.) > std::numeric_limits<short>::max()) ? std::numeric_limits<short>::max() : (short)(GregsNint(t->nSigmaProton() * 100.));

#ifdef TPC_DNDX
  double bg[4];
  float mDndxPred[4];
  //In principle, particle masses should be taken from StarClassLibrary
  double Masses[4] = {0.93827231, 0.13956995, 0.493677, 0.51099907e-3};
  double mDndxZ[4];
  double mdNdxLocal;
  mdNdxLocal = t->probPidTraits().dNdxFit();
  for(int iHypo = 0; iHypo < 4; iHypo++) {
    bg[iHypo] = ::abs(t->charge()) * t->p().mag() / Masses[iHypo];
    mDndxPred[iHypo] = StdEdxModel::instance()->dNdx(bg[iHypo]);
    mDndxZ[iHypo] = ::log( mdNdxLocal / mDndxPred[iHypo]);
  } //for(int iHypo = 0; iHypo < 4; iHypo++)

  float nsE, nsPi, nsK, nsP;
  nsE =  float( mDndxZ[3] / t->probPidTraits().dEdxErrorFit() ); 
  nsPi = float( mDndxZ[1] / t->probPidTraits().dEdxErrorFit() ); 
  nsK =  float( mDndxZ[2] / t->probPidTraits().dEdxErrorFit() ); 
  nsP =  float( mDndxZ[0] / t->probPidTraits().dEdxErrorFit() ); 

  mdNdx = float(mdNdxLocal * 1e6);
  mDndxNSigmaElectron = (fabs(nsE * 100.f) > std::numeric_limits<short>::max()) ? std::numeric_limits<short>::max() : (short)(GregsNint(nsE * 100.f));
  mDndxNSigmaPion = (fabs(nsPi * 100.f) > std::numeric_limits<short>::max()) ? std::numeric_limits<short>::max() : (short)(GregsNint(nsPi * 100.f));
  mDndxNSigmaKaon = (fabs(nsK * 100.f) > std::numeric_limits<short>::max()) ? std::numeric_limits<short>::max() : (short)(GregsNint(nsK * 100.f));
  mDndxNSigmaProton = (fabs(nsP * 100.f) > std::numeric_limits<short>::max()) ? std::numeric_limits<short>::max() : (short)(GregsNint(nsP * 100.f));
#endif

  mPidProbElectron = t->pidProbElectron();
  mPidProbPion = t->pidProbPion();
  mPidProbKaon = t->pidProbKaon();
  mPidProbProton = t->pidProbProton();
  mdEdx = float(t->dEdx() * 1e6);

  mChiSq = ( ( t->chi2xy() * 1000.f) > std::numeric_limits<unsigned short>::max()) ? std::numeric_limits<unsigned short>::max() : (unsigned short)( GregsNint( t->chi2xy() * 1000.f) );
  mMap[0] = t->topologyMap().data(0);
  mMap[1] = t->topologyMap().data(1);

  //Primary helix for primatry track and global helix for the global track
  mHelix = t->helix(); 
  if(t->type() == 0) { //Global track

    mP = StHbtThreeVector(0., 0., 0.); //This will keep the trackType
    mHelixGlobal = t->helix();

    double pathlengthGlobal = mHelixGlobal.pathLength(ev->primaryVertexPosition());
    mPGlobal = mHelixGlobal.momentumAt(pathlengthGlobal,ev->magneticField()*kilogauss);
    StThreeVectorD dcaGlobal(mHelixGlobal.at(pathlengthGlobal) - ev->primaryVertexPosition());
    mDCAxyGlobal = dcaGlobal.perp();
    mDCAzGlobal =  dcaGlobal.z();
  }
  else { //Primary track

    double pathlength = mHelix.pathLength(ev->primaryVertexPosition());
    mP = mHelix.momentumAt(pathlength,ev->magneticField()*kilogauss);

    //Return the pointer to the global track assosiated with the primary
    if(t->globalTrack()) { 
      mHelixGlobal = t->globalTrack()->helix();
      double pathlengthGlobal = mHelixGlobal.pathLength(ev->primaryVertexPosition());
      mPGlobal = mHelixGlobal.momentumAt(pathlengthGlobal,ev->magneticField()*kilogauss);
      StThreeVectorD dcaGlobal(mHelixGlobal.at(pathlengthGlobal) - ev->primaryVertexPosition());
      mDCAxyGlobal = dcaGlobal.perp();
      mDCAzGlobal =  dcaGlobal.z();
    }
  }
 
  //Time-of-Flight information
  mTofBeta = -999.;

  if( (t->type() == 0) && (t->btofPidTraits().beta() > 0) ) { //global
    mTofBeta = t->btofPidTraits().beta();
  }

  if(t->type() == 1) { //primary
    StMuTrack* mGlobTrack = dst->globalTracks(t->index2Global());
    if(mGlobTrack->btofPidTraits().beta() > 0) {
      mTofBeta = mGlobTrack->btofPidTraits().beta();
    }
  }

//    cout << "*******************" << endl;
//    cout << " vertex " << ev->primaryVertexPosition() << endl;
//    cout << " helix " << mHelix << endl;
//    cout << " helix " << mHelixGlobal << endl;
//    cout << " p " << mP << " pmag " << mP.mag() << "     " << t->p() << endl;
//    cout << " p " << mPGlobal << " pmag " << mPGlobal.mag() << endl;
//    cout << " l " << pathlength << " dca " << dca << " dcamag " << dca.mag() << endl;
//    cout << " l " << pathlengthGlobal << " dca " << dcaGlobal << " dcamag " << dcaGlobal.mag() << endl;
  
  mHiddenInfo = 0;

  //
  // added by nik
  //
  //mXfr = 0.;
  //mYfr = 0.;
  //mZfr = 0.;
  //mTfr = 0.;
};

//_________________
short StHbtTrack::TrackType() const {

  if(mP.magnitude() > 0) {
    return 1;  //Primary tracks
  }
  else {
    return 0;  //Global tracks
  }
}

//_________________
float StHbtTrack::DCAxy() const {

  if( TrackType() == 1) {
    return 0.;
  }
  else {
    return mDCAxyGlobal;
  }
}

//_________________
float StHbtTrack::DCAz() const {

  if( TrackType() == 1) {
    return 0.;
  }
  else {
    return mDCAzGlobal;
  }
}

//_________________
void StHbtTrack::SetNSigmaElectron(const float& ns) {

  mNSigmaElectron = (fabs(ns * 100.f) > std::numeric_limits<short>::max()) ? std::numeric_limits<short>::max() : (short)(GregsNint(ns * 100.f));
}

//_________________
void StHbtTrack::SetNSigmaElectron(const double& ns) {

  mNSigmaElectron = (fabs(ns * 100.) > std::numeric_limits<short>::max()) ? std::numeric_limits<short>::max() : (short)(GregsNint(ns * 100.));
}

//_________________
void StHbtTrack::SetNSigmaPion(const float& ns) {

  mNSigmaPion = (fabs(ns * 100.) > std::numeric_limits<short>::max()) ? std::numeric_limits<short>::max() : (short)(GregsNint(ns * 100.));
}

//_________________
void StHbtTrack::SetNSigmaPion(const double& ns) {

  mNSigmaPion = (fabs(ns * 100.) > std::numeric_limits<short>::max()) ? std::numeric_limits<short>::max() : (short)(GregsNint(ns * 100.));
}

//_________________
void StHbtTrack::SetNSigmaKaon(const float& ns) {

  mNSigmaKaon = (fabs(ns * 100.f) > std::numeric_limits<short>::max()) ? std::numeric_limits<short>::max() : (short)(GregsNint(ns * 100.f));
}

//_________________
void StHbtTrack::SetNSigmaKaon(const double& ns) {

  mNSigmaKaon = (fabs(ns * 100.) > std::numeric_limits<short>::max()) ? std::numeric_limits<short>::max() : (short)(GregsNint(ns * 100.));
}

//_________________
void StHbtTrack::SetNSigmaProton(const float& ns) {

  mNSigmaProton = (fabs(ns * 100.f) > std::numeric_limits<short>::max()) ? std::numeric_limits<short>::max() : (short)(GregsNint(ns * 100.f));
}

//_________________
void StHbtTrack::SetNSigmaProton(const double& ns) {

  mNSigmaProton = (fabs(ns * 100.) > std::numeric_limits<short>::max()) ? std::numeric_limits<short>::max() : (short)(GregsNint(ns * 100.));
}

//_________________
void StHbtTrack::SetChi2(const float& x) {

  mChiSq = ( ( x * 1000.f) > std::numeric_limits<unsigned short>::max()) ? std::numeric_limits<unsigned short>::max() : (unsigned short)( GregsNint( x * 1000.f) );
}

//_________________
void StHbtTrack::SetChi2(const double& x) {

  mChiSq = ( (x * 1000.) > std::numeric_limits<unsigned short>::max()) ? std::numeric_limits<unsigned short>::max() : (unsigned short)( GregsNint(x * 1000.) );
}

//_________________
float StHbtTrack::NHitsFit2PossRatio() const {

  if(mNHitsPoss > 0) {
    return (float)NHitsFit()/(float)mNHitsPoss;
  }
  else {
    return 0.f;
  }
}

//_________________
int StHbtTrack::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 StHbtTrack::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;
}

#ifdef TPC_DNDX
//_________________
void StHbtTrack::SetDndxNSigmaElectron(const float& ns) {

  mDndxNSigmaElectron = (fabs(ns * 100.f) > std::numeric_limits<short>::max()) ? std::numeric_limits<short>::max() : (short)(GregsNint(ns * 100.f));
}

//_________________
void StHbtTrack::SetDndxNSigmaElectron(const double& ns) {

  mDndxNSigmaElectron = (fabs(ns * 100.) > std::numeric_limits<short>::max()) ? std::numeric_limits<short>::max() : (short)(GregsNint(ns * 100.));
}

//_________________
void StHbtTrack::SetDndxNSigmaPion(const float& ns) {

  mDndxNSigmaPion = (fabs(ns * 100.) > std::numeric_limits<short>::max()) ? std::numeric_limits<short>::max() : (short)(GregsNint(ns * 100.));
}

//_________________
void StHbtTrack::SetDndxNSigmaPion(const double& ns) {

  mDndxNSigmaPion = (fabs(ns * 100.) > std::numeric_limits<short>::max()) ? std::numeric_limits<short>::max() : (short)(GregsNint(ns * 100.));
}

//_________________
void StHbtTrack::SetDndxNSigmaKaon(const float& ns) {

  mDndxNSigmaKaon = (fabs(ns * 100.f) > std::numeric_limits<short>::max()) ? 
    std::numeric_limits<short>::max() : (short)(GregsNint(ns * 100.f));
}

//_________________
void StHbtTrack::SetDndxNSigmaKaon(const double& ns) {

  mDndxNSigmaKaon = (fabs(ns * 100.) > std::numeric_limits<short>::max()) ? 
    std::numeric_limits<short>::max() : (short)(GregsNint(ns * 100.));
}

//_________________
void StHbtTrack::SetDndxNSigmaProton(const float& ns) {

  mDndxNSigmaProton = (fabs(ns * 100.f) > std::numeric_limits<short>::max()) ? 
    std::numeric_limits<short>::max() : (short)(GregsNint(ns * 100.f));
}

//_________________
void StHbtTrack::SetDndxNSigmaProton(const double& ns) {

  mDndxNSigmaProton = (fabs(ns * 100.) > std::numeric_limits<short>::max()) ? 
    std::numeric_limits<short>::max() : (short)(GregsNint(ns * 100.));
}

#endif

#endif
