////////////////////////////////////////////////////////////////////
/// \class RAT::DU::TimeReidualCalculator
///
/// \brief Useful calculations for time residuals
//         and  related functions
///
/// \author Max Smiley <masmiley@berkeley.edu>
///
/// REVISION HISTORY:\n
///  - 2020-11 : Max Smiley - First revision
///
/// \details Returns PMT hit times corrected by time-of-flight
///          and reconstructed event time.
///
/// It can be used in RAT, ROOT or external programs that link to
/// the libRATEvent library.
///
////////////////////////////////////////////////////////////////////

#ifndef __RAT_DU_TimeResidualCalculator__
#define __RAT_DU_TimeResidualCalculator__

#include <RAT/DU/LightPathCalculator.hh>
#include <RAT/DU/Point3D.hh>
#include <RAT/DS/PMT.hh>
#include <RAT/FitterPMT.hh>

#include <TObject.h>
#include <TVector3.h>

namespace RAT
{
  namespace DU
  {

    class TimeResidualCalculator : public TObject
    {

    public:

      /////////////////////////////////
      ////////     METHODS     ////////
      /////////////////////////////////

      /// Default constructor
      TimeResidualCalculator() : TObject() { }

      /// Called at the start of a run, loads from the database
      /// Sets whether we use the partially or fully filled
      /// calculation
      void BeginOfRun();

      /// This function calculates the time residual for a hit on PMT 'pmtCal'
      /// for an event at 'fitPos' and 'fitTime'. There are options to use the full
      /// group velocity calculation (with/without a specific energy specified),
      /// and the added PMT bucket instead of the effective velocity.
      /// Refraction is modelled for values of 'localityVal' > 0.0. If 'localityVal' = 0.0,
      /// then the straight line approximation is used. For refractive calculations, the refraction
      /// is modelled based on the energy of the light provided (default 3.103125 * 1e-6 MeV = 400nm).
      ///
      /// @param[in] pmtCal The PMT on which the hit was recorded
      /// @param[in] fitPos The event position for which the hit was recorded
      /// @param[in] fitTime The event time for which the hit was recorded
      /// @param[in] useGroup A toggle to determine whether the effective or group velocity is used in the calculation (defaults to effective)
      /// @param[in] photonEnergy The photon energy in MeV (defaults to 400 nm -> 3.103125 * 1e-6 MeV)
      /// @param[in] useBucket A toggle to determine whether the PMT bucket time is used in the calculation (defaults to off)
      /// @param[in] localityVal The accepted tolerance [mm] for how close the path is calculated to the 'pmtPos' (defaults to 0.0 -> Straight Line Calculation)
      double CalcTimeResidual( const RAT::DS::PMTCal& pmtCal,
                               const RAT::DU::Point3D& fitPos,
                               const double fitTime,
                               const Bool_t useGroup = false,
                               const Double_t photonEnergy = 3.103125 * 1e-6,
                               const Bool_t useBucket = false,
                               const Double_t localityVal = 0.0,
                               const Bool_t useNhits = false,
                               const Double_t nhitsVal = 800);

      /// This function calculates the time residual for a hit on PMT 'pmtFitter'
      /// for an event at 'fitPos' and 'fitTime'. There are options to use the full
      /// group velocity calculation (with/without a specific energy specified),
      /// and the added PMT bucket instead of the effective velocity.
      /// Refraction is modelled for values of 'localityVal' > 0.0. If 'localityVal' = 0.0,
      /// then the straight line approximation is used. For refractive calculations, the refraction
      /// is modelled based on the energy of the light provided (default 3.103125 * 1e-6 MeV = 400nm).
      ///
      /// @param[in] pmtFitter The PMT on which the hit was recorded
      /// @param[in] fitPos The event position for which the hit was recorded
      /// @param[in] fitTime The event time for which the hit was recorded
      /// @param[in] useGroup A toggle to determine whether the effective or group velocity is used in the calculation (defaults to effective)
      /// @param[in] photonEnergy The photon energy in MeV (defaults to 400 nm -> 3.103125 * 1e-6 MeV)
      /// @param[in] useBucket A toggle to determine whether the PMT bucket time is used in the calculation (defaults to off)
      /// @param[in] localityVal The accepted tolerance [mm] for how close the path is calculated to the 'pmtPos' (defaults to 0.0 -> Straight Line Calculation)
      double CalcTimeResidual( const RAT::FitterPMT& pmtFitter,
                               const RAT::DU::Point3D& fitPos,
                               const double fitTime,
                               const Bool_t useGroup = false,
                               const Double_t photonEnergy = 3.103125 * 1e-6,
                               const Bool_t useBucket = false,
                               const Double_t localityVal = 0.0,
                               const Bool_t useNhits = false,
                               const Double_t nhitsVal = 800);

      /// This function calculates the time residual for a hit on PMT with
      /// ID 'pmtID' at time 'pmtTime' for an event at 'fitPos' and 'fitTime'.
      /// There are options to use the full
      /// group velocity calculation (with/without a specific energy specified),
      /// and the added PMT bucket instead of the effective velocity.
      /// Refraction is modelled for values of 'localityVal' > 0.0. If 'localityVal' = 0.0,
      /// then the straight line approximation is used. For refractive calculations, the refraction
      /// is modelled based on the energy of the light provided (default 3.103125 * 1e-6 MeV = 400nm).
      ///
      /// @param[in] pmtID The PMT ID for the PMT on which the hit was recorded
      /// @param[in] pmtTime The time for the hit on the PMT
      /// @param[in] fitPos The event position for which the hit was recorded
      /// @param[in] fitTime The event time for which the hit was recorded
      /// @param[in] useGroup A toggle to determine whether the effective or group velocity is used in the calculation (defaults to effective)
      /// @param[in] photonEnergy The photon energy in MeV (defaults to 400 nm -> 3.103125 * 1e-6 MeV)
      /// @param[in] useBucket A toggle to determine whether the PMT bucket time is used in the calculation (defaults to off)
      /// @param[in] localityVal The accepted tolerance [mm] for how close the path is calculated to the 'pmtPos' (defaults to 0.0 -> Straight Line Calculation)
      double CalcTimeResidual( const UInt_t pmtID,
                               const double pmtTime,
                               const RAT::DU::Point3D& fitPos,
                               const double fitTime,
                               const Bool_t useGroup = false,
                               const Double_t photonEnergy = 3.103125 * 1e-6,
                               const Bool_t useBucket = false,
                               const Double_t localityVal = 0.0,
                               const Bool_t useNhits = false,
                               const Double_t nhitsVal = 800);

      // 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( TimeResidualCalculator, 0 );

    private:

      ///////////////////////////////////////////////////
      /////////     PRIVATE MEMBER VARIABLES     ////////
      ///////////////////////////////////////////////////

      Bool_t fPartialFlag;                            //True if the calculator should use the partial fill calculation
      DU::LightPathCalculator fLightPath;         //LightPathCalculator object for the calculator
      size_t fAVSystemId; // coordinate system id for Point3D

    };

  } // namespace DU

} // namespace RAT

#endif