////////////////////////////////////////////////////////////////////
// Processor for generating constants from the ECA
//
// Author: Gabriel D. Orebi Gann <gorebigann@lbl.gov> Author and contact
//         Javier Caravaca <jcaravaca@berkeley.edu> - Contact
//
// REVISION HISTORY:
//
//           Oct 2013  G.D. Orebi Gann   Add vector of ints for
//                                       TSlope point status
//                     + K. Kamdin       Fix array indexing
//                                       & extra debug output
//           Sep 2014  K. Kamdin         Add options for extra
//                                       diagnostic output.
//                                       Add run_status field to
//                                       .ratdb output
//                                       Add new flags for more
//                                       robust checks.
//           Jun 24  N Barros            Change table header to
//                                       new database schema
//           Jun 27  J. Caravaca         Added rate and pattern as
//                                       an index to ECA constants
//                                       Make compatible with SNO
//                                       EpedRecords
//                                       Added extra output for monitoring
//
//
// This class generates ECA constants from the electronics
// calibrations runs.
//
//
////////////////////////////////////////////////////////////////////
#ifndef __RAT_ECAProc__
#define __RAT_ECAProc__

#include <RAT/Processor.hh>
#include <RAT/DB.hh>
#include <RAT/DS/Entry.hh>
#include <RAT/DS/Run.hh>
#include <RAT/ECAHists.hh>
#include <RAT/ECABits.hh>
#include <RAT/BitManip.hh>

#include <string>
#include "dprintf.hpp"
#include "fileio.hpp"
#include "multiio.hpp"

#include "TFile.h"
#include "TMath.h"
#include "TGraphErrors.h"
#include "TF1.h"
#include <sys/stat.h>

namespace RAT {


class ECAProc : public Processor {
public:

  ECAProc();
  virtual ~ECAProc();
  void BeginOfRun( DS::Run& run );
  void EndOfRun( DS::Run& run );
  virtual Processor::Result DSEvent(DS::Run& run, DS::Entry& ds);

protected:

  // Output and status methods
  void Die(std::string message="", int flag_err=0, float info1=0, float info2=0, int return_code=1);
  void DontDie(std::string message="", int flag_err=0, float info1=0, float info2=0);
  void InitLogOut(std::string _logfilename);
  void InitECARoot(std::string _rootfilename);
  void CloseECARoot();
  void CreateECATable();
  void CreateECAMoni();
  void MergeECAResults();
  void Summarise();
  bool MatchPrevTinj(std::string msg);
  int IdentifyLast(int cccc);
  // Kate
  void WriteTSlopesRoot();
  void WriteECADebugHistosRoot();
  void InitECADebugOut(std::string _debugfilename);
  void WriteECADebugHeader();
  void FillECADebug();
  void CloseECADebug();
  void ReassignSigs();
  std::vector<int> fCellsToReassign;
  // Diagnostics
  void PedDiagnostic();
  std::vector<int> TSlopeFilter(int cccc);
  int TSlopeNGood(int cccc);
  void TSlopeDiagnostic();
  std::vector<int> TSlopeBadCombined(int cccc);

  // Calculations
  void MultiCalc(int n, std::vector<int> arg);
  void TSlopeFit(int cccc);
  void LinearFit(int n, float* &x, float* &y, float* &p, float valid);
  void CubicFit(int n, float* &x, float* &y, float* &ye, float* &p, float* &pe, float& chisq);

  bool FileExists(std::string filename);

  void LoadPatterns();

  // ECA control information (user-defined)
  DBLinkPtr fECAbank;
  DBLinkPtr fECAPatt;
  std::vector<int> fCurrentPattern;
  std::vector<std::vector<std::vector<int> > > fPatterns;
  int fECAflag;
  int fPassNo;
  int fRunRangeMax;
  std::string fECAIndex;
  UInt_t fRunMask;
  int fECArate;
  int fECAmerge;
  int fECAlogverb;
  int fECAdiff;
  int fRunMerge;
  int fDoDroop;
  // DQIDs
  DBLinkPtr fDQXXbank;
  std::vector<int> fDQID;
  std::vector<int> fECADQID;
  std::vector<int> fECAPrevDQID;
  // Histograms
  ECAHists fHists;
  // Status words
  ECABits fECABits;

  // Results
  // NB charges and TAC in adc counts, therefore ints
  // However if the median falls between 2, it will be a float
  // and float = int = 32-bit, therefore not using any extra space this way
  int fOverallMask;
  std::vector<int> fCellStatus;
  std::vector<int> fTestChannel;
  int fNChanNotTested;

  // Pedestals and widths
  std::vector<double> fCellQHS;
  std::vector<double> fCellQHL;
  std::vector<double> fCellQLX;
  std::vector<double> fCellTAC;
  std::vector<double> fCellSigQHS;   // Estimate of 1 sigma spread of points
  std::vector<double> fCellSigQHL;
  std::vector<double> fCellSigQLX;
  std::vector<double> fCellSigTAC;
  std::vector<double> fCellWidthQHS; // P80-P50, used for width tests (from SNO)
  std::vector<double> fCellWidthQHL;
  std::vector<double> fCellWidthQLX;
  std::vector<double> fCellWidthTAC;
  std::vector<std::vector<int> > fCellNo;  // store cell# for 1st 16 ev on each chan

  // Tslopes
  // number of entries needed for TSlope-point flags per cell
  //(32-bits per word therefore NPoints/32 entries needed)
  int fNdim;

  // Flag bad points in a TAC slope for a single cell (32-bit word per cell)
  std::vector<std::vector<int> > fCellBad;
  // Flag suspicious points in a TAC slope for a single cell
  std::vector<std::vector<int> > fCellSusp;
  std::vector<std::vector<int> > fCellCurl;  // points on TAC slope that are in the curl region
  // Arrays to hold median/width at each point, and fit parameters, per cell
  std::vector<std::vector<double> > fCellTACPoints;  // 2D array of fNTotCell cells
                                             // * (31 tac points) per cell
  std::vector<std::vector<double> > fCellTACrms;  // 2D array of fNTotCell cells
                                             // * (31 tac points) per cell
  std::vector<std::vector<double> > fCellTACwidth;
  std::vector<std::vector<double> > fCellTACFits;  // 2D array of fNTotCell cells
                                             // * (4 fit pars) per cell
  // X values should be the same for every cell, and every event; but are floats!
  std::vector<double> fEVTACX;
  // Last good point on slope, in ADC counts
  //std::vector<int> fLastTAC;

  // Previous ECA numbers
  std::vector<int> fPrevStatus;
  std::vector<double> fPrevQHS;
  std::vector<double> fPrevQHL;
  std::vector<double> fPrevQLX;
  std::vector<double> fPrevTAC;
  std::vector<double> fPrevSigQHS;
  std::vector<double> fPrevSigQHL;
  std::vector<double> fPrevSigQLX;
  std::vector<double> fPrevSigTAC;
  std::vector<std::vector<int> > fPrevBad;
  std::vector<std::vector<double> > fPrevTACPoints;
  std::vector<std::vector<double> > fPrevTACFits;
  std::vector<double> fPrevEVTACX;
  //std::vector<int> fPrevLast;

  // Number of events per cell (for pedestals)
  std::vector<int> fNevCell;
  // Number of events per point on slope, per cell (Tslope)
  // i.e. fNevTACSlp[cell number][point number] = Nevents
  std::vector<std::vector<int> > fNevTACSlp;

  // Actual event values per cell (a length-fNMaxEV array per cell)
  // e.g. fEVQHS[cell #][event #] = qhs
  std::vector<std::vector<int> > fEVQHS;
  std::vector<std::vector<int> > fEVQHL;
  std::vector<std::vector<int> > fEVQLX;
  std::vector<std::vector<int> > fEVTAC;
  // per-cell array of fNSlopepoints, fNMaxEV events each
  // e.g. fEVTACPoints[cell #][slope point][event #] = measured T (V in adc counts)
  std::vector<std::vector<std::vector<int> > > fEVTACPoints;

  int fNMaxEV;
  // kate
  int fLastPatternID;
  int fTimeSkipped;
  //extra diagnostics
  int fSuperDebug;
  std::string fTSlopesRootName;
  TFile* fTSlopesRootFile;
  std::vector<TGraphErrors*> fTSlopes;
  std::vector<TF1*> fLinearFits;
  std::vector<TF1*> fCubicFits;
  TH1F* fTrigWordHist;
  TH1F* fTrigWordHistSkippedEV;
  TH1F* fResetTimes;
  std::string fECAdebugdbname;
  omtext ecadebugrecord;
  oftext fECAdebugdbfile;
  std::string fECAdebugname;
  std::vector<std::vector<float> > fCellTACFitErrs;  // 2D array of fNTotCell cells  // * (4 fit parerrs) per cell
  std::string fECAdebughistosname;
  TFile* fdebughistosROOTfile;
  TH1F* fb0_NHit100Lo;
  TH1F* fb1_NHit100Med;
  TH1F* fb2_NHit100Hi;
  TH1F* fb3_NHit20;
  TH1F* fb4_NHit20LB;
  TH1F* fb5_ESumLo;
  TH1F* fb6_ESumHi;
  TH1F* fb7_OWLN;
  TH1F* fb8_OWLELo;
  TH1F* fb9_OWLEHi;
  TH1F* fb10_PulseGT;
  TH1F* fb11_Prescale;
  TH1F* fb12_Pedestal;
  TH1F* fb13_Pong;
  TH1F* fb14_Sync;
  TH1F* fb15_EXTASY;
  TH1F* fb16_Ext2;
  TH1F* fb17_Ext3;
  TH1F* fb18_Ext4;
  TH1F* fb19_Ext5;
  TH1F* fb20_Ext6;
  TH1F* fb21_Ext7;
  TH1F* fb22_Ext8PulseAsync;
  TH1F* fb23_SpecialRaw;
  TH1F* fb24_NCD;
  TH1F* fb25_SoftGT;
  TH1F* fb26_MissedTrig;

  int fRunNo;
  int fNcrate;
  int fNcard;
  int fNchannel;
  int fNcell;
  int fTotChannel;
  int fNTotCell;
  int fNDSEvents;
  int fNSlopePoints;
  int fPrevNSlopePoints;
  int fNTACFitPars;
  float fMedian;
  float fWidth;
  float fWidth2;
  float fSig;
  BitManip *fBits;
  bool isSNOdata;

  UInt_t fGTDelC;
  UInt_t fGTDelF;
  UInt_t fPattern;
  UInt_t fCalType;
  UInt_t fPattSet;
  UInt_t fPedWidth;
  UInt_t fNumSkip;
  UInt_t fHitSkip;
  float fTinj;
  int fArrayID;
  int fNSet;
  std::vector<int> fNPatt;

  float fDAQns_offset;
  float fDAQns_max;
  float fDAQns_scale1;
  float fDAQns_scale2;

  // For output
  omtext ecalog;
  std::string fECAlogname;
  std::string fECAdbname;
  std::string fECAmoniname;
  std::string fECArootname;
  oftext fECAlogfile;
  oftext fECAdbfile;
  TFile *fECArootfile;

};

extern omtext ecalog;

} // namespace RAT
#endif