// $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 "PamVMCVolCrossMgr.h"

#include "PamVMCDetPamela.h"

//#include "TFluka.h"



ClassImp(PamVMCApplication)

  PamVMCApplication::PamVMCApplication(const char *name, const char *title, const char *filename, UInt_t seed) 
  : TVirtualMCApplication(name,title),
    fEventNo(0),
    fVerbose(2),
    fStack(0),
    fdetector(0),
    //fPrimaryGenerator(0,seed),
    fRootManager(filename,kWrite)
{
  // Standard constructor

  // Create a user stack
  fStack = new PamVMCStack(1000);
    
  // Create a primary generator
  fPrimaryGenerator = new PamVMCPrimaryGenerator(fStack, seed);

  fdetector = new PamVMCDetPamela();

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

}



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


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


void PamVMCApplication::InitMC(const char* setup, const char *filename, UInt_t seed )
{    
// Initialize MC.

  fVerbose.InitMC();

  gROOT->LoadMacro(setup);
  gInterpreter->ProcessLine("Config()");
  gMC->SetStack(fStack);
  std::cout<<"!!! BEFORE INIT GMC"<<std::endl;
  
  gMC->Init();
  cout<<"INIT MC"<<endl;
  gMC->BuildPhysics();
  cout<<"PHYSICS BUILDED"<<endl;
    
  PamVMCRawMgr::Instance(filename);

  // Initialize seed for random generation // Cecilia  
  PamVMCDigMgr::Instance(seed);

  fdetector->InitMC();
  // fdetector->Print();

  PamVMCSDMgr::Instance()->Register();
  
  PamVMCDigMgr::Instance()->LoadCalib();
  PamVMCRawMgr::Instance(filename)->WriteToFile();
  
  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();
  gMC->DefineIon("He4",2,4,1,0.);
  gMC->DefineIon("Boron",5,10,1,0.);  
  gMC->DefineIon("Carbon",6,12,1,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");
  gGeoManager->CloseGeometry();
  gMC->SetRootGeometry();

  cout<<"!!CONSTRUCT GEOMETRY!!"<<endl;
   fdetector->ConstructCuts();

}

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();
  //fPrimaryGenerator->Print();
}

void PamVMCApplication::BeginEvent()
{    
// User actions at beginning of event
  PamVMCSDMgr::Instance()->PreEvent();
  fEventNo++;
}

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

  fVerbose.BeginPrimary();
}

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

void PamVMCApplication::Stepping()
{    
  if (fStack->GetCurrentTrack()->IsPrimary()){
    PamVMCVolCross* tmp=(PamVMCVolCross*)PamVMCVolCrossMgr::Instance()->GetSD(gMC->CurrentVolName());
    if (tmp){
      tmp->CrossVol();
    }
  }
// User actions at each step
  fVerbose.Stepping();
  PamVMCDetectorSD* temp=(PamVMCDetectorSD*) PamVMCSDMgr::Instance()->GetSD(gMC->CurrentVolName());
  if(temp){
    fdstatus=INSIDE;
    if(gMC->IsTrackEntering()){ fdstatus=ENTERING; }
    if(gMC->IsTrackExiting() || gMC->IsTrackOut() || gMC->IsTrackStop() ) { fdstatus=EXITING;}
    temp->FillHit(fdstatus,gMC);    
  }
  
}

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

}

void PamVMCApplication::FinishPrimary()
{    
// User actions after finishing of a primary track
  fPrimaryGenerator->SetGood(PamVMCVolCrossMgr::Instance()->IsTrackGood());
  PamVMCVolCrossMgr::Instance()->Reset();
  fVerbose.FinishPrimary();
}

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

    

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

    PamVMCSDMgr::Instance()->Compress();

    PamVMCRawMgr::Instance()->WriteEvent();

    fRootManager.Fill();

    fPrimaryGenerator->ClearPrimCol();

    PamVMCSDMgr::Instance()->Clear();

    fStack->Reset();

	//getchar();
   
} 

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

  PamVMCDigMgr::Instance()->FinishRun(); //write RunTrailer to buffer

  PamVMCRawMgr::Instance()->FinishRun(); //write RunTrailer to file and close;

  PamVMCDigMgr::Instance()->PrintCollections();

}

void PamVMCApplication::Field(const Double_t* x, Double_t* b) const
{
  PamVMCFieldMgr::Instance()->Field(x,b);
}
