//
// Caryatid.h
//
//                  by Anatael Cabrera <anatael.cabrera@physics.ox.ac.uk>

#ifndef Caryatid_h
#define Caryatid_h

#include <TObject.h>

#include "MessageService/MsgService.h"

#include <iostream>
#include <stdio.h>
#include <math.h>
#include <vector>

class Caryatid {
  
 public:
  
  Caryatid();
  ~Caryatid();
 private:

  //BASIC pedestal information:
  std::vector<Short_t> fSPentries_v;

  //Float_t ftime;

  Int_t fcrate;
  Int_t fvarc;
  Int_t fvmm;
  Int_t fvfb;
  Int_t fva;
  Int_t fvach;

  Int_t fplane;

  Short_t ferror;

  // Pedestal with no truncation:
  Float_t frawMean;
  Float_t frawRms;
  Int_t   fnumPointsRaw;
  //DAQ values - values obtained from the DAQ tables.
  //Float_t fpedDaq;
  //Float_t fsparThDaq;

  //
  // TRUNCATION:
  // The presence of outliers in the pedestal data requires 
  // the application of some truncation method.
  //

  //Pedestal truncation Method 1:
  //
  // Uses the width of raw pedesal ("frawRms") to truncate the pedestal.
  // The actual cut will be frawRms*fTruncFactor. 
  // This method requires to loop over the data twice!
  // I used this method to tune ideal fix values for truncation, which
  // depended on kind of detector the VA channel was connected to, i.e.
  // whether the PMT anodes, low gain PINs or high gain PINs. The latter 
  // ones have more intrinsic noise. 
  //

  Int_t fnumPointsT1;

  Float_t fmeanTruc1;
  Float_t frmsTrunc1;

  //Valirable truncation threshold:
  Float_t ftruncthrT1;

  //Pedestal Truncation Method 2:
  //
  // Uses tuned values for a fix cut. It can be achieve in one loop: hence faster.
  // Default method.
  // If wierd features appeared on the data whose suspect may be the truncation method,
  // please compare results by using "method 1" (above).
  //

  Int_t fnumPointsT2;

  Float_t fmeanTruc2;
  Float_t frmsTrunc2;
  
  // Fixed trucation thresholds for Method 2:
  static const Int_t TRTHRPMT   = 15;
  static const Int_t TRTHRLGPIN = 18;
  static const Int_t TRTHRHGPIN = 30;

  // Difference between pedetal/sparsification thrshold calculated by DAQ and Caryatid:
  //Int_t fdeltaSpars;
  //Int_t fdeltaPed;

  // Configuration variables:
  static Int_t  fSparsFactor;
  static Int_t  fTruncFactor;
  static Int_t  fTruncFlag;

 public:
  //Input:
  void    AddressMe(const Int_t crate,
		    const Int_t varc,
		    const Int_t vmm,
		    const Int_t vfb,
		    const Int_t va,
		    const Int_t vach );

  void    InputSPEntry(Int_t entry)             {fSPentries_v.push_back(entry);}

  //void    SetTime(const Float_t time)           {ftime      = time;}
  void    SetError(const Int_t error)           {ferror      = error;}
  void    SetPlane(const Int_t plane )          {fplane     = plane;}

  //void    SetPedDAQ(const Int_t pedDAQ)         {fpedDaq    = pedDAQ;} 
  //void    SetSparThDAQ(const Int_t sparThDAQ)   {fsparThDaq = sparThDAQ;}  

  Bool_t  AreYouAt( const Int_t crate,
		    const Int_t varc,
		    const Int_t vmm,
		    const Int_t vfb,
		    const Int_t va,
		    const Int_t vach );

  //Executable Methods:
  void    GetSTAT();  //Get MEANs and RMSs info of pedestal - stir by configuration variables

 private:

  //Private methods used in GetSTAT():
  Int_t   GetInfoRaw();
  Int_t   GetInfoTrunc1();
  Int_t   GetInfoTrunc2();

 public:

  //
  // Configuration variables:
  //

  //TruncationFlag: 0=no truncation, 1=Method 1 & 2=Method 2.
  static void SetTruncFlag(const Int_t truncFlag)   {Caryatid::fTruncFlag = truncFlag;}
  static void SetTruncFactor(const Int_t truncFac)  {Caryatid::fTruncFactor = truncFac;}
  static void SetSparsFactor(const Int_t sparsFac)  {Caryatid::fSparsFactor = sparsFac;}

  //
  // Output:
  //

  static Int_t GetTruncFactor() {return Caryatid::fTruncFactor;}  
  static Int_t GetSparsFactor() {return Caryatid::fSparsFactor;}
  static Int_t EncriptMeAKey(const Int_t crate,
			     const Int_t varc,
			     const Int_t vmm,
			     const Int_t vfb,
			     const Int_t va,
			     const Int_t vach);

  Int_t   GetIDKey(); 
  Bool_t  SparsifiedChannel();
  Bool_t  IsTPMTchannel();
  Bool_t  IsCMchannel();
  Bool_t  IsLGPIN();
  Bool_t  IsHGPIN();

  //Pedestal Information:
  Float_t GetRawMean()   {return frawMean;}
  Float_t GetRawRms()    {return frawRms;}
  Float_t GetMeanT1()    {return fmeanTruc1;}
  Float_t GetRmsT1()     {return frmsTrunc1;}
  Float_t GetMeanT2()    {return fmeanTruc2;}
  Float_t GetRmsT2()     {return frmsTrunc2;}

  Int_t   GetEntries()   {return fnumPointsRaw;}
  Int_t   GetEntriesT1() {return fnumPointsT1;}
  Int_t   GetEntriesT2() {return fnumPointsT2;}

  //Location:
  Int_t   GetCrate() {return fcrate;}
  Int_t   GetVarc()  {return fvarc;}
  Int_t   GetVmm()   {return fvmm;}
  Int_t   GetVfb()   {return fvfb;}
  Int_t   GetVA()    {return fva;}
  Int_t   GetVAch()  {return fvach;}

  Int_t   GetPlane() {return fplane;}
  Int_t   GetError() {return ferror;}

  //Truncation Threshold:
  Float_t GetTrThresholdT1() {return ftruncthrT1;}
  Float_t GetTrThresholdT2() {
      if(fvach == 18 && fva == 0)      return TRTHRLGPIN; //LG PIN
      else if(fvach == 18 && fva == 1) return TRTHRHGPIN; //HG PIN
      else return TRTHRPMT;
  }

  //Sparsification Threshold: //Special value for noisy PPS channel
  Float_t GetRawSparsLevel(){
    if((fcrate==4 && fvarc==0 && fvmm==5 && fvfb==1 && fva==0) 
       && (frawRms*fSparsFactor < 30.)) return 30.; //PPS
    else return (frawRms*fSparsFactor);
  }
  Float_t GetSparsLevelT1(){
    if((fcrate==4 && fvarc==0 && fvmm==5 && fvfb==1 && fva==0) 
       && (frmsTrunc1*fSparsFactor < 30.)) return 30.; //PPS
    else return (frmsTrunc1*fSparsFactor);
  }
  Float_t GetSparsLevelT2(){
    if((fcrate==4 && fvarc==0 && fvmm==5 && fvfb==1 && fva==0) 
       && (frmsTrunc2*fSparsFactor < 30.)) return 30.; //PPS
    else return (frmsTrunc2*fSparsFactor);
  }

  // From comparison with DAQ Tables:
  //void    SetDeltaSpars(const Int_t sparsDelta) {fdeltaSpars = sparsDelta;}
  //void    SetDeltaPed(const Int_t pedDelta)     {fdeltaPed   = pedDelta;}

  //Int_t   GetDeltaSpars() {return fdeltaSpars;}
  //Int_t   GetDeltaPed()   {return fdeltaPed;}

  void    FlushCaryatids() {fSPentries_v.clear();}

  //SOUDAN:
  static const Int_t CRATEMAX = 16;
  static const Int_t VARCMAX  = 3;
  static const Int_t VMMMAX   = 6;
  static const Int_t VFBMAX   = 2;
  static const Int_t VAMAX    = 3;
  static const Int_t VACHMAX  = 22;

};

#endif
