//
// ********************************************************************
// * License and Disclaimer                                           *
// *                                                                  *
// * The  Geant4 software  is  copyright of the Copyright Holders  of *
// * the Geant4 Collaboration.  It is provided  under  the terms  and *
// * conditions of the Geant4 Software License,  included in the file *
// * LICENSE and available at  http://cern.ch/geant4/license .  These *
// * include a list of copyright holders.                             *
// *                                                                  *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work  make  any representation or  warranty, express or implied, *
// * regarding  this  software system or assume any liability for its *
// * use.  Please see the license in the file  LICENSE  and URL above *
// * for the full disclaimer and the limitation of liability.         *
// *                                                                  *
// * This  code  implementation is the result of  the  scientific and *
// * technical work of the GEANT4 collaboration.                      *
// * By using,  copying,  modifying or  distributing the software (or *
// * any work based  on the software)  you  agree  to acknowledge its *
// * use  in  resulting  scientific  publications,  and indicate your *
// * acceptance of all terms of the Geant4 Software license.          *
// ********************************************************************
//
//
//
// Class Description:
//
// This is the class manager of the GEANT4e package.
// It is the main interface for the user to define the setup and
// start the propagation. Initializes GEANT4 for the propagation.

// History:
// - Created:   Pedro Arce, February 2001
// --------------------------------------------------------------------

#ifndef G4ErrorPropagatorManager_hh
#define G4ErrorPropagatorManager_hh

#include "globals.hh"
#include "G4ErrorPropagatorData.hh"
#include "G4ErrorPropagator.hh"
#include "G4ApplicationState.hh"

class G4ErrorPropagationNavigator;
class G4ErrorRunManagerHelper;
class G4ErrorTarget;
class G4ErrorTrajState;

class G4VUserDetectorConstruction;
class G4VPhysicalVolume;
class G4VUserPhysicsList;
class G4UserRunAction;
class G4UserEventAction;
class G4UserStackingAction;
class G4UserTrackingAction;
class G4UserSteppingAction;
class G4Mag_UsualEqRhs;
class G4Track;

class G4ErrorPropagatorManager
{
 public:  // with description
  G4ErrorPropagatorManager();
  // Initialise data to 0. Starts the G4ErrorRunManagerHelper and
  // G4ErrorPropagationNavigator.

  ~G4ErrorPropagatorManager();

  static G4ErrorPropagatorManager* GetErrorPropagatorManager();
  // Get only instance of G4ErrorPropagatorManager. If it does not exists,
  // creates it

  void EventTermination();
  // Set state to G4ErrorState_Init

  void RunTermination();
  // Set state to G4ErrorState_Init and invoke
  // G4ErrorRunManagerHelper::RunTermination()

  void InitGeant4e();
  // Initializes Geant4 and Geant4e

  void InitTrackPropagation();
  // Set the propagator step number to 0 and the G4ErrorState to Propagating

  G4bool InitFieldForBackwards();
  // Creates the G4ErrorMag_UsualEqRhs, that will control backwards tracking

  G4int Propagate(G4ErrorTrajState* currentTS, const G4ErrorTarget* target,
                  G4ErrorMode mode = G4ErrorMode_PropForwards);
  // Inits track propagation, invokes G4ErrorPropagator::Propagate and
  // terminates "event"

  G4int PropagateOneStep(G4ErrorTrajState* currentTS,
                         G4ErrorMode mode = G4ErrorMode_PropForwards);
  // Invokes G4ErrorPropagator::PropagateOneStep

  G4bool CloseGeometry();
  // Close Geant4 geometry

  void SetUserInitialization(G4VUserDetectorConstruction* userInit);
  // Invokes G4ErrorRunManagerHelper to construct detector and set
  // world volume
  void SetUserInitialization(G4VPhysicalVolume* userInit);
  // Invokes G4ErrorRunManagerHelper to  set world volume
  void SetUserInitialization(G4VUserPhysicsList* userInit);
  // Invokes G4ErrorRunManagerHelper to initialize physics

  void SetUserAction(G4UserTrackingAction* userAction);
  // Invokes G4EventManager to set a G4UserTrackingAction
  void SetUserAction(G4UserSteppingAction* userAction);
  // Invokes G4EventManager to set a G4UserSteppingAction

  G4String PrintG4ErrorState();
  G4String PrintG4ErrorState(G4ErrorState state);
  // Print Geant4e state

  G4String PrintG4State();
  G4String PrintG4State(G4ApplicationState state);
  // Print Geant4 state

  // Set and Get methods

  G4ErrorRunManagerHelper* GetErrorRunManagerHelper() const
  {
    return theG4ErrorRunManagerHelper;
  }

  void SetSteppingManagerVerboseLevel();

  G4ErrorPropagationNavigator* GetErrorPropagationNavigator() const
  {
    return theG4ErrorPropagationNavigator;
  }

  G4ErrorPropagator* GetPropagator() const { return thePropagator; }

 private:
  void StartG4ErrorRunManagerHelper();
  // Create a G4ErrorRunManagerHelper if it does not exist and set to it
  // the G4ErrorPhysicsList

  void StartNavigator();
  // create a G4ErrorPropagationNavigator

 private:
  static G4ThreadLocal G4ErrorPropagatorManager* theG4ErrorPropagatorManager;

  G4ErrorRunManagerHelper* theG4ErrorRunManagerHelper;

  G4ErrorPropagator* thePropagator;

  G4Mag_UsualEqRhs* theEquationOfMotion;

  G4ErrorPropagationNavigator* theG4ErrorPropagationNavigator;
};

#endif
