#include <iostream>
#include <TString.h>
#include <TPDGCode.h>
#include <TMath.h>
#include "PamVMCOptMgr.h"

ClassImp(PamVMCOptMgr)

using std::cout;
using std::endl;
using TMath::Pi;
using TMath::TwoPi;

PamVMCOptMgr * PamVMCOptMgr::fopt = 0;

PamVMCOptMgr * PamVMCOptMgr::Instance(){

  if(fopt == 0) {
    fopt = new PamVMCOptMgr();
  }
  return fopt;
}
 
void PamVMCOptMgr::ParseOptions(TXMLNode *node){

  foptmap.DeleteAll();
  
  
  if( node ){
    if (strcmp(node->GetNodeName(), "Main_settings") == 0) {
      
      TXMLNode* ch_node=node->GetChildren();
      for (; ch_node; ch_node = ch_node->GetNextNode()) {
	if (ch_node->GetNodeType() == TXMLNode::kXMLElementNode) { // Element Node
	  if (strcmp(ch_node->GetNodeName(), "Init_mode_set") == 0) {
	    SetOpt("Init_mode_set",ParseInitOpt(ch_node->GetChildren()));
	  }
	  if (strcmp(ch_node->GetNodeName(), "Random_mode_set") == 0) {
	    SetOpt("Random_mode_set",ParseRandomOpt(ch_node->GetChildren()));
	  }
	  if (strcmp(ch_node->GetNodeName(), "Runtime_mode_set") == 0) {
	    SetOpt("Runtime_mode_set",ParseRuntimeOpt(ch_node->GetChildren()));
	  }
	  if (strcmp(ch_node->GetNodeName(), "Primary_mode_set") == 0) {
	    SetOpt("Primary_mode_set",ParsePrimaryOpt(ch_node->GetChildren()));
	  }
	}
      }
    }
  } else {
    SetOpt("Init_mode_set",ParseInitOpt(0));
    SetOpt("Random_mode_set",ParseRandomOpt(0));
    SetOpt("Runtime_mode_set",ParseRuntimeOpt(0));
    SetOpt("Primary_mode_set",ParsePrimaryOpt(0));
  }
}


pInitModeOpt * PamVMCOptMgr::ParseInitOpt(TXMLNode *node){
  //defaults
  TString PAM_VMC = gSystem->Getenv("PAM_VMC");
  TString path = PAM_VMC+"/config";
  TString path_tmp = PAM_VMC+"/examples";
  TString path_out = PAM_VMC+"/examples";
  TString filepattern = "out";
  TString C_name = "g4Config.C";
  TString in_name = "g4config2.in";
  Bool_t use_cookies = 0;
  Bool_t use_nocalo = kFALSE;


  if( node ){
    for ( ; node; node = node->GetNextNode()) {
      if ( (node->GetNodeType() == TXMLNode::kXMLElementNode) ) { // Element Node
	TString val = node->GetText();
	if( val.Length()){
	  if (strcmp(node->GetNodeName(), "g4Config_path") == 0){
	    path =  val;
	  }
	  if (strcmp(node->GetNodeName(), "g4Config_C_name") == 0){
	    C_name =  val;
	  }
	  if (strcmp(node->GetNodeName(), "g4Config_in_name") == 0){
	    in_name =  val;
	  }
	  if (strcmp(node->GetNodeName(), "use_pbs_jobcookie") == 0){
	    use_cookies = kTRUE;
	    TXMLNode *node_ch = node->GetChildren();
	    for ( ; node_ch; node_ch = node_ch->GetNextNode()) {
	      if (strcmp(node_ch->GetNodeName(), "out_tmp_dir") == 0){
		path_tmp = node_ch->GetText();
	      }
	    }
	  }
	  if (strcmp(node->GetNodeName(), "out_path") == 0){
	    path_out = val;
	  }
	  if (strcmp(node->GetNodeName(), "out_file_pattern") == 0){
	    filepattern = val;
	  }
	}	  
	if (strcmp(node->GetNodeName(), "dont_use_pbs_jobcookie") == 0){
	  use_cookies = kFALSE;
	}
	if (strcmp(node->GetNodeName(), "use_nocalo") == 0){
	  cout << "Found nocalo flag" << endl;
	  use_nocalo = kTRUE;
	}
      }
    }
  }
  return new pInitModeOpt( path, C_name, in_name, use_cookies, use_nocalo, path_tmp, path_out, filepattern );
}


pRandomModeOpt * PamVMCOptMgr::ParseRandomOpt(TXMLNode *node){
  //defaults
  Bool_t read_f_mode = kFALSE;
  TString PAM_VMC = gSystem->Getenv("PAM_VMC");
  TString read_g4_seed_path=PAM_VMC+"/examples/radom_dump.root";
  Bool_t custom_gen = kFALSE;
  Int_t seed1 = 1000;
  Int_t seed2 = 1001;
  Bool_t write_mode = kFALSE;
  TString write_path = PAM_VMC+"/examples";
  TString writename = "random_dump.root";

  if( node ){
    for ( ; node; node = node->GetNextNode()) {
      if ( (node->GetNodeType() == TXMLNode::kXMLElementNode) ) { // Element Node
	TString val = node->GetText();
	if( val.Length()){
	  if (strcmp(node->GetNodeName(), "generate_g4_seed") == 0){
	    read_f_mode = kFALSE;
	    TXMLNode *node_ch = node->GetChildren();
	    for ( ; node_ch; node_ch = node_ch->GetNextNode()) {
	      if (strcmp(node_ch->GetNodeName(), "auto_g4_seed") == 0){
		custom_gen = kFALSE;
	      }
	      if (strcmp(node_ch->GetNodeName(), "dont_save_g4rnd_in_file") == 0){
		write_mode = kFALSE;
	      }
	      if (strcmp(node_ch->GetNodeName(), "save_g4rnd_in_file") == 0){
		write_mode = kTRUE;
		TXMLNode *node_ch2 = node_ch->GetChildren();
		for ( ; node_ch2; node_ch2 = node_ch2->GetNextNode()) {
		  TString val_ch2 = node_ch2->GetText();
		  if (val_ch2.Length()){
		    if (strcmp(node_ch2->GetNodeName(), "g4_rnd_path") == 0){
		      write_path = node_ch2->GetText();
		    }
		    if (strcmp(node_ch2->GetNodeName(), "g4_rnd_filename") == 0){
		      writename = node_ch2->GetText();	      
		    }
		  }
		}
	      }
	      
	      TString val_ch = node_ch->GetText();
	      if (val_ch.Length()){
		if (strcmp(node_ch->GetNodeName(), "init_g4_seed1") == 0){
		  custom_gen = kTRUE;
		  seed1 = atoi(val_ch);
		}
		if (strcmp(node_ch->GetNodeName(), "init_g4_seed2") == 0){
		  custom_gen = kTRUE;
		  seed2 = atoi(val_ch);
		}
	      }
	    }
	  }
	  if (strcmp(node->GetNodeName(), "read_g4_seed_filepath") == 0){
	    read_f_mode = kTRUE;
	    read_g4_seed_path = val;
	  }
	
	
	}
      }
    }
  }
  
  return new pRandomModeOpt( read_f_mode,  read_g4_seed_path, custom_gen, seed1, seed2, write_mode, write_path, writename );
}

pRuntimeModeOpt * PamVMCOptMgr::ParseRuntimeOpt(TXMLNode *node){
  //defaults
  Int_t verbose_lev = 0;
  Int_t maxstep = 50000;
  Save_cond sv_c = EVERYTHING;
  Save_mode sv_m = ALL_DETECTORS;

  
  if( node ){
    for ( ; node; node = node->GetNextNode()) {
      if ( (node->GetNodeType() == TXMLNode::kXMLElementNode) ) { // Element Node
	TString val = node->GetText();
	if( val.Length()){
	  if (strcmp(node->GetNodeName(), "verbose_level") == 0){
	    verbose_lev = atoi(val);
	  }
	  if (strcmp(node->GetNodeName(), "maxstep") == 0){
	    maxstep = atoi(val);
	  }
	  if (strcmp(node->GetNodeName(), "save_condition") == 0){
	    TXMLNode *node_ch = node->GetChildren();
	    for ( ; node_ch; node_ch = node_ch->GetNextNode()) {
	      if (strcmp(node_ch->GetNodeName(), "accept_only") == 0) sv_c = ACCEPT_ONLY;
	      if (strcmp(node_ch->GetNodeName(), "trig_only") == 0) sv_c = TRIG_ONLY;
	      if (strcmp(node_ch->GetNodeName(), "everything") == 0) sv_c = EVERYTHING;
	    }
	  }
	  if (strcmp(node->GetNodeName(), "save_mode") == 0){
	    TXMLNode *node_ch = node->GetChildren();
	    for ( ; node_ch; node_ch = node_ch->GetNextNode()) {
	      if (strcmp(node_ch->GetNodeName(), "all_detectors") == 0) sv_m = ALL_DETECTORS;
	      if (strcmp(node_ch->GetNodeName(), "only_primaries") == 0) sv_m = ONLY_PRIMARIES;
	    }
	  }
	  
	}
	
      }
    }
  }
  return new pRuntimeModeOpt(verbose_lev, maxstep, sv_c, sv_m );
}


pPrimaryModeOpt * PamVMCOptMgr::ParsePrimaryOpt(TXMLNode *node){
  //defaults
  Bool_t read_mode = kFALSE; //0 - generate primary kinematics, 1 -read from file;
  TString read_path = "/set/path/to/kine.root"; // path to file with primary kinematics
  Int_t pdg = kProton; //PDG code of  primary
  Bool_t spt_mode = kTRUE; // 0 - dome; 1 - user defined angles and vertex point
  Bool_t vert_mode = kFALSE; //0 - fixed point, 1 - vertex box
  Bool_t ang_mode = kFALSE; // 0 - fixed angle, 1 - isotropic
  Momentum_mode mom_mode = FIXED; // fixed, flat, powerlaw

  Momentum_units units = GV_R; // GV_p, GV_R, GeV_T
  Double_t mom_fix = 1.; //Momentum, Rig, Kine
  Double_t mom_min = 1.;
  Double_t mom_max = 2.; 
  Double_t gamma = 2.75; 

  Nevents_mode nv_m = NEV_TOT; //Total, accept, trigg
  Int_t nevents = 100; //number of events

  //Spatial and angular coordinates for fixed-isotropic case
  Double_t x0 = 0.;
  Double_t y0 = 0.;
  Double_t z0 = 130.;
  Double_t x0_min = -40.;
  Double_t x0_max = 40.;
  Double_t y0_min = -40.;
  Double_t y0_max = 40.;
  Double_t z0_min = 130.;
  Double_t z0_max = 130.;
  Double_t theta = 0.;
  Double_t phi = 0.;
  Double_t theta_min = 0.;
  Double_t theta_max = Pi()/2.;
  Double_t phi_min = 0.;
  Double_t phi_max = TwoPi();
  
  if( node ){
    for ( ; node; node = node->GetNextNode()) {
      if ( (node->GetNodeType() == TXMLNode::kXMLElementNode) ) { // Element Node
	if (strcmp(node->GetNodeName(), "read_from_file") == 0){
	  read_mode = kTRUE;
	  TString val = node->GetText();
	  if (val.Length() ) read_path = val;
	}
	if (strcmp(node->GetNodeName(), "define_primaries") == 0){
	  read_mode = kFALSE;
	  TXMLNode *node_ch = node->GetChildren();
	  for ( ; node_ch; node_ch = node_ch->GetNextNode()) {
	    if (strcmp(node_ch->GetNodeName(), "particle_type") == 0){
	      TXMLNode *node_ch2 = node_ch->GetChildren();
	      for ( ; node_ch2; node_ch2 = node_ch2->GetNextNode()) {
		if (strcmp(node_ch2->GetNodeName(), "kProton") == 0){
		  pdg = kProton;
		}
		if (strcmp(node_ch2->GetNodeName(), "H-2") == 0){
		  pdg = 1000010020;
		}
		if (strcmp(node_ch2->GetNodeName(), "H-3") == 0){
		  pdg = 1000010030;
		}
		if (strcmp(node_ch2->GetNodeName(), "He-3") == 0){
		  pdg = 1000020030;
		}
		if (strcmp(node_ch2->GetNodeName(), "He-4") == 0){
		  pdg = 1000020040;
		}
		if (strcmp(node_ch2->GetNodeName(), "user_pdg") == 0){
		  TString val2 = node_ch2->GetText();
		  if( val2.Length() ) pdg = atoi(val2);
		}
	      }
	    }
	    if (strcmp(node_ch->GetNodeName(), "gen_mode") == 0){
	      TXMLNode *node_ch2 = node_ch->GetChildren();
	      for ( ; node_ch2; node_ch2 = node_ch2->GetNextNode()) {
		if (strcmp(node_ch2->GetNodeName(), "user_defined") == 0){
		  spt_mode = kTRUE;
		  TXMLNode *node_ch3 = node_ch2->GetChildren();
		  for ( ; node_ch3; node_ch3 = node_ch3->GetNextNode()) {
		    
		    //spatial
		    if (strcmp(node_ch3->GetNodeName(), "vertex_mode") == 0){
		      TXMLNode *node_ch4 = node_ch3->GetChildren();
		      for ( ; node_ch4; node_ch4 = node_ch4->GetNextNode()) {
			if (strcmp(node_ch4->GetNodeName(), "vertex_box") == 0){
			  vert_mode = kTRUE;
			  TXMLNode *node_ch5 = node_ch4->GetChildren();
			  for ( ; node_ch5; node_ch5 = node_ch5->GetNextNode()) {
			    TString val5 = node_ch5->GetText();
			    if( val5.Length()){
			      if (strcmp(node_ch5->GetNodeName(), "x0_min") == 0) x0_min = atof(val5);
			      if (strcmp(node_ch5->GetNodeName(), "x0_max") == 0) x0_max = atof(val5);
			      if (strcmp(node_ch5->GetNodeName(), "y0_min") == 0) y0_min = atof(val5);
			      if (strcmp(node_ch5->GetNodeName(), "y0_max") == 0) y0_max = atof(val5);   
			      if (strcmp(node_ch5->GetNodeName(), "z0_min") == 0) z0_min = atof(val5);
			      if (strcmp(node_ch5->GetNodeName(), "z0_max") == 0) z0_max = atof(val5);
			    }
			  }
			}
			if (strcmp(node_ch4->GetNodeName(), "vertex_fix_point") == 0){
			  vert_mode = kFALSE;
			  TXMLNode *node_ch5 = node_ch4->GetChildren();
			  for ( ; node_ch5; node_ch5 = node_ch5->GetNextNode()) {
			    TString val5 = node_ch5->GetText();
			    if( val5.Length()){
			      if (strcmp(node_ch5->GetNodeName(), "x0") == 0) x0 = atof(val5);
			      if (strcmp(node_ch5->GetNodeName(), "y0") == 0) y0 = atof(val5);
			      if (strcmp(node_ch5->GetNodeName(), "z0") == 0) z0 = atof(val5);
			    }
			  }	
			}
		      }
		      
		    }
		    
		    //angular
		    if (strcmp(node_ch3->GetNodeName(), "ang_mode") == 0){
		      TXMLNode *node_ch4 = node_ch3->GetChildren();
		      for ( ; node_ch4; node_ch4 = node_ch4->GetNextNode()) {
			if (strcmp(node_ch4->GetNodeName(), "ang_fixed") == 0){
			  ang_mode = kFALSE;
			  TXMLNode *node_ch5 = node_ch4->GetChildren();
			  for ( ; node_ch5; node_ch5 = node_ch5->GetNextNode()) {
			    TString val5 = node_ch5->GetText();
			    if( val5.Length()){
			      if (strcmp(node_ch5->GetNodeName(), "theta") == 0) theta = atof(val5);
			      if (strcmp(node_ch5->GetNodeName(), "phi") == 0) phi = atof(val5);
			    }
			  }	
			}
			if (strcmp(node_ch4->GetNodeName(), "ang_iso") == 0){
			  ang_mode = kTRUE;
			  TXMLNode *node_ch5 = node_ch4->GetChildren();
			  for ( ; node_ch5; node_ch5 = node_ch5->GetNextNode()) {
			    TString val5 = node_ch5->GetText();
			    if( val5.Length()){
			      if (strcmp(node_ch5->GetNodeName(), "theta_min") == 0) theta_min = atof(val5);
			      if (strcmp(node_ch5->GetNodeName(), "phi_min") == 0) phi_min = atof(val5);
			      if (strcmp(node_ch5->GetNodeName(), "theta_max") == 0) theta_min = atof(val5);
			      if (strcmp(node_ch5->GetNodeName(), "phi_max") == 0) phi_min = atof(val5);
			    }
			  }		
			}
		      }
		      
		    }
		    
		    
		  }
		}
		
		
		if (strcmp(node_ch2->GetNodeName(), "dome") == 0){
		  spt_mode = kFALSE;
		}

	      }
	    }
	    
	    //momentum mode
	    if (strcmp(node_ch->GetNodeName(), "momentum_mode") == 0){
	      TXMLNode *node_ch2 = node_ch->GetChildren();
	      for ( ; node_ch2; node_ch2 = node_ch2->GetNextNode()) {
		if (strcmp(node_ch2->GetNodeName(), "momentum_mode_fixed") == 0){
		  mom_mode = FIXED;
		  TXMLNode *node_ch3 = node_ch2->GetChildren();
		  for ( ; node_ch3; node_ch3 = node_ch3->GetNextNode()) {
		    TString val3 = node_ch3->GetText();
		    if( val3.Length()){
		      if (strcmp(node_ch3->GetNodeName(), "P0") == 0) mom_fix = atof(val3);			 
		    }
		  }	
		}
		
		if (strcmp(node_ch2->GetNodeName(), "momentum_mode_flat") == 0){
		  mom_mode = FLAT;
		  TXMLNode *node_ch3 = node_ch2->GetChildren();
		  for ( ; node_ch3; node_ch3 = node_ch3->GetNextNode()) {
		    TString val3 = node_ch3->GetText();
		    if( val3.Length()){
		      if (strcmp(node_ch3->GetNodeName(), "P0_min") == 0) mom_min = atof(val3);			 
		      if (strcmp(node_ch3->GetNodeName(), "P0_max") == 0) mom_max = atof(val3);			 
		    }
		  }	
		}
		
		if (strcmp(node_ch2->GetNodeName(), "momentum_mode_powerlaw") == 0){
		  mom_mode = POWERLAW;
		  TXMLNode *node_ch3 = node_ch2->GetChildren();
		  for ( ; node_ch3; node_ch3 = node_ch3->GetNextNode()) {
		    TString val3 = node_ch3->GetText();
		    if( val3.Length()){
		      if (strcmp(node_ch3->GetNodeName(), "P0_min") == 0) mom_min = atof(val3);			 
		      if (strcmp(node_ch3->GetNodeName(), "P0_max") == 0) mom_max = atof(val3);			 
		      if (strcmp(node_ch3->GetNodeName(), "gamma") == 0) gamma = atof(val3);			 
		    }
		  }	
		}
		
	      }	    
	    }
	    //momentum units
	    if (strcmp(node_ch->GetNodeName(), "momentum_units") == 0){
	      TXMLNode *node_ch2 = node_ch->GetChildren();
	      for ( ; node_ch2; node_ch2 = node_ch2->GetNextNode()) {
		if (strcmp(node_ch2->GetNodeName(), "GV_p") == 0) units = GV_p;			 
		if (strcmp(node_ch2->GetNodeName(), "GV_R") == 0) units = GV_R;			 			 
		if (strcmp(node_ch2->GetNodeName(), "GeV_T") == 0) units = GeV_T;
	      }
	    }
	    //nevents
	    if (strcmp(node_ch->GetNodeName(), "nevents") == 0){
	      TXMLNode *node_ch2 = node_ch->GetChildren();
	      for ( ; node_ch2; node_ch2 = node_ch2->GetNextNode()) {
		TString val2 = node_ch2->GetText();
		if (strcmp(node_ch2->GetNodeName(), "nev_tot") == 0) nv_m = NEV_TOT;			 
		if (strcmp(node_ch2->GetNodeName(), "nev_accept") == 0) nv_m = NEV_ACCEPT;
		if (strcmp(node_ch2->GetNodeName(), "nev_trigg") == 0) nv_m = NEV_TRIGG;
		if(val2.Length()) nevents = atoi(val2);
	      }
	    }
	    
	    
	  }
	}
      }
    }
  }
  return new  pPrimaryModeOpt(read_mode, read_path, pdg, spt_mode, vert_mode, ang_mode,
			      mom_mode, units, mom_fix, mom_min, mom_max, gamma, nv_m,  nevents,  x0,  y0, z0,
			      x0_min,  x0_max, y0_min, y0_max, z0_min, z0_max,  
			      theta,  phi, theta_min, theta_max,  phi_min, phi_max);
}
