#ifndef PAMVMCTRKSD_H
#define PAMVMCTRKSD_H

#ifdef __cplusplus
extern "C" {
#endif

#define GPINIT gpinit_
#define GPUDIFFUSION gpudiffusion_
#define GPBEGIN gpbegin_
#define GPDSPE gpdspe_
#define GPDCSPE gpdcspe_

  extern void GPINIT(float*, float*);

  extern void GPBEGIN();

  extern void GPUDIFFUSION(int* ,float* ,int*, float* ,float* ,int*);

  extern void GPDSPE();

  extern void GPDCSPE(float*, float*, float*, float*, float*, float* );

#ifdef __cplusplus
}
#endif



#include <iostream>

#include "PamVMCDetectorSD.h"
#include "PamVMCTrkHit.h"
#include "PamVMCTrkF77GpsSpe.h"
#include "PamVMCTrkF77GpcSpe.h"
#include "PamVMCTrkDig.h"
#include <TDatabasePDG.h>
#include <TGeoManager.h>
#include <TSystem.h>
#include <TFile.h>
#include <TH1F.h>
 

class pGPSSPEData;


class PamVMCTrkSD: public PamVMCDetectorSD{
  
 private:
  cGPCSPE * fGPCSPE;
  cGPSSPE * fGPSSPE;
  pGPSSPEHits * fgps;

 public:
  PamVMCTrkSD():PamVMCDetectorSD("PamVMCTrkHit","TSPA",1000)
    {
      fGPCSPE = 0;
      fGPSSPE = 0;
      fgps = new pGPSSPEHits();
      Init();
    };
  
  virtual ~PamVMCTrkSD(){ delete fgps;} 

 //Loading SPE hit resolution data from resxy_new.root
 //which should present in the same directory then application library
 
  void Init(){ 
    TString G4WORKDIR=gSystem->Getenv("G4WORKDIR");
    TString PLATFORM=gSystem->Getenv("PLATFORM");
    TFile * resspe = 
      new TFile(G4WORKDIR+"/lib/tgt_"+PLATFORM+"/resxy_new.root");
    if(resspe->IsOpen()){
      TH1F * hsx;
      TH1F * hsy;
      TString num;
      float cwx[11][1000];
      float cwy[11][1000];
      for(Int_t j=0; j<11; j++){
	num=(::Form("%4i",1000+2*j));
	resspe->GetObject("h"+num+";1",hsx);
	num=(::Form("%4i",2000+2*j));
	resspe->GetObject("h"+num+";1",hsy);
	if ((hsx)&&(hsy)){
	  for(Int_t i = 0; i<1000; i++){
	    cwx[j][i]=hsx->GetBinContent(i);
	    cwy[j][i]=hsy->GetBinContent(i);
	  }
	}else{
	  cout<<"!!!WARNING: SPE hit resolution data file corrupted!!!"<<endl
	      <<"!!!Application terminated..."<<endl;
	  // exit(-1);
	}
      }

       gpinit_((*cwx), (*cwy));
       
       delete hsx;
       delete hsy;
    } else cout<<"!!!WARNING: SPE hit resolution data file resxy_new.root"
	     <<" is not present in: " <<G4WORKDIR+"/lib/tgt_"+PLATFORM
	     <<" or corrupted!!!"<<endl;

    delete resspe;
  }

  /*This method for zeroing PROXTANTI, PROYTANTI, GLOBSTRIPX, GLOBSTRIPY
    arrays in fortran common. Calls before each event */
  virtual void PreEvent(){ gpbegin_(); }

  void Register(){
    
    PamRootManager::Instance()->
      Register(fdname.Data(),"TClonesArray", &fHitColl);
    TString a=fHitColl?"exist":"not exist"; 
    PamRootManager::Instance()->
      Register("GPSSPE","pGPSSPEHits",&fgps);
    
    if (fdig) ((PamVMCTrkDig*)fdig)->RegisterTrkData(fgps);

  }

   virtual void ClearHitColl(){
     fnohit=0;
     (*fHitColl).Clear("C");
     fgps->Clear();
   }


 virtual void Compress(){fgps->Compress(); (*fHitColl).Compress();}

 virtual void SaveTrkHit(const char * dname){
   PamVMCDetectorHit * t=(PamVMCDetectorHit*) CreateTrkHit(dname);
   *t=*fhit;
 }

 virtual PamVMCTrkHit * CreateTrkHit(const char * dname) 
  { 
    fdetID=(PamVMCGeoID*)fdmap(dname); 
    return CreateTrkHit();
 }

 virtual  PamVMCTrkHit * CreateTrkHit() 
  { 
    PamVMCTrkHit *hit=  (PamVMCTrkHit *) fHitColl->New(fnohit++);
    InitHit();
    SetTrkHit(hit);
    return hit;
  }

  void FillHit(fin f,TVirtualMC *g){
    ffi=f;
    //g->SetMaxStep(0.001); // 10 um
    switch(f) {
    case ENTERING:
      CleanHit();
       FillVolID();
      InitHit();
      //cout<<">>>ENTERING in PLANE: "<<GetPlaneID()<<endl;
    default: 
      UpdateHit(g);
      //TParticlePDG* particlePDG = TDatabasePDG::Instance()->GetParticle(gMC->TrackPid());
      //Double_t mass = particlePDG->Mass();
      //Double_t x,y,z,e;
      //g->TrackMomentum(x,y,z,e);
      //Double_t P0 = TMath::Sqrt(x*x+y*y+z*z);
      //Double_t energy =  TMath::Sqrt(P0*P0+mass*mass)-mass;
      //cout<<"stepping... Stepsize"<<gMC->TrackStep()*10000<<"um "<<" particle PDG is:"<<gMC->TrackPid()<<" Kin.energy:"<<energy*1000000<<" keV"<<endl;
     
      if (g->Edep()) PreDigit(); 
      
      break;      
    }

    switch(f){
    case EXITING:
      //cout<<"<<<EXITING out"<<gMC->TrackPid()<<endl;
    // Save hit if energy release is greater than zero
      if(fhit->GetEREL()){
	SaveTrkHit(fdname.Data());
      }
      break;
    default:
      break;
    }
  }
  


  /*This method for simulation spatial tracker resolution, use data from
    resxy_new.root file. Calls on track exiting when we know XOUT,YOUT,ZOUT */
  void SetTrkHit(PamVMCTrkHit *t){
    float xin = (float)fhit->GetXIN();
    float yin = (float)fhit->GetYIN();
    float zin = (float)fhit->GetZIN();
    float xout = (float)fhit->GetXOUT();
    float yout = (float)fhit->GetYOUT();
    float zout = (float)fhit->GetZOUT();

    gpdcspe_(&xin, &yin, &zin, &xout, &yout, &zout);

    fGPCSPE=&gpcspe_;

    //      cout<<"GPCSPE"<<fGPCSPE->xave<<" "<<fGPCSPE->yave<<" "<<
    //	fGPCSPE->zave<<" " <<fGPCSPE->nxmult<<" "<<fGPCSPE->nymult<<endl;

      	fGPCSPE->SetHit(t);
  }


  /*This method designed for calculaton energy release on trakcer strips
    is calls for each step*/

  virtual void PreDigit(){
     
      Double_t x,y,z,px,py,pz,e,p;
      
      gMC->TrackMomentum(px,py,pz,e);
      
     
      p=sqrt(px*px+py*py+pz*pz);
     
      if(p){ //sometimes FLUKA vives u p=0

	gGeoManager->cd(gMC->CurrentVolPath());
      
	int iact=ffi;

	float *trpar = new float[6]; 

	gMC->TrackPosition(x,y,z);

	trpar[0]=(float)x;
	trpar[1]=(float)y;
	trpar[2]=(float)z;

	trpar[3]=(float)px/p;
	trpar[4]=(float)py/p;
	trpar[5]=(float)pz/p;
     
	int *numvol = new int[2];
	numvol[0]=GetPlaneID();
	//if (numvol[0]==6) numvol[0]=0;
	numvol[1]=GetPadID();

	float deloss=(float)gMC->Edep();
	
	float step=(float)gMC->TrackStep();
	
	int itypar=TDatabasePDG::Instance()->ConvertPdgToGeant3(gMC->TrackPid());
	
	gpudiffusion_(&iact, trpar, numvol, &deloss, &step, &itypar);
	
	delete numvol;
	delete trpar;
      }

  }


  /*This method calculate ADC amplitudes from strips. It use data arrays
    PROXTANTI, PROYTANTI, GLOBSTRIPX, GLOBSTRIPY in common. Calls after
    each event from application */

 virtual void Digitize(){

   gpdspe_();

   fGPSSPE = &gpsspe_; 

   fgps->SetData(fGPSSPE);
 }



Int_t GetPlaneID(){
  Int_t pl=Int_t((fhit->GetPOS()-1)/6.)+1;
  return pl;
}

Int_t GetPadID(){
    return (fhit->GetPOS()-(GetPlaneID()-1)*6);
}

  ClassDef(PamVMCTrkSD,1)

};



#endif // PAMVMCTRKSD_H
