#ifndef MARS_MJCalibration
#define MARS_MJCalibration

#ifndef MARS_MCalibrationChargeCam
#include "MCalibrationChargeCam.h"
#endif
#ifndef MARS_MCalibrationChargeBlindCam
#include "MCalibrationChargeBlindCam.h"
#endif
#ifndef MARS_MCalibrationChargePINDiode
#include "MCalibrationChargePINDiode.h"
#endif
#ifndef MARS_MCalibrationRelTimeCam
#include "MCalibrationRelTimeCam.h"
#endif
#ifndef MARS_MCalibrationQECam
#include "MCalibrationQECam.h"
#endif
#ifndef MARS_MBadPixelsCam
#include "MBadPixelsCam.h"
#endif

class TEnv;
class MRunIter;
class MSequence;
class MParList;
class MPedestalCam;
class MExtractor;
class MExtractTime;

class MExtractBlindPixel;
class MHCalibrationChargeBlindCam;

class MJCalibration : public MParContainer
{
private:
    static const Int_t gkIFAEBoxInaugurationRun;         // Run number of first IFAE box calibration
    static const Int_t gkSecondBlindPixelInstallation;   // Run number upon which second blind pixel was installed
    static const Int_t gkThirdBlindPixelInstallation;    // Run number upon which third blind pixel was installed

    TString fOutputPath;                                 // Path to the output files

    TEnv           *fEnv;
    MRunIter       *fRuns;                               // Calibration files
    MSequence      *fSequence;                           // Sequence

    MExtractor     *fExtractor;                          // Signal extractor
    MExtractTime   *fTimeExtractor;                      // Arrival Time extractor

    MBadPixelsCam              fBadPixels;               // Bad Pixels cam, can be set from previous runs
    MCalibrationChargeCam      fCalibrationCam;          // Calibration conversion factors FADC2Phe
    MCalibrationChargeBlindCam fCalibrationBlindCam;     // Calibration from Blind Pixel(s)
    MCalibrationChargePINDiode fCalibrationPINDiode;     // Calibration from PIN Diode
    MCalibrationQECam          fQECam;                   // Quantum efficiency, can be set from previous runs
    MCalibrationRelTimeCam     fRelTimeCam;              // Calibration constants rel. times

    MCalibrationCam::PulserColor_t fColor;               // Colour of the pulsed LEDs

    enum  Display_t                                      // Possible Display types
    {
        kFullDisplay,
        kDataCheckDisplay,
        kNormalDisplay
    };

    Display_t fDisplayType;                              // Chosen Display type

    enum  Device_t                                       // Possible devices for calibration
    {
        kUseBlindPixel,
        kUsePINDiode
    }; 

    Byte_t fDevices;                                     // Bit-field for used devices for calibration

    Bool_t fRelTimes;                                    // Flag if relative times have to be calibrated
    Bool_t fDataCheck;                                   // Flag if the data check is run on raw data
    Bool_t fDebug;

    void   DisplayResult(MParList &plist);
    Bool_t WriteResult();
    void   CheckEnv();

    // WORKAROUNDS!!!
    Bool_t FindColor();
    void   InitBlindPixel(MExtractBlindPixel &blindext,
                          MHCalibrationChargeBlindCam &blindcam);

public:
    MJCalibration(const char *name=NULL, const char *title=NULL);
    ~MJCalibration();
  
    const char* GetOutputFile() const;
    void SetEnv(const char *env);

    MCalibrationChargeCam  &GetCalibrationCam() { return fCalibrationCam; }
    MCalibrationRelTimeCam &GetRelTimeCam()     { return fRelTimeCam;     }
    MCalibrationQECam      &GetQECam()          { return fQECam;          }
    MBadPixelsCam          &GetBadPixels()      { return fBadPixels;      }

    Bool_t IsUseBlindPixel() const;
    Bool_t IsUsePINDiode()   const;

    void SetBadPixels(const MBadPixelsCam &bad)    { bad.Copy(fBadPixels);   }
    void SetExtractor(MExtractor* ext)             { fExtractor = ext; }
    void SetTimeExtractor(MExtractTime* ext)       { fTimeExtractor = ext; }
    void SetQECam(const MCalibrationQECam &qe)     { qe.Copy(fQECam);        }
    void SetColor(const MCalibrationCam::PulserColor_t color) { fColor = color; }

    void SetInput(MRunIter *iter) { fRuns=iter; }
    void SetSequence(MSequence *seq) { fSequence=seq; }
    void SetOutputPath(const char *path=".");

    // Displays
    void SetFullDisplay()      { fDisplayType = kFullDisplay;      }
    void SetDataCheckDisplay() { fDisplayType = kDataCheckDisplay; }
    void SetNormalDisplay()    { fDisplayType = kNormalDisplay;    }

    // Rel. Time
    void SetRelTimeCalibration(const Bool_t b=kTRUE) { fRelTimes = b; }

    // Data Check
    void SetDataCheck(const Bool_t b=kTRUE) { fDataCheck = b; SetDataCheckDisplay(); }

    // Debug
    void SetDebug(const Bool_t b=kTRUE) { fDebug = b; }

    // Devices
    void SetUseBlindPixel(const Bool_t b=kTRUE);
    void SetUsePINDiode(const Bool_t b=kTRUE);
  
    Bool_t ReadCalibrationCam();
    Bool_t ProcessFile(MPedestalCam &pedcam);
    Bool_t Process(MPedestalCam &pedcam);

    ClassDef(MJCalibration, 0) // Tool to run a calibration per pulser colour and intensity
};

#endif
