#ifndef PAMVMC_DETECTOR_HIT_H
#define PAMVMC_DETECTOR_HIT_H
#include <cmath>
#include <iostream>

#include <TObject.h>
#include <TVirtualMC.h>
#include <TParticle.h>

#include "PamVMCGeoID.h"

using std::sqrt;
using std::cout;
using std::endl;

class pHitData: public TObject {

public:
  Int_t    fPOS;
  Int_t    fPDG;    //Particle PDG
  Double_t fPATH;   //PATH length in specific SD in (cm)
  Double_t fTOF;
  Double_t fPIN;
  Double_t fXOUT;
  Double_t fYOUT;
  Double_t fZOUT;
  Double_t fEREL;   //Energy released during hit
  Double_t fXIN;    
  Double_t fYIN;
  Double_t fZIN;
  Bool_t   fPRIM; //1 if it was a hit from primary particle

  pHitData():  fPOS(0), fPDG(0), fPATH(0.), fTOF(0.), fPIN(0.), fXOUT (0.), 
    fYOUT (0.),  fZOUT (0.), fEREL (0.),
    fXIN(0.),  fYIN (0.), fZIN (0.), fPRIM(kFALSE) { };


  // Kept for back-compatibility
  virtual void Clean() {
    fPOS=fPDG=0;
    fPATH= fTOF= fPIN= fXOUT = 
      fYOUT =  fZOUT = fEREL = 
      fXIN=  fYIN = fZIN = 0.;
    fPRIM = kFALSE;
  }

  // Inherithed from TObject

  virtual void Clear( Option_t * = "") { Clean(); }

  virtual void Print(Option_t * ="" ) const
  { cout << "pHitData: "<<endl
         <<"ID of SD volume: " << fPOS << endl
         <<"HIT INFORMATION: " << endl
	 <<"Partice PDG: " << fPDG << endl
         <<"XIN: " << fXIN << " (cm)"<<endl
         <<"YIN: " << fYIN << " (cm)"<<endl
         <<"ZIN: " << fZIN << " (cm)"<<endl
         <<"PIN: " << fPIN << " (GeV/c)"<<endl
         <<"XOUT: " << fXOUT << " (cm)"<<endl
         <<"YOUT: " << fYOUT << " (cm)"<<endl
         <<"ZOUT: " << fZOUT << " (cm)"<<endl
         <<"PATH: " << fPATH << " (cm)"<<endl
         <<"EREL: " << fEREL*1E6 << " (keV)"<<endl
         <<"TOF: " << fTOF << " (s)"<<endl
	 <<"PRIMARY: "<<fPRIM<<endl; } 
  
  ClassDef(pHitData,1)

};


pHitData & operator+=( pHitData &a, const pHitData & p); 


class PamVMCDetectorHit : public TObject
{
  public:
    PamVMCDetectorHit();
    virtual ~PamVMCDetectorHit();

    //Set and Add methods

    virtual void CleanHit() {
       fhitdata.Clean();
       fnocall=0;
    }
    
    virtual void Clear(Option_t * = ""){ this->~PamVMCDetectorHit();   }

    virtual pHitData * GenHit() { return new pHitData(fhitdata);}

    void operator =  (const PamVMCDetectorHit & p );

    void operator += (const PamVMCDetectorHit & p );

    virtual void FillHitEntering(pHitData &phd){ 
      SetHit(phd); }

    virtual void Print(Option_t* option = "") const;

    void FillHit(TVirtualMC *g, Bool_t is_prim) {
      fnocall++;
      double x,y,z,e;
      g->TrackPosition(x,y,z);
      UpdPDG(g->TrackPid());
      UpdXIN(x);
      UpdYIN(y);
      UpdZIN(z);
      SetXOUT(x);
      SetYOUT(y);
      SetZOUT(z);
      g->TrackMomentum(x,y,z,e);
      UpdPIN(sqrt(x*x+y*y+z*z));
      AddTOF((g->GetStack()->GetCurrentTrack()->T())/1.0E9 /*TG4G3Units::Time()*/+(g->TrackTime()));
      AddPATH(g->TrackStep());
      AddEREL(g->Edep());
      SetPRIM(is_prim);
    }    
  

  void SetHit( const pHitData &phd){ 
      fnocall++; 
      SetPOS(phd.fPOS);
      AddTOF(phd.fTOF); 
      AddPATH( phd.fPATH );  
      AddEREL( phd.fEREL );
      UpdPDG( phd.fPDG );
      UpdXIN( phd.fXIN );
      UpdYIN( phd.fYIN );
      UpdZIN( phd.fZIN );
      UpdPIN( phd.fPIN );
      SetXOUT( phd.fXOUT );
      SetYOUT( phd.fYOUT );
      SetZOUT( phd.fZOUT );
      SetPRIM( phd.fPRIM );
    }

    void UpdXIN(Double_t x){ 
      if(! fhitdata.fXIN) SetXIN( x );}
    void UpdYIN(Double_t x){ 
      if(! fhitdata.fYIN) SetYIN( x );}
    void UpdZIN(Double_t x){ 
      if(! fhitdata.fZIN) SetZIN( x );}
    void UpdPIN(Double_t x){ 
      if(! fhitdata.fPIN) SetPIN( x );}
    void UpdPDG(Int_t x){ 
      if(! fhitdata.fPDG) SetPDG( x );}
    void SetPOS    (Int_t pos)      { fhitdata.fPOS = pos; }    
    void SetPDG    (Int_t pdg)      { fhitdata.fPDG = pdg; }
    void AddPATH   (Double_t ln)    { fhitdata.fPATH += ln; }  
    void AddEREL   (Double_t de)    { fhitdata.fEREL += de; }
    void SetXIN    (Double_t xin)   { fhitdata.fXIN = xin; }
    void SetYIN    (Double_t yin)   { fhitdata.fYIN = yin; }
    void SetZIN    (Double_t zin)   { fhitdata.fZIN = zin; }
    void SetTOF    (Double_t tofin) { fhitdata.fTOF = tofin; }
    void SetPIN    (Double_t pxin)  { fhitdata.fPIN = pxin; }
    void SetXOUT   (Double_t xout)  { fhitdata.fXOUT = xout; }
    void SetYOUT   (Double_t yout)  { fhitdata.fYOUT = yout; }
    void SetZOUT   (Double_t zout)  { fhitdata.fZOUT = zout; }
    void SetPRIM   (Bool_t prim)    { fhitdata.fPRIM = prim; }
    void Reset(); 
                 
    // Get methods

    const pHitData *GetHit() {return &fhitdata;}
    Int_t    GetPOS()      { return fhitdata.fPOS; };
    Int_t    GetPDG()      { return fhitdata.fPDG; };
    Double_t GetPATH()     { return fhitdata.fPATH; };
    Double_t GetEREL()     { return fhitdata.fEREL; };
    Double_t GetXIN()      { return fhitdata.fXIN;  };
    Double_t GetYIN()      { return fhitdata.fYIN; };
    Double_t GetZIN()      { return fhitdata.fZIN; };
    Double_t GetTOF()      { return fhitdata.fTOF; };
    Double_t GetPIN()      { return fhitdata.fPIN; };
    Double_t GetXOUT()     { return fhitdata.fXOUT; };
    Double_t GetYOUT()     { return fhitdata.fYOUT; };
    Double_t GetZOUT()     { return fhitdata.fZOUT; };
    Bool_t GetPRIM()       { return fhitdata.fPRIM; };
    
 protected:

    pHitData fhitdata;
    Int_t    fnocall;
    void AddTOF    (Double_t tofin) { 
      if (tofin!=0.) SetTOF((GetTOF()==0.) ? tofin: (GetTOF()+tofin)/2.);
    }

  ClassDef(PamVMCDetectorHit,1) //PamVMCDetectorHit  
};

//PamVMCDetectorHit & operator+=(PamVMCDetectorHit & a, const PamVMCDetectorHit & p );

#endif //PAMVMC_DETECTOR_HIT_H
