///////////////////////////////////////////////////////////////////
//
// Event simulation
//
// Author: Glenn Horton-Smith
//
// REVISION HISTORY:
//     24 Feb 2010 : Gabriel Orebi Gann - Inclusion of PMT noise hits:
//                Basic version taken from (the now obsolete) NoiseProc
//                Plus alterations:
//                - Timing distribution corrected to distribute noise hits from 200ns
//                before first photon hit to (200ns + trigger_window) after the last
//                - Read in noise rate (Hz) from database, instead of number of hits.
//                - Correct noise rate for average channel efficiency (taken from new routine
//                in geo/DetectorConstruction).
//                - Include option for different noise models: off, average rate or per-PMT
//                with the per-PMT reading in individual tube noise rates and correcting
//                by individual PMT channel efficiencies.
//     25 Feb 2010 : Gabriel Orebi Gann - Add front end times to noise hits.
//     05 Mar 2010 : Gabriel Orebi Gann - Remove all reference to DAQTHRESH.ratdb file
//                - Read in noiserate array from DAQ.ratdb instead
//                - Calculate channel thresholds from DQXX info directly
//                - Include flag (from DAQ.ratdb) to check whether we want to use DQXX
//                info to determine whether each PMT is online.
//                - If so, do not record noise hits on those that aren't.
//                - Include flag (from DAQ.ratdb) to determine which
//                experimental definitions to use for a tube being online
//                (in case SNO+ uses a different definition from SNO, this
//                allows us still to do comparisons to SNOMAN MC).
//     02 Apr 2010 : Gabriel Orebi Gann - Add real time to MC (i.e. date etc).
//     09 Apr 2010 : Gabriel Orebi Gann - Fill date/time into run header.
//     12 Apr 2010 : Gabriel Orebi Gann - Move noise control to new ratdb file.
//     10 Sep 2010 : Gabriel Orebi Gann - Init. DQXX before PMTCharge (now that
//                   PMTCharge uses DQXX info to determine tube status).
//     04 Mar 2011 : P G Jones - New messenger class
//     01 Jul 2012 : Nuno Barros - Added run time control.
//                   settings from new table (DAQ_RUN_LEVEL)
//     01 Dec 2014 : W Heintzelman - add fAuxiliarySim flag (for use by
//                   PEnergy fitter) so normal EndOfEvent processing is skipped
//                   for an auxiliary simulation
//     19 May 2015 : J Walker - Added flasher generator.
//     30 Sep 2016 : W Heintzelman - add registration of GenPMTEff generator
//     16 Oct 2016 : N Barros - Cleaned up code.
//                   Removed superfluous headers
//                   Expanded CLHEP unit system in RAT
//                   Added reactor generator
//     04 Jan 2017 : F Descamps - Changed time format in RUN.ratdb
//
///////////////////////////////////////////////////////////////////

#ifndef __RAT_Gsim__
#define __RAT_Gsim__

#include <G4UserRunAction.hh>
#include <G4UserEventAction.hh>
#include <G4PrimaryParticle.hh>

#include <RAT/Producer.hh>
#include <RAT/EventTime.hh>
#include <RAT/DB.hh>
#include <RAT/DS/Run.hh>
#include <RAT/Noise.hh>
#include <RAT/AfterPulse.hh>
#include <RAT/Profiler.hh>
#ifdef USE_CHROMA
#include <RAT/Chroma.hh>
#endif

#include <string>

class G4Run;
class G4RunManager;

namespace RAT {

class ProcBlock;
class Detector;
class GsimMessenger;
class SteppingAction;

namespace DS
{
  class Entry;
}

int get_pdgcode(const G4PrimaryParticle *p);

class Gsim : public Producer, G4UserRunAction, G4UserEventAction
{
  static std::string fHostname;
  static std::string fMachineType;

  // Non static aspects
public:
  Gsim();
  Gsim(ProcBlock *theMainBlock);
  virtual ~Gsim();

  // G4UserRunAction methods
  virtual void BeginOfRunAction(const G4Run* aRun);
  virtual void EndOfRunAction(const G4Run* aRun);

  // G4UserEventAction methods
  virtual void BeginOfEventAction(const G4Event* anEvent);
  virtual void EndOfEventAction(const G4Event* anEvent);

  // Convert G4Event into DS::Entry
  void MakeEvent(const G4Event *g4ev, DS::Entry& ds);

  // Set The discard optical photons flag
  void SetDiscardOpticalPhotons( bool state ) { fDiscardOpticalPhotons = state; };

  // Set the flag to skip BeginOfRunAction, BeginOfEventAction, and
  // EndOfEventAction processing.
  // Used for auxiliary-event simulations, e.g., in the PEnergy energy fitter.
  void SetAuxiliarySim( bool state ) { fAuxiliarySim = state; };
  bool GetAuxiliarySim() { return fAuxiliarySim; };

  // get the pointer to chroma photon propagation interface
  #ifdef USE_CHROMA
  Chroma* GetChroma() { return chroma; }
  #endif

  DS::Run* GetRun() {return &fRun;}

  void SetRunDuration(double duration) {fTimedRun = true; fRunDuration = duration;}
  double GetRunDuration() {return fRunDuration;}
  bool IsTimedRun() {return fTimedRun;};

  void SetRunNumberOverride(long run_number) {fRunNumberOverride = run_number;}
  long GetRunNumberOverride() {return fRunNumberOverride;}

  void SetSubrunNumberOverride(long subrun_number) {fSubRunNumberOverride = subrun_number;}
  long GetSubrunNumberOverride() {return fSubRunNumberOverride;}

  void SetRunSimMode(bool status=true) { fRunMcMode = status; if (status) fTimedRun = true;}
  bool GetRunSimMode() const { return fRunMcMode;}

protected:
  void Init(); // the real constructor

  void ExpandUnitsTable();
  //DBLinkPtr fdaqThresh;
  std::vector<float> fChanThresh;
  int fNumThresh;

  Noise fNoise; // GDOG: For noise hit calculation
  AfterPulse fAfterPulse;

  DBLinkPtr fRLdaq;
  DBLinkPtr fLdaq;

  EventTime fEventTime;

  #ifdef USE_CHROMA
  Chroma* chroma;   // Chroma photon propagation interface
  #endif

  G4RunManager *fRunManager;
  Detector *fTheDetector;
  GsimMessenger* fGsimMessenger;

  bool fDiscardOpticalPhotons;
  bool fAuxiliarySim;  //  Set true to skip end-of-event processing

  // For run time duration control
  G4double fRunDuration;
  G4bool fTimedRun;

  DS::Run fRun; // The current run

  Profiler fEventOutputProfile; // Profiled event output times
  Profiler fEventSimProfile; // Profiled event simulation times
  Profiler fEventBuildProfile; // Profiled event building times
  Profiler fRunProfile; // Time take for whole runs
  long fRunNumberOverride;
  long fSubRunNumberOverride;
  bool fRunMcMode;

  SteppingAction *fSteppingAction;
};


} // namespace RAT

#endif