#ifndef MARS_MCalibrationChargeCalc
#define MARS_MCalibrationChargeCalc

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

#ifndef ROOT_TArrayC
#include <TArrayC.h>
#endif

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

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

class MCalibrationPattern;
class MPedestalCam;
class MPedestalPix;
class MCalibrationChargePINDiode;
class MHCalibrationChargeBlindCam;
class MCalibrationIntensityBlindCam;
class MCalibrationBlindCam;
class MCalibrationChargePix;
class MCalibrationIntensityChargeCam;
class MCalibrationChargeCam;
class MHCalibrationChargeCam;
class MCalibrationIntensityQECam;
class MCalibrationQECam;
class MGeomCam;
class MExtractedSignalCam;
class MBadPixelsIntensityCam;
class MBadPixelsCam;
class MExtractor;

class MCalibrationChargeCalc : public MTask
{
private:

  static const Float_t fgChargeLimit;          //! Default for fChargeLimit        (now set to: 2.5)
  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.5)
  static const Float_t fgPheErrLowerLimit;     //! Default for fPheErrLowerLimit   (now set to: 9.0)
  static const Float_t fgPheErrUpperLimit;     //! Default for fPheErrUpperLimit   (now set to: 4.5)
  static const Float_t fgFFactorErrLimit;      //! Default for fFFactorErrLimit    (now set to: 4.5)
  static const Float_t fgArrTimeRmsLimit;      //! Default for fArrTimeRmsLimit    (now set to: 3.5)
 
  static const TString fgNamePedestalCam;      //! "MPedestalCam"
  
  // Variables
  Float_t fChargeLimit;                        // Limit acceptance mean charge  (in units of PedRMS)
  Float_t fChargeErrLimit;                     // Limit acceptance charge error (in abs. numbers)
  Float_t fChargeRelErrLimit;                  // Limit acceptance rel. error mean (in abs. numbers)
  Float_t fLambdaCheckLimit;                   // Limit rel. diff. lambda and lambdacheck in Blind Pixel
  Float_t fLambdaErrLimit;                     // Limit acceptance lambda error in Blind Pixel
  Float_t fNumHiGainSamples;                   // Number High-Gain FADC slices used by extractor
  Float_t fNumLoGainSamples;                   // Number Low -Gain FADC slices used by extractor
  Float_t fPheErrLowerLimit;                   // Lower limit acceptance nr. phe's w.r.t. area idx mean (in sigmas)
  Float_t fPheErrUpperLimit;                   // Upper limit acceptance nr. phe's w.r.t. area idx mean (in sigmas)
  Float_t fFFactorErrLimit;                    // Limit acceptance F-Factor w.r.t. area idx mean
  Float_t fArrTimeRmsLimit;                    // Limit acceptance RMS of absolute arrival times
  Float_t fSqrtHiGainSamples;                  // Square root nr. High-Gain FADC slices used by extractor
  Float_t fSqrtLoGainSamples;                  // Square root nr. Low -Gain FADC slices used by extractor 

  MCalibrationCam::PulserColor_t fPulserColor; // Calibration LEDs colour 
  Float_t fStrength;                           // Calibration LEDs strength 

  Int_t   fNumInnerFFactorMethodUsed;          // Number of inner pixels used for F-Factor Method calibration

  Byte_t  fFlags;                              // Bit-field for the general flags
  TArrayC fResultFlags;                        // Bit-fields for the fitting results   (one field per area index)
  TArrayC fBlindPixelFlags;                    // Bit-fields for the blind pixel flags (one field per blind pixel)
  TArrayC fPINDiodeFlags;                      // Bit-fields for the PIN Diode flags   (one field per PIN Diode  )
  
  TString fOutputPath;                         // Path to the output file
  TString fOutputFile;                         // Name of the output file  
  TString fNamePedestalCam;                    // Name of the 'MPedestalCam' container

  Int_t   fNumProcessed;                       // Number of processed events (for Intensity calibration)
  Bool_t  fUseExtractorRes;                    // Include extractor resolution in F-Factor method
  
  // Pointers
  MBadPixelsIntensityCam         *fIntensBad;      //!  Bad Pixels  
  MBadPixelsCam                  *fBadPixels;      //!  Bad Pixels
  MCalibrationIntensityChargeCam *fIntensCam;      //!  Intensity Calibration results of all pixels   
  MCalibrationChargeCam          *fCam;            //!  Calibrated Charges results of all pixels
  MHCalibrationChargeCam         *fHCam;           //!  Charges histograms of all pixels   
  MCalibrationIntensityBlindCam  *fIntensBlind;    //!  Intensity Calibration results of the Blind Pixels
  MCalibrationBlindCam           *fBlindCam;       //!  Calibrated Charges of the Blind Pixels
  MHCalibrationChargeBlindCam    *fHBlindCam;      //!  Charges histograms of the Blind Pixels  
  MCalibrationChargePINDiode     *fPINDiode;       //!  Calibrated Charges of the PIN Diode
  MCalibrationIntensityQECam     *fIntensQE;       //!  Intensity Calibration Quantum Efficiencies of all pixels
  MCalibrationQECam              *fQECam;          //!  Calibrated Quantum Efficiencies of all pixels 
  MGeomCam                       *fGeom;           //!  Camera geometry
  MExtractedSignalCam            *fSignal;         //! Extracted Signal
  MCalibrationPattern            *fCalibPattern;   //! Calibration DM pattern
  MPedestalCam                   *fPedestals;      //! Pedestals all pixels (calculated previously from ped.file)
  MExtractor                     *fExtractor;      //! Signal Extractor

  // enums
  enum  Check_t
    {
      kCheckDeadPixels,
      kCheckExtractionWindow,
      kCheckHistOverflow,
      kCheckDeviatingBehavior,
      kCheckOscillations,
      kCheckArrivalTimes
    };                                         // Possible Checks

  Byte_t fCheckFlags;                          // Bit-field to hold the possible check flags
  
  enum  { kDebug,
          kPheFitOK, kFFactorFitOK, kBlindPixelFitOK, kBlindPixelPedFitOK, kPINDiodeFitOK };

  // functions
  void   FinalizePedestals       ( const MPedestalPix    &ped, MCalibrationChargePix &cal, const Int_t aidx );
  void   FinalizeArrivalTimes    ( MCalibrationChargePix &cal, MBadPixelsPix &bad, const char* what);
  Bool_t FinalizeCharges         ( MCalibrationChargePix &cal, MBadPixelsPix &bad, const char* what);
  Bool_t FinalizePINDiode        ();
  Bool_t FinalizeBlindCam        ();  
  Bool_t FinalizeFFactorMethod   ();
  void   FinalizeBadPixels       ();
  void   FinalizeFFactorQECam    ();  
  void   FinalizeBlindPixelQECam ();
  void   FinalizePINDiodeQECam   ();
  void   FinalizeCombinedQECam   ();
  void   FinalizeUnsuitablePixels();

  const char* GetOutputFile();

  // Query checks
  Bool_t IsCheckDeadPixels       () const { return TESTBIT(fCheckFlags,kCheckDeadPixels);        }
  Bool_t IsCheckDeviatingBehavior() const { return TESTBIT(fCheckFlags,kCheckDeviatingBehavior); }
  Bool_t IsCheckExtractionWindow () const { return TESTBIT(fCheckFlags,kCheckExtractionWindow);  }
  Bool_t IsCheckHistOverflow     () const { return TESTBIT(fCheckFlags,kCheckHistOverflow);      }
  Bool_t IsCheckOscillations     () const { return TESTBIT(fCheckFlags,kCheckOscillations);      }
  Bool_t IsCheckArrivalTimes     () const { return TESTBIT(fCheckFlags,kCheckArrivalTimes);      }

  void   PrintUncalibrated( MBadPixelsPix::UncalibratedType_t typ, const char *text) const;

  // Global fit results
  void   SetPheFitOK          ( const Int_t aidx, const Bool_t b=kTRUE ) {
    b ? SETBIT(fResultFlags[aidx], kPheFitOK) 
      : CLRBIT(fResultFlags[aidx], kPheFitOK);      }
  void   SetFFactorFitOK      ( const Int_t aidx, const Bool_t b=kTRUE ) {
    b ? SETBIT(fResultFlags[aidx], kFFactorFitOK) 
      : CLRBIT(fResultFlags[aidx], kFFactorFitOK);  }
  void   SetBlindPixelFitOK   ( const Int_t  idx, const Bool_t b=kTRUE ) {
    b ? SETBIT(fBlindPixelFlags[idx], kBlindPixelFitOK) 
      : CLRBIT(fBlindPixelFlags[idx], kBlindPixelFitOK); }
  void   SetBlindPixelPedFitOK( const Int_t  idx, const Bool_t b=kTRUE ) {
    b ? SETBIT(fBlindPixelFlags[idx], kBlindPixelPedFitOK) 
      : CLRBIT(fBlindPixelFlags[idx], kBlindPixelPedFitOK); }
  void   SetPINDiodeFitOK     ( const Int_t  idx, const Bool_t b=kTRUE ) {
    b ? SETBIT(fPINDiodeFlags[idx], kPINDiodeFitOK) 
      : CLRBIT(fPINDiodeFlags[idx], kPINDiodeFitOK); }

  Int_t  PreProcess (MParList *pList);
  Bool_t ReInit     (MParList *pList); 
  Int_t  Process    ();
  Int_t  PostProcess();
  Int_t  ReadEnv(const TEnv &env, TString prefix, Bool_t print);

public:

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

  void Clear(const Option_t *o="");

  Int_t Finalize();

  Bool_t IsDebug() const   {  return TESTBIT(fFlags,kDebug); }
  
  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;     }

  // Checks
  void SetCheckArrivalTimes( const Bool_t b=kTRUE ) {
    b ? SETBIT(fCheckFlags,kCheckArrivalTimes)
      : CLRBIT(fCheckFlags,kCheckArrivalTimes); }
  void SetCheckDeadPixels( const Bool_t b=kTRUE ) {
    b ? SETBIT(fCheckFlags,kCheckDeadPixels)
      : CLRBIT(fCheckFlags,kCheckDeadPixels); }
  void SetCheckDeviatingBehavior( const Bool_t b=kTRUE ) {
    b ? SETBIT(fCheckFlags,kCheckDeviatingBehavior)
      : CLRBIT(fCheckFlags,kCheckDeviatingBehavior); }
  void SetCheckExtractionWindow( const Bool_t b=kTRUE ) {
    b ? SETBIT(fCheckFlags,kCheckExtractionWindow)
      : CLRBIT(fCheckFlags,kCheckExtractionWindow); }
  void SetCheckHistOverflow( const Bool_t b=kTRUE ) {
    b ? SETBIT(fCheckFlags,kCheckHistOverflow)
      : CLRBIT(fCheckFlags,kCheckHistOverflow); }
  void SetCheckOscillations( const Bool_t b=kTRUE ) {
    b ? SETBIT(fCheckFlags,kCheckOscillations)
      : CLRBIT(fCheckFlags,kCheckOscillations); }
  void SetDebug            ( const Bool_t b=kTRUE ) { 
    b ? SETBIT(fFlags, kDebug) 
      : CLRBIT(fFlags, kDebug); }

  void SetExtractor(MExtractor   *ext) { fExtractor=ext; }
  void SetPedestals(MPedestalCam *cam) { fPedestals=cam; }
									 
  void SetArrTimeRmsLimit   ( const Float_t f=fgArrTimeRmsLimit        ) { fArrTimeRmsLimit   = f;     }
  void SetFFactorErrLimit   ( const Float_t f=fgFFactorErrLimit        ) { fFFactorErrLimit   = f;     }
  void SetLambdaErrLimit    ( const Float_t f=fgLambdaErrLimit         ) { fLambdaErrLimit    = f;     }
  void SetLambdaCheckLimit  ( const Float_t f=fgLambdaCheckLimit       ) { fLambdaCheckLimit  = f;     }
  void SetNamePedestalCam   ( const char *name=fgNamePedestalCam.Data()) { fNamePedestalCam   = name;  }
  void SetOutputPath        ( TString path="."                   );
  void SetOutputFile        ( TString file="ChargeCalibStat.txt" );
  void SetPheErrLowerLimit  ( const Float_t f=fgPheErrLowerLimit       ) { fPheErrLowerLimit  = f;     }
  void SetPheErrUpperLimit  ( const Float_t f=fgPheErrUpperLimit       ) { fPheErrUpperLimit  = f;     }
  void SetPulserColor       ( const MCalibrationCam::PulserColor_t col ) { fPulserColor       = col;   }
  void SetUseExtractorRes(Bool_t b=kTRUE) { fUseExtractorRes = b; }

  ClassDef(MCalibrationChargeCalc, 3)   // Task calculating Calibration Containers and Quantum Efficiencies
};

#endif
