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

#include <TObject.h>
#include <TVirtualMC.h>
#include <TParticle.h>
#include <TG4G3Units.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;

  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.) { };

//   pHitData( pHitData & p ): fPOS(p.fPOS), fPDG(p.fPDG), fPATH(p.fPATH), fTOF(p.fTOF), 
//     fPIN(p.fPIN), fXOUT (p.fXOUT), 
//     fYOUT( p.fYOUT),  fZOUT (p.fZOUT), fEREL( p.fEREL), 
//     fXIN(p.fXIN),  fYIN( p.fYIN), fZIN( p.fZIN) { };


  void Clean() {
    fPOS=fPDG=0;
    fPATH= fTOF= fPIN= fXOUT = 
      fYOUT =  fZOUT = fEREL = 
      fXIN=  fYIN = fZIN = 0.;
  }

  //  pHitData & operator+=( const pHitData &a);//, const pHitData & p) ;
  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
         <<"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; } 
  
  ClassDef(pHitData,1)

};


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


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

    //Set and Add methods

    void CleanHit() {
       fhitdata.Clean();
       fnocall=0;
    }
    pHitData * GenHit() { return new pHitData(fhitdata);}


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

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

    void FillHit(TVirtualMC *g) {
      fnocall++;
      //      SetPOS(pos);
      ///      TLorentzVector k;
      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())/TG4G3Units::Time()+(g->TrackTime()));
      AddPATH(g->TrackStep());
      AddEREL(g->Edep());

    }    
  
    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 );
    }

    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 Incnocall () {fnocall++;}
    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 Reset(); //{ fhitdata.Clean(); }
                 
    // Get methods

    const pHitData *GetHit() {return &fhitdata;}
    //Int_t    Getnocall()   { return fnocall; };
    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; };
    
  protected:

    pHitData fhitdata;
  //    Int_t    fHITN;
  //    Int_t    fPOS;    //Number, defines copy number of SD volume;
    Int_t    fnocall;
    // Double_t IncrementAve ( Double_t t, Double_t d) 
    // { return (t*(fnocall-1) + d)/fnocall; }
    void AddTOF    (Double_t tofin) { 
      //fhitdata.fTOF = IncrementAve(fhitdata.fTOF,tofin);
      if (tofin!=0.) SetTOF((GetTOF()==0.) ? tofin: (GetTOF()+tofin)/2.);
    }

  ClassDef(PamVMCDetectorHit,1) //PamVMCDetectorHit  
};

#endif //PAMVMC_DETECTOR_HIT_H
