////////////////////////////////////////////////////////////////////////
/// \class RAT::VertexFunction
///
/// \brief  All MultiPath PMT-vertex likelihood functions inherit from this
///
/// \author Jeff Tseng <jeff.tseng@physics.ox.ac.uk> (contact)
///
/// REVISION HISTORY:\n
///     2018-02-06 : J Tseng - new file
///
/// \details Base class for MultiPath PMT-vertex likelihood functions
///
////////////////////////////////////////////////////////////////////////

#ifndef __RAT_VertexFunction__
#define __RAT_VertexFunction__

#include <string>
#include <vector>
#include <RAT/FitterComponent.hh>
#include <RAT/DS/FitResult.hh>
//#include <RAT/FitterPMT.hh>

namespace RAT {

class VertexFunction : public FitterComponent {

public:

  /// description of a fit parameter,
  /// including name and histogram specification
  /// (used by DumpLikelihoods)
  class Parameter {
  public:

    // constructor
    Parameter(const std::string& name, int nbins, double low, double high) :
        fName(name), fNBins(nbins), fLow(low), fHigh(high) {}

    // parameter name
    const std::string GetName() const { return fName; }

    // histogram specification for DumpLikelihoods
    int GetNBins() const { return fNBins; }
    double GetLowValue() const { return fLow; }
    double GetHighValue() const { return fHigh; }
  private:
    std::string fName; // parameter name
    int fNBins; // histogram number of bins
    double fLow; // histogram low edge
    double fHigh; // histogram high edge
  };

  /// constructor.
  /// This should initialize the parameter list fPars.
  VertexFunction() : fPars(), fRes(0.0) {}

  /// from FitterComponent:
  ///virtual std::string GetName() const;
  ///virtual void BeginOfRun( DS::Run& run );
  ///virtual void EndOfRun( DS::Run& run );

  /// initialise the function (when instantiated by MultiPath method)
  virtual void Initialise( const std::string& param ) = 0;

  /// set seed from a previous result
  virtual void SetSeed(const DS::FitResult& result) = 0;

  /// set a result from the parameters
  virtual DS::FitResult MakeResult(const std::vector<double>& pars) = 0;

  /// set a starting set of parameters for one iteration
  virtual std::vector<double> GetStart() = 0;

  /// calculates the figure of merit for a given PMT and vertex.
  /// input:  pmt = PMT position
  ///         par = current parameters (ordered as in fPars)
  /// output: diff = derivatives with respect to the parameters
  /// returns the figure of merit.
  /// also can set fRes, which can be accessed via GetResidual(),
  ///   but this is optional.
  virtual double Calculate( const std::vector<double>& pmt,
                            const std::vector<double>& par,
                            std::vector<double>& diff ) = 0;

  /// check whether the parameters yield a valid result
  virtual bool ValidResult(const std::vector<double>& par) = 0;

  /// return the residual calculated by the last Calculate
  double GetResidual() { return fRes; }

  // information on the function parameters
  size_t GetNumberOfParameters() { return fPars.size(); }
  const std::vector<Parameter>& GetParameters() { return fPars; }

protected:

  std::vector<Parameter> fPars; // parameter descriptions
  double fRes; // residual

};

} //::RAT

#endif