// $Id: PamVMCPrimaryGenerator.h,v 1.0 2007/06/03 

#ifndef PAMVMC_PRIMARY_GENERATOR_H
#define PAMVMC_PRIMARY_GENERATOR_H

#include <iostream>
#include <TVirtualMCApplication.h>
#include <TClonesArray.h>
#include <TVector3.h>
#include <TVector2.h>
#include <TMath.h>
#include <TRandom3.h>

#include "PamRootManager.h"

class TVirtualMCStack;

using std::cout;
using std::endl;
using TMath::Sqrt;

class PamVMCPrimary : public TObject
{

 public:
  
  PamVMCPrimary(): fPDG(0), fX0(0.), fY0(0.), fZ0(0.), fTHETA(0.), fPHI(0.), fP0(0.), fGOOD(kFALSE) { };


  Int_t fPDG;
  Double_t fX0, fY0, fZ0;
  Double_t fTHETA, fPHI;  // RADIANTS
  Double_t fP0;
  Bool_t fGOOD;

  void Clean() { fPDG=0; fX0=fY0=fZ0=fTHETA=fPHI=fP0=0.; fGOOD=kFALSE;}

  void Clear(const Option_t * =""){ Clean(); }

  void Print(const Option_t * ="") const
    { cout<<"PRIMARY particle infromation:"<<endl;
      cout<<"Pdg="<<fPDG<<endl; //add name later
      cout<<"Position: "<<"("<<fX0<<","<<fY0<<","<<fZ0<<")"<<endl;
      cout<<"P0, Theta, Phi: "<<fP0<<","<<fTHETA*180./3.1415<<","<<fPHI*180./3.1415<<endl;
      cout<<"GOOD Single Track:"<<fGOOD<<endl;
    }

  ClassDef(PamVMCPrimary,1);
};

PamVMCPrimary & operator+=(PamVMCPrimary &a, const PamVMCPrimary &b);

class PamVMCPrimaryGenerator : public TObject
{
  public:
    PamVMCPrimaryGenerator(TVirtualMCStack* stack, UInt_t seed); 
    //PamVMCPrimaryGenerator(UInt_t seed);
    PamVMCPrimaryGenerator();

    virtual ~PamVMCPrimaryGenerator();

    // methods
    
    void GeneratePrimary();
    // set methods
    void SetParticle(Int_t pdg);
    void SetPosition(Double_t vx, Double_t vy, Double_t vz) 
         {fprim.fX0=vx; fprim.fY0=vy; fprim.fZ0=vz;};
   
    void SetKinEnergy(Double_t kinEnergy) {fprim.fP0=KinEToMomentum(kinEnergy);};
    void SetRigidity(Double_t rigidity) {fprim.fP0=RigToMomentum(rigidity);};
    void SetMomentum(Double_t momentum) {fprim.fP0=momentum; };

    void SetDirection(Double_t theta, Double_t phi) {fprim.fTHETA=theta; fprim.fPHI=phi; };
    void SetMomentum(Double_t px, Double_t py, Double_t pz);

    void SetGood(Bool_t isgood) {fprim.fGOOD=isgood; };

    // gen methods

    void GenPosition(Double_t xmin, Double_t xmax, Double_t ymin, Double_t ymax, Double_t zmin, Double_t zmax){
      SetPosition(frnd->Uniform(xmin,xmax),frnd->Uniform(ymin,ymax),frnd->Uniform(zmin,zmax)); }
	//Spherical distribution in radius, thetamin, thetamax, phimin, phimax.
    void GenSphDist(Double_t, Double_t, Double_t, Double_t, Double_t);
    
    void GenDirection(Double_t thetamin, Double_t thetamax, Double_t phimin, Double_t phimax){
	SetDirection(frnd->Uniform(thetamin,thetamax),frnd->Uniform(phimin,phimax)); }

    //flat spectra generator
    void GenSpe(Double_t PEmin, Double_t PEmax, Bool_t isEnergy=kFALSE); 
    //power law spectra, gamma - differential spectral index
    void GenSpe(Double_t PEmin, Double_t PEmax, Double_t gamma, Bool_t isEnergy=kFALSE); 

    //spherical dist. from radius r, allow only those particles going to cross 3 TOFs
    void GenSphDist(Double_t);


    void GenSphPhiThe(Double_t , Double_t , Double_t , Double_t , 
		      Double_t , Double_t ); // cecilia

    // get methods
    Int_t GetParticle(){ return fprim.fPDG; };
    void  GetPositon(TVector3 & v){ v.SetXYZ(fprim.fX0,fprim.fY0,fprim.fZ0); };
    void  GetPosition(Double_t X0, Double_t Y0,Double_t Z0)
          {X0=fprim.fX0; Y0=fprim.fY0; Z0=fprim.fZ0;};

    Double_t GetKinEnergy() { return MomentumToKinE(fprim.fP0); };
    Double_t GetRigidity() { return MomentumToRig(fprim.fP0); };
    Double_t GetMomentum() { return fprim.fP0; };
    
    void GetDirection(TVector2 & v) {v.Set(fprim.fTHETA,fprim.fPHI);}
    
    Bool_t Getgood(){ return fprim.fGOOD; };

    //work with collection of primaries

    void Register(){
      PamRootManager::Instance()->
	Register("PRIM","TClonesArray", &fprimColl);
    }

    void ClearPrimCol(){
      fevno=0;
      (*fprimColl).Clear();
    }

	void Print(const Option_t * ="") const {fprim.Print();};

  private:
    // methods
    
    Double_t MomentumToKinE(Double_t P0);
    Double_t KinEToMomentum(Double_t E0);
    Double_t MomentumToRig(Double_t P0) { return P0/fcharge; };
    Double_t RigToMomentum(Double_t R0){ return R0*fcharge; };

    // data members
    TVirtualMCStack*  fStack;
    Int_t             fevno;
    PamVMCPrimary     fprim;
    Double_t          fmass;
    Double_t          fcharge;
    TClonesArray*     fprimColl; 

    TRandom3 *        frnd;
    
  ClassDef(PamVMCPrimaryGenerator,2)  //PamVMCPrimaryGenerator
};

// inline functions


inline Double_t PamVMCPrimaryGenerator::MomentumToKinE(Double_t P0)
{ return  Sqrt(P0*P0+fmass*fmass)-fmass; }

inline Double_t PamVMCPrimaryGenerator::KinEToMomentum(Double_t E0)
{ return  Sqrt(E0*E0+2.*E0*fmass); }

#endif //PAMVMC_PRIMARY_GENERATOR_H

