#ifndef MARS_MCalibrationChargeCalc
#define MARS_MCalibrationChargeCalc

/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// MCalibrationChargeCalc                                                   //
//                                                                         //
// Integrates the time slices of the all pixels of a calibration event     //
// and substract the pedestal value                                        //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

#ifndef MARS_MTask
#include "MTask.h"
#endif

#ifndef MARS_MBadPixelsPix
#include "MBadPixelsPix.h"
#endif

#ifndef MARS_MCalibrationCam
#include "MCalibrationCam.h"
#endif

class MRawEvtData;
class MRawRunHeader;
class MPedestalCam;
class MPedestalPix;
class MCalibrationChargePINDiode;
class MCalibrationChargeBlindPix;
class MCalibrationChargePix;
class MCalibrationChargeCam;
class MCalibrationQECam;
class MGeomCam;
class MExtractedSignalCam;
class MExtractedSignalBlindPixel;
class MExtractedSignalPINDiode;
class MBadPixelsCam;
class MBadPixelsPix;
class MTime;
class MCalibrationChargeCalc : public MTask
{
private:

  static const Float_t fgChargeLimit;            //! Default for fChargeLimit            (now set to: 3.)
  static const Float_t fgChargeErrLimit;         //! Default for fChargeErrLimit         (now set to: 0.)
  static const Float_t fgChargeRelErrLimit;      //! Default for fChargeRelErrLimit      (now set to: 1.)
  static const Float_t fgLambdaCheckLimit;       //! Default for fLambdaCheckLimit       (now set to: 0.2)
  static const Float_t fgLambdaErrLimit;         //! Default for fLabmdaErrLimit         (now set to: 0.2)
  static const Float_t fgPheErrLimit;            //! Default for fPheErrLimit            (now set to: 5.)
  static const Float_t fgTimeLowerLimit;         //! Default for fTimeLowerLimit         (now set to: 1.) 
  static const Float_t fgTimeUpperLimit;         //! Default for fTimeUpperLimit         (now set to: 2.)
  
  Float_t fChargeLimit;            // Limit (in units of PedRMS) for acceptance of mean charge
  Float_t fChargeErrLimit;         // Limit (in units of PedRMS) for acceptance of charge sigma square
  Float_t fChargeRelErrLimit;      // Limit (in units of Sigma of fitted charge) for acceptance of mean  
  Float_t fLambdaCheckLimit;       // Limit for rel. diff. lambda and lambdacheck blind pixel
  Float_t fLambdaErrLimit;         // Limit for acceptance of lambda error blind pixel
  Float_t fPheErrLimit;            // Limit for acceptance number phe's w.r.t area index mean (in sigmas)
  Float_t fTimeLowerLimit;         // Limit (in units of FADC slices) for dist. to first signal slice
  Float_t fTimeUpperLimit;         // Limit (in units of FADC slices) for dist. to last signal slice

  MPedestalCam               *fPedestals;     //! Pedestals of all pixels in the camera
  MCalibrationChargeCam      *fCam;           // Calibration events of all pixels in the camera
  MCalibrationQECam          *fQECam;         // Derived Quantum efficiency of all pixels in the camera  
  MRawEvtData                *fRawEvt;        //! raw event data (time slices)
  MRawRunHeader              *fRunHeader;     //! RunHeader information
  MGeomCam                   *fGeom;          //! Geometry information
  MBadPixelsCam              *fBadPixels;     //! Bad Pixels information
  
  MTime                      *fEvtTime;       //! Time of the event

  MExtractedSignalCam        *fSignals;       //! Extracted signal of pixels in the camera
  MExtractedSignalBlindPixel *fSigBlind;      //! Extracted signal of Blind Pixel
  MExtractedSignalPINDiode   *fSigPIN;        //! Extracted signal of PIN Diode 

  MCalibrationChargePINDiode *fPINDiode;      // Calibration results of the PIN Diode
  MCalibrationChargeBlindPix *fBlindPixel;    // Calibration results of the Blind Pixel 

  Float_t  fNumHiGainSamples; 
  Float_t  fNumLoGainSamples; 
  Float_t  fSqrtHiGainSamples;
  Float_t  fSqrtLoGainSamples; 
  
  Float_t fConversionHiLo;
  Int_t   fFlags;                              // Flag for the fits used

  enum  { kUseQualityChecks, kHiLoGainCalibration };

  MCalibrationCam::PulserColor_t fPulserColor;
  
  Int_t  PreProcess(MParList *pList);
  Bool_t ReInit(MParList *pList); 
  Int_t  Process();
  Int_t  PostProcess();

  void   FinalizePedestals   ( const MPedestalPix &ped, MCalibrationChargePix &cal,
                               Float_t &avped, Float_t &avrms);
  void   FinalizeAvPedestals ( MCalibrationChargePix &cal, Float_t avped, Float_t avrms, Int_t avnum);
  Bool_t FinalizeCharges     ( MCalibrationChargePix &cal, MBadPixelsPix &bad );
  Bool_t FinalizePINDiode();
  Bool_t FinalizeBlindPixel();
  Bool_t FinalizeFFactorMethod();
  void   FinalizeBadPixels();
  void   FinalizeFFactorQECam();  
  void   FinalizeBlindPixelQECam();
  void   FinalizePINDiodeQECam();
  
  void PrintUnsuitable(MBadPixelsPix::UnsuitableType_t typ, const char *text) const;   
  void PrintUncalibrated(MBadPixelsPix::UncalibratedType_t typ, const char *text) const;

public:

  MCalibrationChargeCalc(const char *name=NULL, const char *title=NULL);

  void Clear(const Option_t *o="");
  
  void SetChargeLimit      ( const Float_t f=fgChargeLimit       ) { fChargeLimit       = f;   }
  void SetChargeErrLimit   ( const Float_t f=fgChargeErrLimit    ) { fChargeErrLimit    = f;   }
  void SetChargeRelErrLimit( const Float_t f=fgChargeRelErrLimit ) { fChargeRelErrLimit = f;   }
  void SetPheErrLimit      ( const Float_t f=fgPheErrLimit       ) { fPheErrLimit       = f;   }  
  void SetLambdaErrLimit   ( const Float_t f=fgLambdaErrLimit    ) { fLambdaErrLimit    = f;   }
  void SetLambdaCheckLimit ( const Float_t f=fgLambdaCheckLimit  ) { fLambdaCheckLimit  = f;   }
  void SetPulserColor      ( MCalibrationCam::PulserColor_t col  ) { fPulserColor       = col; }
  void SetTimeLowerLimit   ( const Float_t f=fgTimeLowerLimit    ) { fTimeLowerLimit    = f;   }
  void SetTimeUpperLimit   ( const Float_t f=fgTimeUpperLimit    ) { fTimeUpperLimit    = f;   }

  void SkipQualityChecks(Bool_t b=kTRUE)
      {b ? CLRBIT(fFlags, kUseQualityChecks)    : SETBIT(fFlags, kUseQualityChecks);}
  void SkipHiLoGainCalibration(Bool_t b=kTRUE)
      {b ? CLRBIT(fFlags, kHiLoGainCalibration) : SETBIT(fFlags, kHiLoGainCalibration);}

  ClassDef(MCalibrationChargeCalc, 1)   // Task to fill the Calibration Containers from raw data
};

#endif
