// $Id: PamVMCApplication.cxx,v 1.0 2007/06/01 
//
// Geant4 ExampleN06 adapted to Virtual Monte Carlo 
#include <cstdlib>
#include <string>
#include <iostream>
#include <TROOT.h>
#include <TInterpreter.h>
#include <TVirtualMC.h>
#include <Riostream.h>
#include <TGeoManager.h>
#include <TVirtualGeoTrack.h>
#include <TLorentzVector.h>
#include "PamVMCApplication.h"
#include "PamVMCCaloSD.h"
#include "PamVMCTrkSD.h"
#include "PamVMCTofSD.h"
#include "PamVMCCardSD.h"
#include "PamVMCCasSD.h"
#include "PamVMCCasSD.h"
#include "PamVMCS4SD.h"
//#include "PamVMCDetectorHit.h"
//#include "PamVMCCalorHit.h"
#include "PamVMCStack.h"
#include "PamVMCDetectorConstruction.h"
#include "PamVMCPrimaryGenerator.h"

ClassImp(PamVMCApplication)

PamVMCApplication::PamVMCApplication(const char *name, const char *title) 
  : TVirtualMCApplication(name,title),
    fEventNo(0),
    fVerbose(0),
    fStack(0),
    fDetConstruction(0),
    fPrimaryGenerator(0),
    fRootManager("pamtest",kWrite)
  //, fdetmap(0)
{
// Standard constructor

  // Create a user stack
  fStack = new PamVMCStack(1000);
  
  // Create detector construction
  fDetConstruction = new PamVMCDetectorConstruction();
  
  // Create a primary generator
  fPrimaryGenerator = new PamVMCPrimaryGenerator(fStack);

  //fCaloSD = new PamVMCCaloSD(); 

  // std::cout <<"!!!!!!!!APPLICATION CREATED!!!"<<std::endl;
 // Create a tracker SD
  
  //fTrackerSD = new PamVMCTrackerSD("PamVMCTracker", fDetConstruction); 

 // Create a tof SD
  
  //fTofSD = new PamVMCTofSD("PamVMCTof", fDetConstruction);

#ifdef PAMFIELD
  // Load the PAMELA magnetic field

  std::string pamcal=getenv("PAM_CALIB"); pamcal+="/trk-param/field_param-0/";
  std::cout << "PAMELA env: " << pamcal << std::endl;
  pamfield.LoadField(pamcal.c_str());
#endif
}


PamVMCApplication::PamVMCApplication()
  : TVirtualMCApplication(),
    fEventNo(0),
    fVerbose(0),
    fStack(0),
    fDetConstruction(0),
    fPrimaryGenerator(0),
    fRootManager()
{    
// Default constructor
}

PamVMCApplication::~PamVMCApplication() 
{
// Destructor  
  
  delete fStack;
  delete fDetConstruction;
  delete fPrimaryGenerator;
  delete gMC;
  gMC = 0;
}

//
// public methods
//

void PamVMCApplication::InitMC(const char* setup)
{    
// Initialize MC.

  fVerbose.InitMC();

    gROOT->LoadMacro(setup);
    gInterpreter->ProcessLine("Config()");
    gMC->SetStack(fStack);
    std::cout<<"!!! BEFORE INIT GMC"<<std::endl;
     gMC->Init();
  
    gMC->BuildPhysics();
 
//Creating a KEYS for SD volume names:
 
    std::cout<<"!!!Creating PamVMCCaloSD object"<<std::endl;
    fdetmap.Add(new TObjString("CAST"), new PamVMCCaloSD() );
    fdetmap.Add(new TObjString("S11Y"), new PamVMCTofSD("S11Y") );
    fdetmap.Add(new TObjString("S12X"), new PamVMCTofSD("S12X") );
    fdetmap.Add(new TObjString("S21X"), new PamVMCTofSD("S21X") );
    fdetmap.Add(new TObjString("S22Y"), new PamVMCTofSD("S22Y") );
    fdetmap.Add(new TObjString("S31Y"), new PamVMCTofSD("S31Y") );
    fdetmap.Add(new TObjString("S32X"), new PamVMCTofSD("S32X") );
    fdetmap.Add(new TObjString("TSPA"), new PamVMCTrkSD() );
    fdetmap.Add(new TObjString("C1D1"), new PamVMCCardSD("C1D1") );
    fdetmap.Add(new TObjString("C2D1"), new PamVMCCardSD("C2D1") );
    fdetmap.Add(new TObjString("SID1"), new PamVMCCasSD() );
    fdetmap.Add(new TObjString("MGSC"), new PamVMCCatSD() );
    fdetmap.Add(new TObjString("S4"), new PamVMCS4SD() );
    fdetmap.Add(new TObjString("NDTI"), new PamVMCNDSD() );
    std::cout<<"!!!!PamVMCCaloSD object created"<<std::endl;
    //fdetmap.Print();
//Registration should be after inserting all detectors in fdetmap
    Register();

}

void PamVMCApplication::RunMC(Int_t nofEvents)
{    
// MC run.

  fVerbose.RunMC(nofEvents);

  gMC->ProcessRun(nofEvents);

  fVerbose.FinishRun();
}


void PamVMCApplication::ConstructGeometry()
{    
// Construct geometry using detector contruction class

  fVerbose.ConstructGeometry();
  fDetConstruction->ConstructGeometry();
      
}

void PamVMCApplication::InitGeometry()
{    
// Initialize geometry
  
  fVerbose.InitGeometry();
  //fCalorimeterSD->Initialize();
  //fTrackerSD->Initialize();
  //fTofSD->Initialize();

//Initialization of HitCollestions in Root file:
  std::cout<<"!!!! Before registration HitCol!!!"<<std::endl;
 
}


void PamVMCApplication::GeneratePrimaries()
{    
// Fill the user stack (derived from TVirtualMCStack) with primary particles.
  
  ///// fVerbose.GeneratePrimaries();

  fPrimaryGenerator->GeneratePrimaries();
}

void PamVMCApplication::BeginEvent()
{    
// User actions at beginning of event

  ///// fVerbose.BeginEvent();

  //fCalorimeterSD->BeginOfEvent();
  fEventNo++;
 }

void PamVMCApplication::BeginPrimary()
{    
// User actions at beginning of a primary track

  fVerbose.BeginPrimary();
}

void PamVMCApplication::PreTrack()
{    
// User actions at beginning of each track

  ////// fVerbose.PreTrack();
  
}

void PamVMCApplication::Stepping()
{    

// User actions at each step
  fVerbose.Stepping();
  ///std::cout<<"!!!! STEP"<<std::endl;

  // if (gMC->IsTrackAlive()){
    PamVMCDetectorSD* temp=(PamVMCDetectorSD*) fdetmap(gMC->CurrentVolName());
    if(temp){
      fdstatus=INSIDE;
      if(gMC->IsTrackEntering()){ fdstatus=ENTERING; }
      if(gMC->IsTrackExiting() || gMC->IsTrackOut() || gMC->IsTrackStop() ) { fdstatus=EXITING;/* fStack->Print();*/}
      temp->FillHit(fdstatus,gMC);
    }
    //  }
 
}

//void PamVMCApplication::FillTempHit(){
//  Double_t pxin,pyin,pzin,ein;
//  gMC->TrackPosition(ftemphit.fXIN,ftemphit.fYIN,ftemphit.fZIN);
//  gMC->TrackMomentum(pxin,pyin,pzin,ein);

//  ftemphit.fPIN=sqrt(pxin*pxin + pyin*pyin + pzin*pzin); 
//  ftemphit.fPDG= gMC->TrackPid();
//  ftemphit.fEREL= gMC->Edep(); 
//  ftemphit.fPATH= gMC->TrackStep();
//  ftemphit.fTOF=  gMC->TrackTime(); 
//  ftemphit.fXOUT=ftemphit.fXIN;
//  ftemphit.fYOUT=ftemphit.fYIN;
//  ftemphit.fZOUT=ftemphit.fZIN;
//}

void PamVMCApplication::PostTrack()
{    
// User actions after finishing of each track


  ///// fVerbose.PostTrack();
}

void PamVMCApplication::FinishPrimary()
{    
// User actions after finishing of a primary track

   fVerbose.FinishPrimary();
}

void PamVMCApplication::FinishEvent()
{    
// User actions after finishing of an event

  //fCalorimeterSD->GetCalorHitBuff()->Shrink();
  /////fVerbose.FinishEvent();
    fRootManager.Fill();
      TMapIter *n= (TMapIter *)fdetmap.MakeIterator(); 
      TObject *o; while( o=(TObject *) n->Next()) { 
       ((PamVMCDetectorSD *)fdetmap.GetValue(o))->ClearHitColl();
      }
  // fCalorimeterSD->PrintTotal();
     //  std::cout<<"ENDCAL EVENT"<<std::endl;
     //fCalorimeterSD->EndOfEvent();
     //fTrackerSD->EndOfEvent();
     //fTofSD->EndOfEvent();
  fStack->Reset();
} 

void PamVMCApplication::FinishRun()
{

  //  fRootManager.Fill();
  fVerbose.FinishRun();

  fRootManager.WriteAll();
}
void PamVMCApplication::Field(const Double_t* x, Double_t* b) const
{
// Uniform magnetic field

#ifdef PAMFIELD
     b[0] = pamfield.GetBX((float *)x);
     b[1] = pamfield.GetBY((float *)x);
     b[2] = pamfield.GetBZ((float *)x);
     cout<<b[0]<<" "<<b[1]<<" "<<b[2]<<endl;
#else
     if(x) { for (Int_t i=0; i<3; i++) b[i] = 0.0; } else { b[0]=b[1]=b[2]=0.0; }

#endif
}
