// $Id: PamVMCApplication.cxx,v 1.0 2007/06/01 
//
// Geant4 PAMELA VMC 
#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 "PamVMCStack.h"
#include "PamVMCPrimaryGenerator.h"

#include "PamVMCFieldMgr.h"

#include "PamVMCSDMgr.h"

#include "PamVMCDetPamela.h"

#include "PamVMCRndMgr.h"
#include "PamVMCOptMgr.h"


ClassImp(PamVMCApplication)

PamVMCApplication::PamVMCApplication(const char *name, const char *title, const char* filename, Int_t seed) 
  : TVirtualMCApplication(name,title),
    fEventNo(0),
    fVerbose(2),
    fStack(0),
    fdetector(0),
    fPrimaryGenerator(0),
    fRootManager(filename,kWrite),
    ftrig(0)
{
  cout<<"---> PamVMCApplication::PamVMCApplication"<<endl;
  // Create a user stack
  fStack = new PamVMCStack(1000);
  
  // Create a primary generator
  fPrimaryGenerator = new PamVMCPrimaryGenerator(fStack);
  
  //Create random object
  frandom = new TRandom3(seed);
  std::cout<<"!!! THE SEED of this MONTE CARLO is: "<<frandom->GetSeed()<<std::endl;

  fdetector = new PamVMCDetPamela();

  PamVMCFieldMgr::Instance()->LoadField();

  cout<<"OK1"<<endl;
  TString fname=filename; fname+=".pam";
  PamVMCOptMgr::Instance();

  if (PamVMCOptMgr::Instance()->GetSaveMode() == ALL_DETECTORS){
    cout<<"OK2"<<endl;
    PamVMCRawMgr::Instance()-> CreateOutFile(fname.Data());
  }
  cout<<"<--- PamVMCApplication::PamVMCApplication"<<endl;
}


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


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

  fVerbose.InitMC();

  gROOT->LoadMacro(setup);
  gInterpreter->ProcessLine("Config()");
  gMC->SetStack(fStack);
  gMC->SetRandom(frandom);
  
#if ROOT_VERSION_CODE >= 333572
  gMC->SetMagField(PamVMCFieldMgr::Instance());
  cout<<"Magnetic field set"<<endl;
#endif

  std::cout<<"!!! BEFORE INIT GMC"<<std::endl;
  
  gMC->Init();
  cout<<"INIT MC"<<endl;
  gMC->BuildPhysics();
  cout<<"PHYSICS BUILDED"<<endl;

  fdetector->InitMC();
  
  // fdetector->Print();
  
  if (PamVMCOptMgr::Instance()->GetSaveMode() == ALL_DETECTORS){
    PamVMCSDMgr::Instance()->Register();
    PamVMCDigMgr::Instance()->Initialize((TRandom3*)gMC->GetRandom());
    PamVMCRawMgr::Instance()->WriteToFile();
  }
  fPrimaryGenerator->SetRandom(gMC->GetRandom());
 
  fPrimaryGenerator->Register();
  
  std::cout<<"LIST OF ACTIVE SD'S:"<<std::endl;
  
  PamVMCSDMgr::Instance()->Print();
}

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

  fVerbose.RunMC(nofEvents);

  gMC->ProcessRun(nofEvents);

  fVerbose.FinishRun();
}

void PamVMCApplication::AddIons(){

  fVerbose.AddIons();
  //Arguments are:
  //name
  //Z (atomic number)
  //A (atomic mass)
  //Q (charge eplus)
  //exitation exitation energy [GeV] 0. if in ground state
  //mass [GeV], if not specified, calculated approx
  gMC->DefineIon("H2",1,2,1,0., 1.875613);
  gMC->DefineIon("H3",1,3,1,0., 2.808921);
  gMC->DefineIon("He3",2,3,2,0.,2.808391);
  gMC->DefineIon("He4",2,4,2,0.,3.727379); 
  gMC->DefineIon("Li6",3,6,3,0.);
  gMC->DefineIon("Li7",3,7,3,0.);
  gMC->DefineIon("Be7",4,7,4,0.);
  gMC->DefineIon("Be9",4,9,4,0.);
  gMC->DefineIon("Be10",4,10,4,0.);
  gMC->DefineIon("B10",5,10,5,0.);
  gMC->DefineIon("B11",5,11,5,0.);
  gMC->DefineIon("C12",6,12,6,0.);
  gMC->DefineIon("N14",7,14,7,0.);
  gMC->DefineIon("O16",8,16,8,0.); 
}


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

  fVerbose.ConstructGeometry();
  new TGeoManager("PAM_GEOM","PAMELA GEOMETRY");
  fdetector->ConstructGeometry();
  //TGeoManager::Import("/home/pamela/PamCAL210508/gp2tgeo.root");
  cout<<"--->CONSTRUCT GEOMETRY"<<endl;
  gGeoManager->CloseGeometry();
  gMC->SetRootGeometry();
  cout<<"<---GEOMETRY CONSTRUCTED"<<endl;
  
  //cout<<"--->CONSTRUCT CUTS"<<endl;
  //fdetector->ConstructCuts();
  //cout<<"<---CUTS CONSTRUCTED"<<endl;

}

void PamVMCApplication::InitGeometry()
{    
  // Initialize geometry
  
  cout<<"!!SETUP CUTS"<<endl;
  //fdetector->InitGeometry();

  fVerbose.InitGeometry(); 
}


void PamVMCApplication::GeneratePrimaries()
{    
  // Fill the user stack (derived from TVirtualMCStack) with primary particles.
  
  fPrimaryGenerator->GeneratePrimary();
}

void PamVMCApplication::BeginEvent()
{    
// User actions at beginning of event
if (PamVMCOptMgr::Instance()->GetSaveMode() == ALL_DETECTORS){
   PamVMCSDMgr::Instance()->PreEvent();
 }
 ftrig = 0;
 fEventNo++;
}

void PamVMCApplication::BeginPrimary()
{    
// User actions at beginning of a primary track
  fVerbose.BeginPrimary();
  //making a clones of random objects states
  if (PamVMCOptMgr::Instance()->GetSaveMode() == ALL_DETECTORS) PamVMCRndMgr::Instance()->MakeRandomClones();
  Double_t x,y,z;
  gMC->TrackPosition(x,y,z);
  fPrimaryGenerator->SetZeroStep(z,x,y);
}

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


#define CAVITY_X 8.07
#define CAVITY_Y 6.57
#define ZCAVITY_MIN 27.399
#define ZCAVITY_MAX 71.059



void PamVMCApplication::Stepping()
{    
  if (fStack->GetCurrentTrack()->IsPrimary()){    
    //write some code to call cross manager for primary
    Double_t x,y,z;
    gMC->TrackPosition(x,y,z);
    fPrimaryGenerator->CheckCrossing(z,x,y);
  }
  
// User actions at each step
  fVerbose.Stepping();
  PamVMCDetectorSD* temp=(PamVMCDetectorSD*) PamVMCSDMgr::Instance()->GetSD(gMC->CurrentVolName()); //old

  if(temp){

    fdstatus=INSIDE;
    if(gMC->IsTrackEntering()){ fdstatus=ENTERING; }
    if(gMC->IsTrackExiting() || gMC->IsTrackOut() || gMC->IsTrackStop() ) { fdstatus=EXITING;}
    temp->FillHit(fdstatus,gMC,fStack->GetCurrentTrack()->IsPrimary());    
  }

}

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

}

void PamVMCApplication::FinishPrimary()
{    
// User actions after finishing of a primary track
  fVerbose.FinishPrimary();
  //Here I should add stuff to check if primary was inside acceptance
  fPrimaryGenerator->CheckInsideAcceptance();
}

void PamVMCApplication::FinishEvent()
{    
// User actions after finishing of an event
  ftrig = PamVMCSDMgr::Instance()->GetTrigger();

  switch( PamVMCOptMgr::Instance()->GetSaveCond()){
  case EVERYTHING:
    if (PamVMCOptMgr::Instance()->GetSaveMode() == ALL_DETECTORS) FillEv();
    fRootManager.Fill();
    break;

  case TRIG_ONLY:
    if( ftrig ){
      if (PamVMCOptMgr::Instance()->GetSaveMode() == ALL_DETECTORS) FillEv();
      fRootManager.Fill();
    }
    break;

  case ACCEPT_ONLY:
    if( fPrimaryGenerator->Getgood() ){
      if (PamVMCOptMgr::Instance()->GetSaveMode() == ALL_DETECTORS) FillEv();
      fRootManager.Fill();
    }
    break;

  default:
    break;


  }



  

  fPrimaryGenerator->ClearPrimCol();
  
  //Check for trigger:
  
  
  PamVMCSDMgr::Instance()->Clear();
  if (PamVMCOptMgr::Instance()->GetSaveMode() == ALL_DETECTORS) PamVMCRndMgr::Instance()->ClearColl();
  
  fStack->Reset(); 
} 


void PamVMCApplication::FillEv(){

  PamVMCSDMgr::Instance()->Digitize();
  //EventNo needs for trigger, particle PDG needs for TOF..
  PamVMCDigMgr::Instance()->Digitize(fEventNo,fPrimaryGenerator->GetParticle());
  
  PamVMCSDMgr::Instance()->Compress();
  
  PamVMCRawMgr::Instance()->WriteEvent();    
  PamVMCRndMgr::Instance()->Compress();
}

void PamVMCApplication::FinishRun()
{
  fVerbose.FinishRun();
  
  fRootManager.WriteAll();

  if (PamVMCOptMgr::Instance()->GetSaveMode() == ALL_DETECTORS){
    PamVMCRawMgr::Instance()->FinishRun();  
    PamVMCDigMgr::Instance()->PrintCollections();
  }

}

#if ROOT_VERSION_CODE < 333572  
void PamVMCApplication::Field(const Double_t* x, Double_t* b) const
{
  PamVMCFieldMgr::Instance()->Field(x,b);
}
#endif
