#ifndef MARS_MCalibrationChargeCam
#define MARS_MCalibrationChargeCam

#ifndef MARS_MParContainer
#include "MParContainer.h"
#endif
#ifndef MARS_MCamEvent
#include "MCamEvent.h"
#endif

class TH1D;
class TH2D;
class TClonesArray;

class MCalibrationChargeBlindPix;
class MCalibrationChargePINDiode;
class MCalibrationChargePix;
class MBadPixelsPix;
class MBadPixelsCam;
class MCalibrationChargeCam : public MParContainer, public MCamEvent
{
private:
  
  static const Float_t gkAverageQE;          // The average quantum efficieny agreed on for the first analysis
  static const Float_t gkAverageQEErr;       // The error of average quantum efficieny 
  
  static const Float_t fgConvFFactorRelErrLimit; // The limit for acceptance of the rel. error of the conversion factor with the FFactor method
  static const Float_t fgPheFFactorRelLimit;     // The rel. limit for acceptance of a calculated number of phe's w.r.t the mean number (in sigma of the error)
  
  Float_t fAverageQE;                // The average quantum efficieny (see Class description)
  Float_t fAverageQEErr;             // The error of the average quantum efficieny (see Class description)
  
  Float_t fConvFFactorRelErrLimit;   // The limit for acceptance of the rel. error of the conversion factor with the FFactor method
  Float_t fPheFFactorRelLimit;       // The rel. limit for acceptance of a calculated number of phe's w.r.t the mean number (in sigma of the error).
  
  Int_t fNumPixels;
  TClonesArray *fPixels;                         //-> Array of MCalibrationPix with fit results

  MCalibrationChargePix *fAverageInnerPix;       //-> Average Pixel of all events
  MCalibrationChargePix *fAverageOuterPix;       //-> Average Pixel of all events
  
  MBadPixelsPix         *fAverageInnerBadPix;    //-> Average Pixel of all events
  MBadPixelsPix         *fAverageOuterBadPix;    //-> Average Pixel of all events
  
  const MCalibrationChargeBlindPix *fBlindPixel; //! Pointer to the Blind Pixel with fit results
  const MCalibrationChargePINDiode *fPINDiode;   //! Pointer to the PIN Diode with fit results

  TH1D* fOffsets;                                //! 
  TH1D* fSlopes;                                 //! 
  
  TH2D* fOffvsSlope;                             //! 

  UInt_t  fNumExcludedPixels;

  Byte_t  fFlags;

  enum  { kFFactorMethodValid, kBlindPixelMethodValid, kPINDiodeMethodValid, kCombinedMethodValid };

  Float_t fMeanFluxPhesInnerPixel;        //  The mean number of photo-electrons in an INNER PIXEL
  Float_t fMeanFluxPhesInnerPixelErr;     //  The uncertainty about the number of photo-electrons INNER PIXEL  
  Float_t fMeanFluxPhesOuterPixel;        //  The mean number of photo-electrons in an INNER PIXEL
  Float_t fMeanFluxPhesOuterPixelErr;     //  The uncertainty about the number of photo-electrons INNER PIXEL  

  Float_t fMeanFluxPhotonsInnerPixel;        //  The mean number of photo-electrons in an INNER PIXEL
  Float_t fMeanFluxPhotonsInnerPixelErr;     //  The uncertainty about the number of photo-electrons INNER PIXEL  
  Float_t fMeanFluxPhotonsOuterPixel;        //  The mean number of photo-electrons in an INNER PIXEL
  Float_t fMeanFluxPhotonsOuterPixelErr;     //  The uncertainty about the number of photo-electrons INNER PIXEL  
  
public:

  MCalibrationChargeCam(const char *name=NULL, const char *title=NULL);
  ~MCalibrationChargeCam();
  
  void Clear(    Option_t *o="" );
  void InitSize( const UInt_t i );

  // Setters   
  void SetAverageQE(          const Float_t qe= gkAverageQE, 
			      const Float_t err=gkAverageQEErr)         { fAverageQE    = qe;           
			                                                  fAverageQEErr = err;         }
  void SetNumPixelsExcluded(  const UInt_t n )            {  fNumExcludedPixels = n; }
  void SetConvFFactorRelErrLimit( const Float_t f=fgConvFFactorRelErrLimit ) { fConvFFactorRelErrLimit = f; }
  void SetPheFFactorRelLimit (  const Float_t f=fgPheFFactorRelLimit )     { fPheFFactorRelLimit = f;    }  

  void SetPINDiode  ( const MCalibrationChargePINDiode *d ) {  fPINDiode   = d;      }
  void SetBlindPixel( const MCalibrationChargeBlindPix *b ) {  fBlindPixel = b;      }

  void SetFFactorMethodValid(    const Bool_t b = kTRUE );
  void SetBlindPixelMethodValid( const Bool_t b = kTRUE );
  void SetPINDiodeMethodValid(   const Bool_t b = kTRUE );  

  // Getters
  Int_t   GetSize()               const;
  UInt_t  GetNumPixels()          const { return fNumPixels; }

  Bool_t  GetConversionFactorFFactor(    Int_t ipx, Float_t &mean, Float_t &err, Float_t &sigma );
  Bool_t  GetConversionFactorBlindPixel( Int_t ipx, Float_t &mean, Float_t &err, Float_t &sigma );
  Bool_t  GetConversionFactorPINDiode(   Int_t ipx, Float_t &mean, Float_t &err, Float_t &sigma );
  Bool_t  GetConversionFactorCombined(   Int_t ipx, Float_t &mean, Float_t &err, Float_t &sigma );

  Float_t GetMeanFluxPhesInnerPixel()     const { return fMeanFluxPhesInnerPixel;     }
  Float_t GetMeanFluxPhesInnerPixelErr()  const { return fMeanFluxPhesInnerPixelErr;  }
  Float_t GetMeanFluxPhesOuterPixel()     const { return fMeanFluxPhesOuterPixel;     }
  Float_t GetMeanFluxPhesOuterPixelErr()  const { return fMeanFluxPhesOuterPixelErr;  }

  Float_t GetMeanFluxPhotonsInnerPixel()     const { return fMeanFluxPhotonsInnerPixel;     }
  Float_t GetMeanFluxPhotonsInnerPixelErr()  const { return fMeanFluxPhotonsInnerPixelErr;  }
  Float_t GetMeanFluxPhotonsOuterPixel()     const { return fMeanFluxPhotonsOuterPixel;     }
  Float_t GetMeanFluxPhotonsOuterPixelErr()  const { return fMeanFluxPhotonsOuterPixelErr;  }

  Bool_t IsBlindPixelMethodValid()   const;
  Bool_t IsPINDiodeMethodValid()     const;  

  // Others
  MCalibrationChargePix &operator[](UInt_t i);
  const MCalibrationChargePix &operator[](UInt_t i) const;

  MCalibrationChargePix *GetAverageInnerPix()              { return fAverageInnerPix; }
  const MCalibrationChargePix *GetAverageInnerPix() const  { return fAverageInnerPix; }

  MCalibrationChargePix *GetAverageOuterPix()              { return fAverageOuterPix; }
  const MCalibrationChargePix *GetAverageOuterPix() const  { return fAverageOuterPix; }

  MBadPixelsPix *GetAverageInnerBadPix()              { return fAverageInnerBadPix; }
  const MBadPixelsPix *GetAverageInnerBadPix() const  { return fAverageInnerBadPix; }

  MBadPixelsPix *GetAverageOuterBadPix()              { return fAverageOuterBadPix; }
  const MBadPixelsPix *GetAverageOuterBadPix() const  { return fAverageOuterBadPix; }

  // Prints
  void Print(Option_t *o="") const;
  
  // Draws
  void DrawPixelContent(Int_t num) const;    
//  void DrawHiLoFits();
  
  // Others
  Bool_t GetPixelContent(Double_t &val, Int_t idx, const MGeomCam &cam, Int_t type=0) const;

  Bool_t CalcMeanFluxPhotonsFFactorMethod(const MGeomCam &geom, const MBadPixelsCam &bad);  

  void   ApplyPINDiodeCalibration(const MGeomCam &geom, const MBadPixelsCam &bad);
  void   ApplyBlindPixelCalibration(const MGeomCam &geom, const MBadPixelsCam &bad);
  void   ApplyFFactorCalibration(const MGeomCam &geom, const MBadPixelsCam &bad);

  ClassDef(MCalibrationChargeCam, 1)	// Container for calibration information of the camera
};

#endif
