#include <iostream>
#include "TObject.h"

using namespace std;

#ifndef OPT_INIT_MODE_H
#define OPT_INIT_MODE_H


#include "TSystem.h"

struct pInitModeOpt : public TObject {
  TString fg4Config_path,  fg4Config_C_name,  fg4Config_in_name;
  Bool_t fuse_pbs_jobcookie, fuse_nocalo;
  TString fout_tmp_dir, fout_path, fout_file_pattern;

  pInitModeOpt( TString g4Config_path, TString g4Config_C_name, TString  g4Config_in_name, Bool_t use_pbs_jobcookie, Bool_t use_nocalo,
		TString out_tmp_dir,  TString out_path, TString out_file_pattern): 
  fg4Config_path(g4Config_path), fg4Config_C_name(g4Config_C_name), fg4Config_in_name(g4Config_in_name), fuse_pbs_jobcookie(use_pbs_jobcookie), fuse_nocalo(use_nocalo),
    fout_tmp_dir(out_tmp_dir), fout_path(out_path), fout_file_pattern(out_file_pattern) {};
 
  virtual void Print(const Option_t* = "") const {
    cout<<"--->Init Options: "<<endl;
    cout<<"       g4Config macro: "<<fg4Config_path<<"/"<<fg4Config_C_name<<endl;
    cout<<"       G4 extra macro: "<<fg4Config_path<<"/"<<fg4Config_in_name<<endl;
    cout<<"       use PBS cookie: "<<fuse_pbs_jobcookie<<endl;
    if ( fuse_pbs_jobcookie ) cout <<"       temp path: "<<  fout_tmp_dir<<endl;   
    cout<<"       use NoCalo: "<<fuse_nocalo<<endl;
    cout<<"       output ROOT-file: "<<fout_path<<"/"<<fout_file_pattern<<".root"<<endl;
    cout<<"       output PAM-file: "<<fout_path<<"/"<<fout_file_pattern<<".pam"<<endl;
  };
};

#endif //OPT_INIT_MODE_H


#ifndef OPT_RND_MODE_H
#define OPT_RND_MODE_H



struct pRandomModeOpt : public TObject {
  Bool_t  fread_from_file_mode; /* 0 - generate, 1 - read from file */
  TString fread_g4_seed_path; /* full path to root-file with g4random engine snapshots */
  Bool_t fgenerate_g4_seed_user; /* 1 - generate random use user-defined seeds, 0 - autogenerate them */
  Int_t fseed1, fseed2;
  Bool_t fwrite_to_file_mode; /* 0 - don't save g4 random snapshots into root-file, 1 - do it */
  TString fwrite_g4_rnd_path, fwrite_g4_rnd_filename; /* path and filename with g4 random snapshots */


 pRandomModeOpt( Bool_t  read_from_file_mode, TString read_g4_seed_path,  Bool_t generate_g4_seed_user,
		 Int_t seed1, Int_t seed2, Bool_t write_to_file_mode, 
		 TString write_g4_rnd_path, TString  write_g4_rnd_filename ):
  fread_from_file_mode( read_from_file_mode), fread_g4_seed_path(read_g4_seed_path), fgenerate_g4_seed_user(generate_g4_seed_user),
    fseed1(seed1), fseed2(seed2), fwrite_to_file_mode(write_to_file_mode),fwrite_g4_rnd_path(write_g4_rnd_path), fwrite_g4_rnd_filename(write_g4_rnd_filename) {};
 
  virtual void Print(const Option_t* = "") const {
    TString tt;
    if ( fread_from_file_mode ) tt = "read from file: "; else tt = "generate ";
    cout<<"--->Random Options: "<<endl;
    cout<<"       G4Random numbers will "<<tt;
    if ( fread_from_file_mode ){
      cout << fread_g4_seed_path <<endl;
    } else {
      if ( fwrite_to_file_mode ) cout<<"and written in file: "<<fwrite_g4_rnd_path<<"/"<<fwrite_g4_rnd_filename<<endl; else cout<<endl;
    }
    if( fgenerate_g4_seed_user ){
      tt = "user-defined random seed numbers: ";
      tt += fseed1;
      tt += ", ";
      tt += fseed2;
    } else tt = " random seed numbers will be generated automatically via TRandom3(0) object";
    if (!fread_from_file_mode ) cout<<"       Generation mode: "<<tt<<endl;
  };
};

#endif //OPT_RND_MODE_H



#ifndef OPT_RUN_MODE_H
#define OPT_RUN_MODE_H
enum Save_cond { EVERYTHING, TRIG_ONLY, ACCEPT_ONLY};
enum Save_mode { ALL_DETECTORS, ONLY_PRIMARIES };

struct pRuntimeModeOpt : public TObject {
  Int_t fverbose_lev; //verbose level
  Int_t fmaxstep;     //maximum number of allowed steps for a given particle
  Save_cond fsv_c;    //condition to save given event
  Save_mode fsv_m;    //what information I wish to save

 pRuntimeModeOpt(Int_t verbose_lev, Int_t maxstep, Save_cond sv_c, Save_mode sv_m): fverbose_lev(verbose_lev), fmaxstep(maxstep), fsv_c(sv_c), fsv_m(sv_m){; }; 

  virtual void Print(const Option_t* = "") const {
     cout<<"--->Runtime Options: "<<endl;
     cout<<"             Verbose level: "<<fverbose_lev<<endl;
     cout<<"       Max number of steps: "<<fmaxstep<<endl;
     TString tt="";
     if(fsv_c == EVERYTHING) tt = "EVERYTHING";
     if(fsv_c == TRIG_ONLY) tt = "TRIG_ONLY";
     if(fsv_c == ACCEPT_ONLY) tt = "ACCEPT_ONLY";
     cout<<"            Save condition: "<<tt<<endl;
     tt="";
     if(fsv_m == ALL_DETECTORS) tt = "ALL_DETECTORS";
     if(fsv_m == ONLY_PRIMARIES) tt = "ONLY_PRIMARIES";
     cout<<"                 Save mode: "<<tt<<endl;
  };

};
#endif //OPT_RUN_MODE_H


#ifndef OPT_PRIMARY_MODE_H
#define OPT_PRIMARY_MODE_H

enum Momentum_mode{ FIXED, FLAT, POWERLAW}; 
enum Momentum_units{ GV_p, GV_R, GeV_T}; 
enum Nevents_mode { NEV_TOT, NEV_ACCEPT, NEV_TRIGG };

struct pPrimaryModeOpt : public TObject {
  Bool_t fread_mode; // 0 - generate primary kinematics, 1 -read from file;
  TString fread_path; // path to file with primary kinematics
  Int_t fpdg; //PDG code of  primary
  Bool_t fspt_mode; // 0 - dome; 1 - user defined angles and vertex point
  Bool_t fvert_mode; //0 - fixed point, 1 - vertex box
  Bool_t fang_mode; // 0 - fixed angle, 1 - isotropic
  Momentum_mode fmom_mode; // fixed, flat, powerlaw

  Momentum_units funits; // GV_p, GV_R, GeV
  Double_t fmom_fix; //Momentum, Rig, Kine
  Double_t fmom_min, fmom_max, fgamma; //momentum for flat case

  Nevents_mode fnv_m; //Total, accept, trigg
  Int_t fnevents; //number of events

  //Spatial and angular coordinates for fixed-isotropic case
  Double_t fx0, fy0, fz0, fx0_min, fx0_max, fy0_min, fy0_max, fz0_min, fz0_max;
  Double_t ftheta, fphi, ftheta_min, ftheta_max, fphi_min, fphi_max;

  pPrimaryModeOpt(Bool_t read_mode, TString read_path, Int_t pdg, Bool_t spt_mode, Bool_t vert_mode, Bool_t ang_mode,
		  Momentum_mode mom_mode, Momentum_units units, Double_t mom_fix, Double_t mom_min, Double_t mom_max,
		  Double_t gamma, Nevents_mode nv_m, Int_t nevents, Double_t x0, Double_t y0, Double_t z0,
		  Double_t x0_min, Double_t x0_max, Double_t y0_min, Double_t y0_max, Double_t z0_min, Double_t z0_max,
		  Double_t theta, Double_t phi, Double_t theta_min, Double_t theta_max, Double_t phi_min, Double_t phi_max):
  fread_mode(read_mode), fread_path(read_path), fpdg(pdg), fspt_mode(spt_mode), fvert_mode(vert_mode), fang_mode(ang_mode),
    fmom_mode(mom_mode), funits(units), fmom_fix(mom_fix), fmom_min(mom_min), fmom_max(mom_max), fgamma(gamma),
    fnv_m(nv_m), fnevents(nevents), fx0(x0), fy0(y0), fz0(z0), fx0_min(x0_min), fx0_max(x0_max), fy0_min(y0_min), fy0_max(y0_max),
    fz0_min(z0_min),fz0_max(z0_max), ftheta(theta), fphi(phi), ftheta_min(theta_min), ftheta_max(theta_max), 
    fphi_min(phi_min), fphi_max(phi_max){ ; }

   virtual void Print(const Option_t* = "") const {
     cout<<"--->Primary Options: "<<endl;
     if( fread_mode ){
       cout<<"             Reading kinematics from file: "<<fread_path<<endl;
       cout<<"                       NEVENTS to process: all events from file"<<endl;
     } else {
       cout<<"             PDG: "<<fpdg<<endl;
       if(! fspt_mode ) {
	 cout<<"             Spatial distribution: Generation Over the Dome (GOD mode) "<<endl;
       } else {
	 cout<<"             Spatial distribution: User-defined "<<endl;
	 if( fvert_mode ){
	   cout<<"             Vertex distribution: Parallelepiped ( x_min, x_max, y_min, y_max, z_min, z_max) = ("
	       <<fx0_min<<", "<<fx0_max<<", "<<fy0_min<<", "<<fy0_max<<", "<<fz0_min<<", "<<fz0_max<<" ) (cm)"<<endl;
	 } else {
	   cout<<"             Vertex distribution: Fixed Point ( "<<fx0<<", "<<fy0<<", "<<fz0<<" ) (cm)"<<endl;

	 }
	 if( fang_mode ){
	   cout<<"             Angular distribution: Isotropic (theta_min, theta_max, phi_min, phi_max) =  ( "
	       <<ftheta_min<<", "<<ftheta_max<<", "<<fphi_min<<", "<<fphi_max<<" ) (rad)"<<endl;
	 } else {
	   cout<<"             Angular distribution: Fixed Angles (theta, phi) =  ( "<<ftheta<<", "<<fphi<<" ) (rad)"<<endl;
	 }
       }
       TString un;
       TString un_det;
       if (funits == GV_p){
	 un = "GV (p)";
	 un_det = "Momentum";
       }
       if (funits == GV_R){
	 un = "GV (R)";
	 un_det = "Rigidity";
       }
       if (funits == GeV_T){
	 un = "GeV_T";
	 un_det = "Kinetic energy";
       }
       if( fmom_mode == FIXED ){
	 cout<<"             "<<un_det<<" distribution: Fixed "<< fmom_fix<<" "<<un<<endl;
       }
       if( fmom_mode == FLAT ){
	 cout<<"             "<<un_det<<" distribution: Flat ( "<<fmom_min<<", "<<fmom_max<<" ) "<<un<<endl;
       }
       if( fmom_mode == POWERLAW ){
	 cout<<"             "<<un_det<<" distribution: Power-law ( "<<fmom_min<<", "<<fmom_max<<" ) "<<un<<" gamma: "<<fgamma<<endl;
       }
       
       TString nev_cond;
       if(  fnv_m ==  NEV_TOT ) nev_cond = " TOTAL"; 
       if(  fnv_m ==  NEV_ACCEPT ) nev_cond = " IN ACCEPTANCE"; 
       if(  fnv_m ==  NEV_TRIGG ) nev_cond = " TRIGGERED"; 
       cout<<"             NEVENTS to process: "<<fnevents<<nev_cond<<endl;
     }
   }
};
#endif //OPT_PRIMARY_MODE_H
