// TKLDiamondTime.hh
// Modified by Yoshi Uchida from TKLVertexRecon_IntHype created by Kazumi Ishii August 2002.
// Last modified by Jason Detwiler October 2002.

#ifndef __TKLDiamondTime_hh__
#define __TKLDiamondTime_hh__

#include "TKLVertexRecon.hh"
#include "PMTInfo.hh"
#include "TMatrix.h"
#include "TCanvas.h"
#include "TClonesArray.h"
#include "TApplication.h"
#include "TH1.h"
#include "TVector3.h"
#include "TKLLightTransportModel.hh"

#include <vector>

class TKLValueAndError {
  public:
    TKLValueAndError operator=(TKLValueAndError vne);
  public:
    Double_t fValue;
    Double_t fError;
    ClassDef(TKLValueAndError,1)
};

//------------------------------------------------------------------------//

class TKLGeomUtils {
  public:
    enum { kNumberOfPMTs = 1325 };
  public:
    static TKLGeomUtils* Instance();
  private:
    TKLGeomUtils();
    static TKLGeomUtils* fgInstance;
  public:
    virtual ~TKLGeomUtils();
    virtual void SetSpeedsOfLight(Double_t c_LS, Double_t c_MO);
    virtual void SetGeometryModel(TKLLightTransportModel::EGeomModel_t geomModel);
    virtual Double_t TimeOfFlightBetween(const TVector3 &vertex, int cableNumber);
    virtual Double_t TimeOfFlightBetween(const TVector3 &vertex, const TVector3 &pmtpos);
    virtual Double_t LengthOfFlight(const TVector3 &vertex, const TVector3& direction, Double_t flightTime);
    virtual Bool_t IsInsideLS(TVector3 vertex);
    virtual Bool_t IsInsideMO(TVector3 vertex);
    virtual TVector3 PMTPositionOf(int cableNumber);
  private:
    Double_t fLSSpeedOfLight;                     // mm/nsec
    Double_t fMOSpeedOfLight;                     // mm/nsec
    TKLLightTransportModel::EGeomModel_t fGeomModel;
    TVector3 fPMTPositions[kNumberOfPMTs];
    ClassDef(TKLGeomUtils,1)
};

//------------------------------------------------------------------------//

class TKLDTFHit {
  public:
    TKLDTFHit operator=(TKLDTFHit hit);
    bool operator>(const TKLDTFHit tq) const;
    bool operator<(const TKLDTFHit tq) const;
  public:
    Float_t fT;
    Float_t fQ;
    Float_t fCorrectedEmissionT;
    Int_t fCableN;
    Int_t fAtwd;
    Int_t fGain;
    ClassDef(TKLDTFHit,1)
};

//------------------------------------------------------------------------//

class TKLDTFHitGroup {
  public:
    TKLDTFHitGroup();
    virtual ~TKLDTFHitGroup();
    virtual void Reset();
    virtual void AddHit(TKLDTFHit hit);
    virtual void RemovePulsesOfLowerGain(int cableNumber, int atwd, int gain);
    virtual void AdjustEmissionTimesForVertex(const TVector3& vertex);
    virtual void CalcTime10to50MethodAndGroupPosition();
                                                  // weeds non-leading
    virtual Double_t CalcTimeLeadingEdgeDiscardOutliers(Float_t *leadingedgewidth=0);
    // edge entries, returns time leading edge, puts 20% to 80% time in leadingedgewidth
    virtual TKLDTFHitGroup& operator=(TKLDTFHitGroup& hitGroup);
    virtual TKLDTFHitGroup& operator+=(TKLDTFHitGroup& hitGroup);
    virtual TVector3 ShiftVectorFromIndividualHits(Double_t emissionTime, TVector3 referenceVector);
    inline TKLValueAndError GetEmissionTime() { return fEmissionTime; }
    inline TVector3 GetPosition() { return fPosition; }
    inline Int_t GetNumberOfHits() { return fHits.size(); }
    inline Bool_t IsValid() { return fIsValid; }
    inline void SetIsValid(Bool_t isValid) { fIsValid = isValid; }
  private:
    vector<TKLDTFHit> fHits;
    Double_t fTotalQ;
    TKLGeomUtils* fGeomUtils;
    TKLValueAndError fEmissionTime;
    TVector3 fPosition;
    Bool_t fIsValid;
    ClassDef(TKLDTFHitGroup,1)
};

//------------------------------------------------------------------------//

class TKLDiamondTime : public TKLVertexRecon {
  public:
    enum EExitConditions {
      kFatalError = -1,
      kSuccess = 0,
      kNonFatalError = 1
    };
  public:
    TKLDiamondTime(TKLLightTransportModel::EGeomModel_t geomModel = TKLLightTransportModel::kTeardropBalloonModel);
    virtual ~TKLDiamondTime();
    virtual Int_t LoadCalibration(Int_t runNumber, const char *tqFlavor);
    virtual Int_t ReconstructVertex(const TClonesArray* tq_ca, TKLVertex* vertex);
    void SetPlotTQs(Bool_t onoff, TApplication* app);
  private:
    virtual Int_t AddTQ(const TClonesArray* tq);
    virtual void MergeLowStatGroups();
    virtual void SetReferenceVertex(Double_t x = 0,  Double_t y = 0, Double_t z = 0);
    virtual void SetReferenceVertex(const TVector3 v);
    virtual void EstimateEmissionTime();
    virtual TVector3 GetNextShift(Bool_t takeBigSteps = false);
  private:
    enum {
      kNumberOfAtwds = 2,
      kNumberOfNearestNeighbors = 4,
      kNumberOfDiamonds = 30,
      kNumberOfPMTs = 1325
    };
    Bool_t fAssumeMC;                             // Part of KludgeMC
    TKLPMTInfo* fPMTInfo;
    Double_t (*fT0)[2];                           //! timing offsets to use for A/B ATWDs
    vector<TKLDTFHitGroup> fHitGroups;
    Int_t  fNHitTubesForDiamond[kNumberOfDiamonds];
    Bool_t fPlotTQs;
    TCanvas* fTQCanvas;
    TApplication* fApp;

    TVector3 fRefVertex;
    TVector3 fStartVertex;
    Double_t fEstimatedEmissionTime;

    TKLGeomUtils* fGeomUtils;

    Int_t fSuperDiamondNearestNeighbors[kNumberOfDiamonds][kNumberOfNearestNeighbors];
    Int_t fGroupNumberOfDiamondIndex[kNumberOfDiamonds];

    ClassDef(TKLDiamondTime,1)
};
#endif