// PhysicsBase.h is a part of the PYTHIA event generator.
// Copyright (C) 2025 Torbjorn Sjostrand.
// PYTHIA is licenced under the GNU GPL v2 or later, see COPYING for details.
// Please respect the MCnet Guidelines, see GUIDELINES for details.

// This file contains the base class for physics classes used inside Pyhia8.

#ifndef Pythia8_PhysicsBase_H
#define Pythia8_PhysicsBase_H

#include "Pythia8/Info.h"
#include "Pythia8/Settings.h"
#include "Pythia8/SharedPointers.h"

namespace Pythia8 {

// Forward declaration of Pythia class.
class Pythia;

//==========================================================================

// Classes that implement physics models should inherit from the PhysicsBase
// class. It includes pointers to objects set up in the controlling Pythia
// object to take care of bookkeeping and simpler service tasks.

class PhysicsBase {

public:

  // Enumerate the different status codes the event generation can have.
  enum Status { INCOMPLETE = -1, COMPLETE = 0, CONSTRUCTOR_FAILED,
    INIT_FAILED, LHEF_END, LOWENERGY_FAILED, PROCESSLEVEL_FAILED,
    PROCESSLEVEL_USERVETO, MERGING_FAILED, PARTONLEVEL_FAILED,
    PARTONLEVEL_USERVETO, HADRONLEVEL_FAILED, CHECK_FAILED,
    OTHER_UNPHYSICAL, HEAVYION_FAILED, HADRONLEVEL_USERVETO };

  // This function is called from above for physics objects used in a run.
  void initInfoPtr(Info& infoPtrIn);

  // Empty virtual destructor.
  virtual ~PhysicsBase() {}

  // Shorthand to read settings values.
  bool   flag(string key) const {return settingsPtr->flag(key);}
  int    mode(string key) const {return settingsPtr->mode(key);}
  double parm(string key) const {return settingsPtr->parm(key);}
  string word(string key) const {return settingsPtr->word(key);}
  vector<bool>   fvec(string key) const {return settingsPtr->fvec(key);}
  vector<int>    mvec(string key) const {return settingsPtr->mvec(key);}
  vector<double> pvec(string key) const {return settingsPtr->pvec(key);}
  vector<string> wvec(string key) const {return settingsPtr->wvec(key);}

protected:

  // Default constructor.
  PhysicsBase() {}

  // If an object needs to set up infoPtr for sub objects, override this
  // and call registerSubObject for each object in question.
  virtual void onInitInfoPtr() {}

  // This function is called in the very beginning of each Pythia::next call.
  virtual void onBeginEvent() {}

  // This function is called in the very end of each Pythia::next call
  // with the argument set to the current status of the event.
  virtual void onEndEvent(Status) {}

  // This function is called from the Pythia::stat() call.
  virtual void onStat() {}

  // This function is called from the PythiaParallel::stat() call.
  // The argument is all thread instances of this PhysicsBase.
  // Each instance can be recast as dynamic_cast<DerivedClass*>(ptr).
  virtual void onStat(vector<PhysicsBase*>, Pythia*) {}

  // Register a sub object that should have its information in sync with this.
  void registerSubObject(PhysicsBase& pb);

  // Pointer to various information on the generation.
  // This is also the place from which a number of pointers are recovered.
  Info*          infoPtr       =  {};

  // Pointer to the settings database.
  Settings*      settingsPtr      = {};

  // Pointer to the particle data table.
  ParticleData*  particleDataPtr  = {};

  // Pointer to logger.
  Logger*        loggerPtr        = {};

  // Pointer to the hadron widths data table
  HadronWidths*  hadronWidthsPtr  = {};

  // Pointer to the random number generator.
  Rndm*          rndmPtr          = {};

  // Pointers to SM and SUSY couplings.
  CoupSM*        coupSMPtr        = {};
  CoupSUSY*      coupSUSYPtr      = {};

  // Pointers to the two incoming beams and to Pomeron, photon or VMD
  // beam-inside-beam cases.
  BeamSetup*    beamSetupPtr    = {};
  BeamParticle* beamAPtr        = {};
  BeamParticle* beamBPtr        = {};
  BeamParticle* beamPomAPtr     = {};
  BeamParticle* beamPomBPtr     = {};
  BeamParticle* beamGamAPtr     = {};
  BeamParticle* beamGamBPtr     = {};
  BeamParticle* beamVMDAPtr     = {};
  BeamParticle* beamVMDBPtr     = {};

  // Pointer to information on subcollision parton locations.
  PartonSystems* partonSystemsPtr = {};

  // Pointers to the total/elastic/diffractive cross sections.
  SigmaTotal*    sigmaTotPtr      = {};
  SigmaCombined* sigmaCmbPtr      = {};

  // A set of sub objects that should have their information in sync
  // with This.
  set<PhysicsBase*> subObjects;

  // Pointer to the UserHooks object (needs to be set to null in
  // classes deriving from UserHooks to avoid closed loop ownership).
  UserHooksPtr      userHooksPtr;

  // Mutex that should be locked for thread-unsafe code.
  mutex* mutexPtr;

private:

  friend class Pythia;
  friend class PythiaParallel;

  // Calls onBeginEvent, then propagates the call to all sub objects
  void beginEvent();

  // Calls onEndEvent, then propagates the call to all sub objects
  void endEvent(Status status);

  // Calls onStat, then propagates the call to all sub objects
  void stat();

};

//==========================================================================

} // end namespace Pythia8

#endif // Pythia8_PhysicsBase_H
