//==========================================================================
//  AIDA Detector description implementation 
//--------------------------------------------------------------------------
// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
// All rights reserved.
//
// For the licensing terms see $DD4hepINSTALL/LICENSE.
// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
//
// Author     : M.Frank
//
//==========================================================================
#ifndef DDG4_GEANT4OUTPUTACTION_H
#define DDG4_GEANT4OUTPUTACTION_H

// Framework include files
#include <DDG4/Geant4EventAction.h>

// Forward declarations
class G4Run;
class G4Event;
class G4VHitsCollection;


/// Namespace for the AIDA detector description toolkit
namespace dd4hep {

  /// Namespace for the Geant4 based simulation part of the AIDA detector description toolkit
  namespace sim {

    // Forward declarations
    class Geant4ParticleMap;

    /// Base class to output Geant4 event data to persistent media
    /**
     *  \author  M.Frank
     *  \version 1.0
     *  \ingroup DD4HEP_SIMULATION
     */
    class Geant4OutputAction: public Geant4EventAction {
    protected:
      /// Helper class for thread savety
      template <typename T> class OutputContext {
      public:
        const T* context;
        void* userData;
        OutputContext(const T* c)
          : context(c), userData(0) {
        }
        template <typename U> U* data() const {
          return (U*) userData;
        }
      };

      /// Property: "Output" output destination
      std::string        m_output  {  };
      /// Property: "HandleErrorsAsFatal" Handle errors as fatal and rethrow eventual exceptions
      bool               m_errorFatal { true };
      /// Reference to MC truth object
      Geant4ParticleMap* m_truth   { nullptr };
    public:
      /// Inhibit default constructor
      Geant4OutputAction() = delete;
      /// Inhibit copy constructor
      Geant4OutputAction(const Geant4OutputAction& copy) = delete;
      /// Standard constructor
      Geant4OutputAction(Geant4Context* c, const std::string& nam);
      /// Default destructor
      virtual ~Geant4OutputAction();
      /// Set or update client for the use in a new thread fiber
      virtual void configureFiber(Geant4Context* ctxt)  override;

      /// begin-of-event callback
      virtual void begin(const G4Event* event)  override;
      /// End-of-event callback
      virtual void end(const G4Event* event)  override;
      /// Callback to initialize storing the Geant4 information
      virtual void beginRun(const G4Run* run);
      /// Callback to store the Geant4 run information
      virtual void endRun(const G4Run* run);

      /// Callback to store the Geant4 event
      virtual void saveRun(const G4Run* run);
      /// Callback to store the Geant4 event
      virtual void saveEvent(OutputContext<G4Event>& ctxt);
      /// Callback to store each Geant4 hit collection
      virtual void saveCollection(OutputContext<G4Event>& ctxt, G4VHitsCollection* collection);
      /// Commit data at end of filling procedure
      virtual void commit(OutputContext<G4Event>& ctxt);
    };

  }    // End namespace sim
}      // End namespace dd4hep
#endif // DDG4_GEANT4OUTPUTACTION_H
