///////////////////////////////////////////////////////////////////////
//
// Base class for methods
//
// Author: Phil G Jones <p.g.jones@qmul.ac.uk>
// Author: Matthew Mottram <m.mottram@qmul.ac.uk> -- contact person
//
// REVISION HISTORY:
//     26/04/2011 : P G Jones - New file
//     05/10/2012 : P G Jones - Changed internal data to be a vector of
//                              hits and the run.
//     24/01/2013 : P G Jones - Changed to derive from the FitterComponent
//                              class. Allows variable setting.
//     2013-08-23 : P G Jones - Updated to use FitterPMT instead of PMTCal
//     2014-03-29 : P G Jones - Updated lifetime, added BeginOfRun method
//     2015-05-13 : W Heintzelman - add fDS (pointer to data structure)
//
// All methods derive from this, directly or indirectly
//
///////////////////////////////////////////////////////////////////////

#ifndef __RAT_Method_Method_
#define __RAT_Method_Method_

#include <string>
#include <vector>
#include <stdexcept>

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

namespace RAT
{

namespace DS
{
  class EV;
  class Run;
}

namespace Methods
{

class Method : public FitterComponent
{
public:
  class MethodFailError : public std::runtime_error
  {
  public:
    // Just sets up a std::runtime_error
    MethodFailError( const std::string& info ) : std::runtime_error( info ) {}
  };

  // Constructor initialises to NULL
  Method() : fRun(NULL) {}
  // Virtual destructor
  virtual ~Method() {}

  // Initialise the method
  //
  // param (optional) defines extra information on how to initialise.
  virtual void Initialise( const std::string& param ) = 0;

  // Called to invoke the method algorithm
  //
  // Returns the best FitResult
  virtual DS::FitResult GetBestFit() = 0;

  // Return the internal fit result
  //
  // Returns the best FitResult
  DS::FitResult GetFitResult() const { return fFitResult; };

  // Set the event information
  //
  // pmtData is the PMT information to consider
  // event is the event information to consider
  // run is the run information to consider
  inline void SetEventData( std::vector<FitterPMT>& pmtData, DS::EV* event, 
                            DS::Run* run, DS::Entry* ds=NULL );

protected:
  std::vector<FitterPMT> fPMTData; // Internal pmt data
  DS::FitResult fFitResult; // Internal FitResult

  DS::EV* fEvent; // Should be used only to get access to classifiers
  DS::Run* fRun; // Internal run
  DS::Entry* fDS;  // Pointer to data structure
};

void
Method::SetEventData( std::vector<FitterPMT>& pmtData,
                      DS::EV* event,
                      DS::Run* run , 
                      DS::Entry* ds)
{
  fEvent = event;
  fRun = run;
  fPMTData = pmtData;
  fDS = ds;
}

} //::Methods

} //::RAT

#endif