////////////////////////////////////////////////////////////////////////
/// \class RAT::DU::SOCReader
///
/// \brief Convenience class for ROOT scripts
///
/// \author P G Jones <p.g.jones@qmul.ac.uk>
/// \author Rob Stainforth <R.Stainforth@liverpool.ac.uk> -- contact person
///
/// REVISION HISTORY:\n
///     25/10/2012 : P G Jones - New File.\n
///     2014-03-26 : P G Jones - Refactor for ds review.
///
/// \details This is the recommended/best way to read a RAT::DS::SOC root file.
/// Use as follows,
/// @verbatim
/// SOCReader socReader("filename.root");
///
/// for( size_t isoc = 0; isoc < socReader.GetSOCCount(); isoc++ )
///   {
///     RAT::DS::SOC rSOC = socReader.GetSOC( isoc );
///     RAT::DS::Run rRun = socReader.GetRun();
///   }
/// @endverbatim
///
////////////////////////////////////////////////////////////////////////
#ifndef __RAT_DU_SOCReader___
#define __RAT_DU_SOCReader___

#include <TObject.h>

#include <string>
#include <vector>

class TChain;

namespace RAT
{
namespace DS
{
  class SOC;
  class Run;
}
namespace DU
{

class SOCReader : public TObject
{
public:
  /// Construct the SOCReader with a filename (inc path)
  ///
  /// @param[in] filename to open
  /// @param[in] useMeta to configure DB or ignore it?
  SOCReader( const std::string& filename, const bool useMeta=true );

  /// Construct the SOCReader with many files to TChain together
  ///
  /// @param[in] filenames to open
  /// @param[in] useMeta to configure DB or ignore it?
  SOCReader( const std::vector<std::string>& filenames, const bool useMeta=true );

  /// Destruct the SOCReader, delete TTrees etc...
  ~SOCReader();

  /// Called whenever the run changes
  void BeginOfRun();

  /// Add a new file to the total (should restart any loops!)
  ///
  /// @param[in] filename to add
  void Add( const std::string& filename );

  /// Get the soc at index
  ///
  /// @param[in] index of the soc to return
  /// @return a constant reference to the soc
  /// @throws DataNotFound if event is out of range
  const DS::SOC& GetSOC( const size_t index );

  /// Get the count of events
  ///
  /// @return the total number of events
  size_t GetSOCCount() { return fTotalSOC; }

  /// Get the run.
  ///
  /// @return a constant reference to the run
  const DS::Run& GetRun();

  /// Get the run with run ID
  ///
  /// @param[in] runID runID to find
  /// @return a constant reference to the run
  /// @throws DataNotFound if not appropriate run can be found
  const DS::Run& GetRunByRunID( const size_t runID );

  /// Get the run with index
  ///
  /// @param[in] index of the run to return
  /// @return a constant reference to the run
  /// @throws DataNotFound if index is out of range
  const DS::Run& GetRunByIndex( const size_t index );

  /// Get the count of runs
  ///
  /// @return the total number of runs
  size_t GetRunCount() { return fTotalRuns; }

  // This ROOT macro adds dictionary methods to this class.
  // The number is 0 as this class is never, and should never be written to disc.
  // It assumes this class has no virtual methods, use ClassDef if change this.
  ClassDefNV( SOCReader, 0 );
protected:
  TChain* fT; ///< The DS T Tree
  TChain* fRunT; ///< The DS runT Tree
  DS::SOC* fSOC; ///< The current event
  DS::Run* fRun; ///< The current run
  ULong64_t fCurrentSOC; ///< The current event index
  ULong64_t fTotalSOC; ///< The total number of events
  ULong64_t fCurrentRun; ///< The current run index
  ULong64_t fTotalRuns; ///< The total number of runs

  bool fUseMeta; ///< Flag to use or ignore Meta information in file. Default true.
};

} // namespace DU

} // namespace RAT

#endif