#ifndef PAMVMCOPTMGR_H
#define PAMVMCOPTMGR_H
#include <iostream>
#include <stdio.h>
#include <stdlib.h>

#include <TSystem.h>
#include <TMap.h>
#include <TObjString.h>
#include <TDOMParser.h>
#include <TXMLAttr.h>
#include <TXMLNode.h>


#include "PamVMCOptions.h"
using namespace std;

class PamVMCOptMgr: public TObject {

 private:
 
  static PamVMCOptMgr * fopt;
  TMap foptmap;

  void SetOpt(const char *name, TObject *value){
    foptmap.Add(new TObjString(name),value);
  }
  
  void ParseOptions(TXMLNode *node);
  pInitModeOpt * ParseInitOpt(TXMLNode *node);
  pRandomModeOpt * ParseRandomOpt(TXMLNode *node);
  pRuntimeModeOpt * ParseRuntimeOpt(TXMLNode *node);
  pPrimaryModeOpt * ParsePrimaryOpt(TXMLNode *node);
 protected:
  PamVMCOptMgr(){
    ParseOptions(0);
  }

 public:

  ~PamVMCOptMgr(){ foptmap.DeleteAll(); }
  
  static PamVMCOptMgr * Instance();

  TObject * GetOpt(const char *name){
    return foptmap(name);
  }
  
  virtual void Print(const Option_t* = "") const { foptmap.Print(); }

  Int_t ParseFile(TString filename) {
      TDOMParser *domParser = new TDOMParser();
      Int_t parsecode = domParser->ParseFile(filename);

      if (parsecode < 0) {
         cerr << domParser->GetParseCodeMessage(parsecode) << endl;
         return -1;
      }

      TXMLNode * node = domParser->GetXMLDocument()->GetRootNode();

      ParseOptions(node);

      return 0;
   }


  //Different getters
  
  //INIT Options
  TString GetOutPath(){
    return  ((pInitModeOpt*)GetOpt("Init_mode_set"))->fout_path;
  }
  TString GetOutPattern(){
    return  ((pInitModeOpt*)GetOpt("Init_mode_set"))->fout_file_pattern;
  }
  TString GetOutPatternFull(){
    TString tmp = ((pInitModeOpt*)GetOpt("Init_mode_set"))->fout_path;
    tmp += "/";
    tmp += ((pInitModeOpt*)GetOpt("Init_mode_set"))->fout_file_pattern;
    return  tmp;
  }
  TString GetTmpPath(){
    return  ((pInitModeOpt*)GetOpt("Init_mode_set"))->fout_tmp_dir;
  }

  Bool_t IsUseCookie(){
    return ((pInitModeOpt*)GetOpt("Init_mode_set"))->fuse_pbs_jobcookie;
  }

  Bool_t IsNoCalo(){
    return ((pInitModeOpt*)GetOpt("Init_mode_set"))->fuse_nocalo;
  }

  TString GetG4ConfigC(){
    TString tmp = ((pInitModeOpt*)GetOpt("Init_mode_set"))->fg4Config_path;
    tmp += "/";
    tmp += ((pInitModeOpt*)GetOpt("Init_mode_set"))->fg4Config_C_name;
    return tmp;
  }

  TString GetG4ConfigIn(){
    TString tmp = ((pInitModeOpt*)GetOpt("Init_mode_set"))->fg4Config_path;
    tmp += "/";
    tmp += ((pInitModeOpt*)GetOpt("Init_mode_set"))->fg4Config_in_name;
    return tmp;
  }

  //RANDOM OPTIONS

  Bool_t IsReadRandomMode(){
    /* 0 - generate, 1 - read from file */
    return ((pRandomModeOpt*)GetOpt("Random_mode_set"))->fread_from_file_mode;
  }
  
  Bool_t IsUserRandomMode(){
    /* 1 - generate random use user-defined seeds, 0 - autogenerate them */
    return ((pRandomModeOpt*)GetOpt("Random_mode_set"))->fgenerate_g4_seed_user;
  }

  void GetUserRandomSeed(Int_t & seed1, Int_t & seed2){
    seed1 = ((pRandomModeOpt*)GetOpt("Random_mode_set"))->fseed1;
    seed2 = ((pRandomModeOpt*)GetOpt("Random_mode_set"))->fseed2;
  }
  Bool_t DoWriteRandom(){
    /* 0 - don't save g4 random snapshots into root-file, 1 - do it */
    return ((pRandomModeOpt*)GetOpt("Random_mode_set"))->fwrite_to_file_mode;
  }
  TString GetRandomOutFile(){
    TString tmp = ((pRandomModeOpt*)GetOpt("Random_mode_set"))->fwrite_g4_rnd_path;
    tmp += "/";
    tmp += ((pRandomModeOpt*)GetOpt("Random_mode_set"))->fwrite_g4_rnd_filename;
    return  tmp;
  }
  TString GetRandomOutFilename(){
    return ((pRandomModeOpt*)GetOpt("Random_mode_set"))->fwrite_g4_rnd_filename;
  }
  TString GetRandomInFilename(){
    return ((pRandomModeOpt*)GetOpt("Random_mode_set"))->fread_g4_seed_path;
  }

  //RUNTIME OPTIONS

  Int_t GetVerboseLevel(){
    return ((pRuntimeModeOpt*)GetOpt("Runtime_mode_set"))->fverbose_lev;
  }
  Int_t GetMaxSteps(){
    return ((pRuntimeModeOpt*)GetOpt("Runtime_mode_set"))->fmaxstep;
  }
  Save_cond GetSaveCond(){
    return ((pRuntimeModeOpt*)GetOpt("Runtime_mode_set"))->fsv_c;
  }
  Save_mode GetSaveMode(){
    return ((pRuntimeModeOpt*)GetOpt("Runtime_mode_set"))->fsv_m;
  }

  //PRIMARY OPTIONS
  Bool_t GetReadPrimMode(){
    return ((pPrimaryModeOpt*)GetOpt("Primary_mode_set"))->fread_mode;
  }
  TString GetReadPrimPath(){
    return ((pPrimaryModeOpt*)GetOpt("Primary_mode_set"))->fread_path;
  }
  Int_t GetPrimPDG(){
    return ((pPrimaryModeOpt*)GetOpt("Primary_mode_set"))->fpdg;
  }

  Momentum_mode GetPrimMomMode(){
    return ((pPrimaryModeOpt*)GetOpt("Primary_mode_set"))->fmom_mode;
  }

  Momentum_units GetPrimMomUnits(){
    return ((pPrimaryModeOpt*)GetOpt("Primary_mode_set"))->funits;
  }

  Double_t GetMomFixed(){
    return ((pPrimaryModeOpt*)GetOpt("Primary_mode_set"))->fmom_fix;
  }

  void GetMomLimits( Double_t & min, Double_t & max){
    min = ((pPrimaryModeOpt*)GetOpt("Primary_mode_set"))->fmom_min;
    max = ((pPrimaryModeOpt*)GetOpt("Primary_mode_set"))->fmom_max;
  }

  Double_t GetMomGamma(){
    return ((pPrimaryModeOpt*)GetOpt("Primary_mode_set"))->fgamma;
  }
  
  Bool_t IsCustomKinematics(){
    return ((pPrimaryModeOpt*)GetOpt("Primary_mode_set"))->fspt_mode;
  }
  Bool_t IsBoxVertex(){
    return ((pPrimaryModeOpt*)GetOpt("Primary_mode_set"))->fvert_mode;
  }
  
  void GetFixedPointVertex( Double_t &x0, Double_t &y0, Double_t &z0 ){
    x0 = ((pPrimaryModeOpt*)GetOpt("Primary_mode_set"))->fx0;
    y0 = ((pPrimaryModeOpt*)GetOpt("Primary_mode_set"))->fy0;
    z0 = ((pPrimaryModeOpt*)GetOpt("Primary_mode_set"))->fz0;
  }

  void GetBoxVertex( Double_t &x0_min, Double_t &x0_max,
		     Double_t &y0_min, Double_t &y0_max,
		     Double_t &z0_min, Double_t &z0_max ){
    x0_min = ((pPrimaryModeOpt*)GetOpt("Primary_mode_set"))->fx0_min;
    x0_max = ((pPrimaryModeOpt*)GetOpt("Primary_mode_set"))->fx0_max;
    y0_min = ((pPrimaryModeOpt*)GetOpt("Primary_mode_set"))->fy0_min;
    y0_max = ((pPrimaryModeOpt*)GetOpt("Primary_mode_set"))->fy0_max;
    z0_min = ((pPrimaryModeOpt*)GetOpt("Primary_mode_set"))->fz0_min;
    z0_max = ((pPrimaryModeOpt*)GetOpt("Primary_mode_set"))->fz0_max;
  }

  Bool_t IsIsotropicPlane(){
    return ((pPrimaryModeOpt*)GetOpt("Primary_mode_set"))->fang_mode;
  }

  void GetFixedAngles( Double_t &theta, Double_t &phi){
    theta = ((pPrimaryModeOpt*)GetOpt("Primary_mode_set"))->ftheta;
    phi = ((pPrimaryModeOpt*)GetOpt("Primary_mode_set"))->fphi;
  }
  void GetIsotropicAngles( Double_t &theta_min, Double_t &theta_max, 
			   Double_t &phi_min, Double_t &phi_max ){
    theta_min = ((pPrimaryModeOpt*)GetOpt("Primary_mode_set"))->ftheta_min;
    theta_max = ((pPrimaryModeOpt*)GetOpt("Primary_mode_set"))->ftheta_max;
    phi_min = ((pPrimaryModeOpt*)GetOpt("Primary_mode_set"))->fphi_min;
    phi_max = ((pPrimaryModeOpt*)GetOpt("Primary_mode_set"))->fphi_max;
  }

  Nevents_mode GetStopMode(){
    return ((pPrimaryModeOpt*)GetOpt("Primary_mode_set"))->fnv_m;
  }

  Int_t GetEvMax(){
    return ((pPrimaryModeOpt*)GetOpt("Primary_mode_set"))->fnevents;
  }

  ClassDef(PamVMCOptMgr,1);


};

#endif
