// This file is part of the GenericLAND software library.
// $Id$
//
// GLG4PrimaryGeneratorMessenger.cc by Glenn Horton-Smith, Feb. 1999
// updated Aug. 3-17, 2001, for new GLG4PrimaryGeneratorAction

////////////////////////////////////////////////////////////////
// GLG4PrimaryGeneratorMessenger
////////////////////////////////////////////////////////////////

#include <RAT/GLG4PrimaryGeneratorMessenger.hh>
#include <RAT/GLG4PrimaryGeneratorAction.hh>

#include <RAT/Factory.hh>

#include "G4VPhysicalVolume.hh"
#include "G4LogicalVolume.hh"
#include "G4Material.hh"
#include "G4MaterialPropertiesTable.hh"
#include "G4ParticleTable.hh"
#include "G4UIcmdWithAString.hh"
#include "G4UIdirectory.hh"
#include "G4UImanager.hh"
#include "G4ios.hh"
#include "G4Event.hh"
#include "globals.hh"

#include <fstream>  // for file streams
#include <sstream>  // for string streams
#include <iomanip>  // for G4std::setw(), etc..

#include <RAT/GLG4Gen.hh>
#include <RAT/GLG4StringUtil.hh>

#include <local_g4compat.hh>
#include <RAT/ParameterMacros.hh>

#include <CLHEP/Units/SystemOfUnits.h>
//using namespace CLHEP;
#include <RAT/Log.hh>
#include <RAT/StringUtil.hh>

using CLHEP::ns;
using RAT::warn;

GLG4PrimaryGeneratorMessenger::GLG4PrimaryGeneratorMessenger(GLG4PrimaryGeneratorAction* myaction)
:fMyAction(myaction)
{
  G4UIdirectory *GenDir= new G4UIdirectory("/generator/");
  GenDir->SetGuidance("Control the primary event generator.");

  fListCmd = new G4UIcommand("/generator/list",this);

  fEventWindowCmd= new G4UIcommand("/generator/event_window", this);
  fEventWindowCmd->SetGuidance("Set/show event time window");
  fEventWindowCmd->SetParameter(new G4UIparameter("window(ns)",'d',true));

  fGunCmd = new G4UIcommand("/generator/gun",this);
  fGunCmd->SetGuidance("Set/show gun parameters.");
  fGunCmd->SetGuidance("  particle_name:           name of particle");
  fGunCmd->SetGuidance("  x_mm, y_mm, z_mm:        position of gun in mm");
  fGunCmd->SetGuidance("  px_MeV, py_MeV, pz_MeV:  momentum in MeV/c");
  fGunCmd->SetGuidance("  K_MeV:                   kinetic energy override");
  fGunCmd->SetGuidance("  pol_x, pol_y, pol_z:     polarization [optional]");
  fGunCmd->SetGuidance("  mult:                    multiplicity [optional]");
  fGunCmd->SetGuidance("For isotropic, leave px,py,pz zero and set K_MeV.");
  fGunCmd->SetGuidance("For random polarization, leave pol_* zero.");
  fGunCmd->SetGuidance("Note: this command is an alias for the two commands:\n"
   "   /generator/pos/set 9 \"x y z\"\n"
   "   /generator/vtx/set 17 \"particle_name px py pz K polx poly polz mult\"\n"
   "Use the above two commands directly for more control.\n"
   "Type the */set commands with only one argument for current state and help."
                      );

  fGunCmd->SetParameter(new G4UIparameter("particle_name", 's', true));
  fGunCmd->SetParameter(new G4UIparameter("x_mm", 'd', true));
  fGunCmd->SetParameter(new G4UIparameter("y_mm", 'd', true));
  fGunCmd->SetParameter(new G4UIparameter("z_mm", 'd', true));
  fGunCmd->SetParameter(new G4UIparameter("px_MeV", 'd', true));
  fGunCmd->SetParameter(new G4UIparameter("py_MeV", 'd', true));
  fGunCmd->SetParameter(new G4UIparameter("pz_MeV", 'd', true));
  fGunCmd->SetParameter(new G4UIparameter("K_MeV", 'd', true));
  fGunCmd->SetParameter(new G4UIparameter("pol_x", 'd', true));
  fGunCmd->SetParameter(new G4UIparameter("pol_y", 'd', true));
  fGunCmd->SetParameter(new G4UIparameter("pol_z", 'd', true));
  fGunCmd->SetParameter(new G4UIparameter("mult", 'd', true));

  fGenAddCmd = new G4UIcommand("/generator/add", this);
  fGenAddCmd->SetGuidance("Enable and add new event generator to simulation.");
  fGenAddCmd->SetGuidance("Usage: /generator/add generator_name generator_state");

  fGenAddCmd->SetParameter(new G4UIparameter("gen_name", 's', true));
  fGenAddCmd->SetParameter(new G4UIparameter("gen_state", 's', true));

  fGenSetCmd = new G4UIcommand("/generator/set", this);
  fGenSetCmd->SetGuidance("Set the state of the last generator added to simulation.");
  fGenSetCmd->SetGuidance("See the generator documentation for details about the ");
  fGenSetCmd->SetGuidance("specific state commands of each generator.");
  fGenSetCmd->SetGuidance("Usage: /generator/set [generator_state]");
  fGenSetCmd->SetParameter(new G4UIparameter("gen_state", 's', true));


  fRateSetCmd= new G4UIcommand("/generator/rate/set",this);
  fRateSetCmd->SetGuidance("Set generator rate");
  fRateSetCmd->SetParameter(new G4UIparameter("setting", 's', true));

  fVtxSetCmd= new G4UIcommand("/generator/vtx/set",this);
  fVtxSetCmd->SetGuidance("Set vertex generator state");
  fVtxSetCmd->SetParameter(new G4UIparameter("setting", 's', true));

  fPosSetCmd= new G4UIcommand("/generator/pos/set",this);
  fPosSetCmd->SetGuidance("Set position generator state");
  fPosSetCmd->SetParameter(new G4UIparameter("setting", 's', true));


  fLastGen = 0;
}


GLG4PrimaryGeneratorMessenger::~GLG4PrimaryGeneratorMessenger()
{
  delete fListCmd;
  delete fGunCmd;
  delete fGenAddCmd;
  delete fGenSetCmd;
  delete fRateSetCmd;
  delete fVtxSetCmd;
  delete fPosSetCmd;
  delete fEventWindowCmd;

}

void GLG4PrimaryGeneratorMessenger::
SetNewValue(G4UIcommand * command,G4String newValues)
{
  G4String first, rest;

  if (command == fListCmd) {
  } else if (command == fGunCmd) {
  } else if (command == fGenAddCmd) {
    RAT::pop_first_word(newValues, first, rest);
    try {
      fLastGen = RAT::GlobalFactory<GLG4Gen>::New(first);
      fLastGen->SetState(rest);
      fMyAction->AddGenerator(fLastGen);
    } catch (RAT::FactoryUnknownID &unknown) {
      G4Exception(__FILE__, "No Active Generator", FatalException, ("Unknown generator " + unknown.id).c_str());
    }
  } else if (command == fGenSetCmd) {
    if (fLastGen) {
      fLastGen->SetState(newValues);
    }
    else
      G4Exception(__FILE__, "No Active Generator", FatalException, "Cannot use /generator/set without active generator");
  } else if (command == fRateSetCmd) {
    if (fLastGen)
      fLastGen->SetTimeState(newValues);
    else
      G4Exception(__FILE__, "No Active Generator", FatalException, "Cannot use /generator/rate/set without active generator");
  } else if (command == fVtxSetCmd) {
    if (fLastGen)
      fLastGen->SetVertexState(newValues);
    else
      G4Exception(__FILE__, "No Active Generator", FatalException, "Cannot use /generator/vtx/set without active generator");
  } else if (command == fPosSetCmd) {
    if (fLastGen)
      fLastGen->SetPosState(newValues);
    else
      G4Exception(__FILE__, "No Active Generator", FatalException, "Cannot use /generator/pos/set without active generator");
  } else if (command == fEventWindowCmd) {
    G4double newWindow = util_to_double(newValues);
    if (newWindow <= 0.0)
      warn << "GLG4PrimaryGeneratorMessenger::SetNewValueTime:  window must be positive"
           << newline;
    else
      fMyAction->SetEventWindow(newWindow*ns);
  } else {
      warn <<  "GLG4PrimaryGeneratorMessenger::SetNewValueTime:  invalid GLG4 \"set\" command";
  }
}


G4String GLG4PrimaryGeneratorMessenger::
GetCurrentValue(G4UIcommand * command)
{
  // Flag unused parameter
  __unused_parameter(command);
  return G4String("invalid GLG4PrimaryGeneratorMessenger \"get\" command");
}