//==========================================================================
//  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_GEANT4VOLUMEMANAGER_H
#define DDG4_GEANT4VOLUMEMANAGER_H

// Framework include files
#include <DD4hep/Detector.h>
#include <DD4hep/IDDescriptor.h>
#include <DDG4/Geant4Primitives.h>

// Geant4 include files
#include <G4VTouchable.hh>

#include <utility>
#include <vector>

// Geant4 forward declarations
class G4VPhysicalVolume;


/// 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 Geant4VolumeManager;
    class Geant4GeometryInfo;

    /// The Geant4VolumeManager to facilitate optimized lookups of cell IDs from touchables.
    /** @class Geant4VolumeManager Geant4VolumeManager.h DDG4/Geant4VolumeManager.h
     *
     * @author  M.Frank
     * @version 1.0
     */
    class Geant4VolumeManager : public Handle<Geant4GeometryInfo>   {
    protected:
      /// Check the validity of the information before accessing it.
      bool checkValidity() const;
    protected:
      friend class Geant4Mapping;
      
      /// Default constructor
      Geant4VolumeManager() = default;
      /// Constructor to be used when reading the already parsed object
      Geant4VolumeManager(const Handle<Geant4GeometryInfo>& e)
        : Handle<Geant4GeometryInfo>(e) {  }
      /// Constructor to be used when reading the already parsed object
      Geant4VolumeManager(const Geant4VolumeManager& e) = default;
      /// Constructor to be used when reading the already parsed object
      template <typename Q> Geant4VolumeManager(const Handle<Q>& e)
        : Handle<Geant4GeometryInfo>(e) {
      }
      /// Assignment operator
      Geant4VolumeManager& operator=(const Geant4VolumeManager& c) = default;
      
    public:
      static const VolumeID InvalidPath = VolumeID(-1LL);
      static const VolumeID Insensitive = VolumeID(-2LL);
      static const VolumeID NonExisting = 0ULL;

      /// Initializing constructor. The tree will automatically be built if possible
      Geant4VolumeManager(const Detector& description, Geant4GeometryInfo* info);

      /// Helper: Generate placement path from touchable object
      std::vector<const G4VPhysicalVolume*>
      placementPath(const G4VTouchable* touchable, bool exception = true) const;
      /// Access CELLID by Geant4 touchable object
      VolumeID volumeID(const G4VTouchable* touchable) const;
      /// Access fully decoded volume fields  by placement path
      void volumeDescriptor(const std::vector<const G4VPhysicalVolume*>& path,
                            std::pair<VolumeID,std::vector<std::pair<const BitFieldElement*, VolumeID> > >& volume_desc) const;
      /// Access fully decoded volume fields by Geant4 touchable object
      void volumeDescriptor(const G4VTouchable* touchable,
                            std::pair<VolumeID,std::vector<std::pair<const BitFieldElement*, VolumeID> > >& volume_desc) const;
    };
  }    // End namespace sim
}      // End namespace dd4hep
#endif // DDG4_GEANT4VOLUMEMANAGER_H
