/***************************************************************************
 *  StHbtTrack:
 *  06/29/2017   gnigmat
 *    mCharge is incoded in mNHits: mNHits = mNHits * mCharge
 *    New dN/dx algorythim is added. To use it one first needs
 *    to uncomment #define TPC_DNDX
 *
 **************************************************************************/

#ifndef StHbtTrack_hh
#define StHbtTrack_hh

#include <cmath>
#include <limits>

#include "Stiostream.h"
#include "StHbtMaker/Infrastructure/StHbtTypes.hh"
#include "StPhysicalHelixD.hh"
/* Th stuff */
#include "StHbtMaker/Base/StHbtHiddenInfo.hh"
/***/

class StEvent;
class StTrack;
class StHbtTTreeTrack;
class StHbtTTreeEvent;
class StMuDst;
class StMuTrack;

//#define TPC_DNDX

//_________________
class StHbtTrack{

 public:
  StHbtTrack();
  StHbtTrack(const StHbtTrack&);         // copy constructor
#ifdef __ROOT__
  StHbtTrack(const StTrack*, StHbtThreeVector);   // c-tor from StTrack of STAR DSTs
  StHbtTrack(const StHbtTTreeEvent* ev, const StHbtTTreeTrack* t);
  StHbtTrack(const StMuDst* dst, const StMuTrack* t);  //c-tor from StMuTrack of StMuDST
#endif
  StHbtTrack(const StEvent*, const StTrack*);
  ~StHbtTrack();

  int GregsNint(float x);   //My copy of ROOT::TMath::Nint(float)
  int GregsNint(double x);  //My copy of ROOT::TMath::Nint(double)

  ///////////////
  //  Getters  //
  ///////////////
  short TrackId() const   {return (short)mTrackId;}
  short TrackType() const;
  short Charge() const;
  short Flag() const      {return mFlag;}
  short NHits() const     {return (short)::fabs(mNHits);}
  short NHitsFit() const; 
  short NHitsPossible() const  {return (short)mNHitsPoss;}
  short NHitsDedx() const      {return (short)mNHitsDedx;}
  float NHitsFit2PossRatio() const;
  float NSigmaElectron() const {return (float)mNSigmaElectron * 0.01f;}
  float NSigmaPion() const     {return (float)mNSigmaPion * 0.01f;}
  float NSigmaKaon() const     {return (float)mNSigmaKaon * 0.01f;}
  float NSigmaProton() const   {return (float)mNSigmaProton * 0.01f;}
#ifdef TPC_DNDX
  double dNdx() const              {return (double)mdNdx * 1e-6;}
  float DndxNSigmaElectron() const {return (float)mDndxNSigmaElectron * 0.01f;}
  float DndxNSigmaPion() const     {return (float)mDndxNSigmaPion * 0.01f;}
  float DndxNSigmaKaon() const     {return (float)mDndxNSigmaKaon * 0.01f;}
  float DndxNSigmaProton() const   {return (float)mDndxNSigmaProton * 0.01f;}
#endif
  float PidProbElectron() const  {return (float)mPidProbElectron * 0.001f;}
  float PidProbPion() const      {return (float)mPidProbPion * 0.001f;}
  float PidProbKaon() const      {return (float)mPidProbKaon * 0.001f;}
  float PidProbProton() const    {return (float)mPidProbProton * 0.001f;}
  double dEdx() const            {return (double)mdEdx * 1e-6;}
  float Eta() const              {return mP.pseudoRapidity();}
  float PseudoRapidity() const   {return mP.pseudoRapidity();}
  float Phi() const              {return mP.phi();}
  float Theta() const            {return mP.theta();}
  float EtaGlobal() const        {return mPGlobal.pseudoRapidity();}
  float PseudoRapidityGlobal() const {return mPGlobal.pseudoRapidity();}
  float PhiGlobal() const        {return mPGlobal.phi();}
  float ThetaGlobal() const      {return mPGlobal.theta();}
  float DCAz() const;
  float DCAxy() const;
  float DCAzGlobal() const  {return mDCAzGlobal;}
  float DCAxyGlobal() const {return mDCAxyGlobal;}
  float Chi2() const        {return (float)mChiSq * 0.001f;}  //According to PicoDst
  StHbtThreeVector P() const;
  float Pt() const;
  float Ptot() const;
  float Ptot2() const;
  StHbtThreeVector PGlobal() const {return mPGlobal;}
  float PtGlobal() const           {return mPGlobal.perp();}
  float PtotGlobal() const         {return mPGlobal.mag();}
  float Ptot2Global() const         {return mPGlobal.mag2();}
  const StPhysicalHelixD& Helix() const   {return mHelix;}
  const StPhysicalHelixD& HelixGlobal() const {return mHelixGlobal;}
  unsigned int TopologyMap(const unsigned int word) const {return mMap[word];}

  //Time-of-Flight information
  float TofBeta() const {return mTofBeta;}
  float TofMassSqr() const;
  //Return particle parameters at freeze-out (for simulation only)
  //float FreezeOutX() const {return mXfr;}
  //float FreezeOutY() const {return mYfr;}
  //float FreezeOutZ() const {return mZfr;}
  //float FreezeOutT() const {return mTfr;}
  
  ///////////////
  //  Setters  //
  ///////////////
  void SetTrackId(const short& id) {mTrackId = (unsigned short)id;}
  //void SetTrackType(const short& t) {mTrackType = t;}   //Now we keep the type in mP
  void SetFlag(const short& fl)          {mFlag = (short)fl;}            
  void SetNHits(const short& nh)         {mNHits = (char)nh;}  //Has to be charge*nHits
  //void SetNHitsFit(const short& nh)      { /* tmp */ }
  //void SetNHitsFit(const short& nh)      {mNHitsFit = (unsigned char)nh;}
  void SetNHitsPossible(const short& nh) {mNHitsPoss = (unsigned char)nh;}
  void SetNHitsDedx(const short& nh)     {mNHitsDedx = (unsigned char)nh;}

  void SetNSigmaElectron(const float& ns);
  void SetNSigmaPion(const float& ns);
  void SetNSigmaKaon(const float& ns);
  void SetNSigmaProton(const float& ns);
  void SetNSigmaElectron(const double& ns);
  void SetNSigmaPion(const double& ns);
  void SetNSigmaKaon(const double& ns);
  void SetNSigmaProton(const double& ns);

#ifdef TPC_DNDX
  void SetDndx(const float& dndx);
  void SetDndx(const double& dndx);
  void SetDndxNSigmaElectron(const float& ns);
  void SetDndxNSigmaElectron(const double& ns);
  void SetDndxNSigmaPion(const float& ns);
  void SetDndxNSigmaPion(const double& ns);
  void SetDndxNSigmaKaon(const float& ns);
  void SetDndxNSigmaKaon(const double& ns);
  void SetDndxNSigmaProton(const float& ns);
  void SetDndxNSigmaProton(const double& ns);
#endif
  void SetPidProbElectron(const float& p) {/* */}
  void SetPidProbPion(const float& p)     {/* */}
  void SetPidProbKaon(const float& p)     {/* */}
  void SetPidProbProton(const float& p)   {/* */}
  void SetdEdx(const float& x)    {mdEdx = x;}
  void SetDCAxyGlobal(const float& x) {mDCAxyGlobal = x;}
  void SetDCAzGlobal(const float& x)  {mDCAzGlobal = x;}
  void SetChi2(const float& x);           //According to PicoDst
  void SetChi2(const double& x);          //According to PicoDst
  void SetP(const StHbtThreeVector& p)       {mP = p;}
  void SetPGlobal(const StHbtThreeVector& p) {mPGlobal = p;}
  void SetHelix(const StPhysicalHelixD& h)       {mHelix = h;}
  void SetHelixGlobal(const StPhysicalHelixD& h) {mHelixGlobal = h;}
  void SetTopologyMap(const int word, const unsigned int map) {mMap[word] = map;}

  //ToF beta
  void SetTofBeta(const float &t) {mTofBeta = t;}
  //Freeze-out parameters (for the simulation only)
  //void SetFreezeOutX(const float &x) {mXfr = x;}
  //void SetFreezeOutY(const float &y) {mYfr = y;}
  //void SetFreezeOutZ(const float &z) {mZfr = z;}
  //void SetFreezeOutT(const float &t) {mTfr = t;}

  /* Th stuff */
  void SetHiddenInfo(StHbtHiddenInfo* aHiddenInfo) {mHiddenInfo = aHiddenInfo;}
  bool ValidHiddenInfo() const { if(mHiddenInfo) {return true;} else {return false;} }
  StHbtHiddenInfo* getHiddenInfo() const {return mHiddenInfo;}
  /***/

  // For I/O of this object -- functions defined in StHbtIO.cc
  friend ostream& operator<<(ostream& out, StHbtTrack& trk);
  friend istream& operator>>(istream& in,  StHbtTrack& trk);

private:

  unsigned short mTrackId;   //There should not be more than 65535 tracks in the event
  //short mTrackType;        //0-global track, 1-primary track
  short mFlag;               //if flag<0 then this is a bad track. The definition comes from StEvent
  char mNHits;               //nHits*charge
  unsigned char mNHitsPoss;  
  unsigned char mNHitsDedx;
  //unsigned char mNHitsFit;   //if(global) {nHitsFit=nHits} if(primary) {nHitsFit=nHits+1}

  short mNSigmaElectron;       //nsigmaE * 100
  short mNSigmaPion;           //nsigmaPi * 100
  short mNSigmaKaon;           //nsimgaK * 100
  short mNSigmaProton;         //nsigmaP * 100
  unsigned short mPidProbElectron;   //prob * 1000; However, we are not using it
  unsigned short mPidProbPion;       //prob * 1000; However, we are not using it
  unsigned short mPidProbKaon;       //prob * 1000; However, we are not using it
  unsigned short mPidProbProton;     //prob * 1000; However, we are not using it
  float mdEdx;               //dE/dx in KeV/cm, i.e. MuTrack->dEdx() * 1e6
  float mDCAxyGlobal;
  float mDCAzGlobal; 

  unsigned short mChiSq;     //Following the StPicoDst: mChiSq = mChi2.xy
  unsigned int mMap[2];

#ifdef TPC_DNDX
  float mdNdx;                //dN/dx in KeV/cm, i.e. dN/dx() * 1e6;
  short mDndxNSigmaElectron;  //nsigmaE * 100
  short mDndxNSigmaPion;      //nsigmaPi * 100
  short mDndxNSigmaKaon;      //nsigmaK * 100
  short mDndxNSigmaProton;    //nsigmaP * 100
#endif

  //Time-of-Flight information
  float mTofBeta;

  StHbtThreeVector mP;
  StHbtThreeVector mPGlobal;
  StPhysicalHelixD mHelix;
  StPhysicalHelixD mHelixGlobal;

  //Particle positions at freeze-out (for MC only)
  //float mXfr;
  //float mYfr;
  //float mZfr;
  //float mTfr;

  /* Th stuff */
  // Fab private : add mutable
  StHbtHiddenInfo* mHiddenInfo; //!
  /***/

  friend class StHbtIOBinary;
  friend class StHbtTTreeEvent;
  friend class StHbtTTreeTrack;
};

#endif
