#ifndef MARS_MBadPixelsPix
#define MARS_MBadPixelsPix

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

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

class MBadPixelsPix : public MParContainer
{
private:
    TArrayC fInfo;

public:
    MBadPixelsPix(const char* name=NULL, const char* title=NULL);

    enum UnsuitableType_t {
        kUnsuitableRun    = BIT(1),
        kUnsuitableEvt    = BIT(2)
    };

    enum CalibrationType_t {
      kHiGainSaturation      = BIT(1),
      kLoGainSaturation      = BIT(2),
      kHiGainFitted          = BIT(3),
      kLoGainFitted          = BIT(4), 
      kCalcChargePedestal    = BIT(5),
      kCalcChargeErrValid    = BIT(6),
      kCalcChargeRelErrValid = BIT(7),
      kCalcChargeSigmaValid  = BIT(8),
      kConversionHiLoValid   = BIT(9),      
      kHiGainOscillating     = BIT(10),
      kLoGainOscillating     = BIT(11),
      kMeanTimeInFirstBin    = BIT(12),
      kMeanTimeInLastBin     = BIT(13), 
      kBlindPixelMethodValid = BIT(14),
      kFFactorMethodValid    = BIT(15), 
      kPINDiodeMethodValid   = BIT(16),
      kCombinedMethodValid   = BIT(17)
    };
    
      
    static const Char_t fgRunMask; // All types which are not event wise determined

    void Reset();
    void Clear(Option_t *o="");
    void Copy(TObject &object) const
    {
        static_cast<MBadPixelsPix&>(object).fInfo = fInfo;
    }

    // Setter
    void   SetUnsuitableRun(UnsuitableType_t typ=kUnsuitableRun) { fInfo[0] |=  typ; }
    void   SetSuitableRun(UnsuitableType_t typ=kUnsuitableRun)   { fInfo[0] &= ~typ; }

    void   SetUnsuitableEvt(UnsuitableType_t typ=kUnsuitableEvt) { fInfo[0] |=  typ; }
    void   SetSuitableEvt(UnsuitableType_t typ=kUnsuitableEvt)   { fInfo[0] &= ~typ; }

    // Calibration
    void   SetHiGainSaturation  ( CalibrationType_t typ=kHiGainSaturation )   { fInfo[1] |=  typ; }
    void   SetNoHiGainSaturation( CalibrationType_t typ=kHiGainSaturation )   { fInfo[1] &= ~typ; }

    void   SetLoGainSaturation  ( CalibrationType_t typ=kLoGainSaturation )   { fInfo[1] |=  typ; }
    void   SetNoLoGainSaturation( CalibrationType_t typ=kLoGainSaturation )   { fInfo[1] &= ~typ; }

    void   SetCombinedMethodValid  ( CalibrationType_t typ=kCombinedMethodValid )   { fInfo[1] |=  typ; }
    void   SetNoCombinedMethodValid( CalibrationType_t typ=kCombinedMethodValid )   { fInfo[1] &= ~typ; }

    void   SetPINDiodeMethodValid  ( CalibrationType_t typ=kPINDiodeMethodValid )   { fInfo[1] |=  typ; }
    void   SetNoPINDiodeMethodValid( CalibrationType_t typ=kPINDiodeMethodValid )   { fInfo[1] &= ~typ; }

    void   SetFFactorMethodValid  ( CalibrationType_t typ=kFFactorMethodValid )   { fInfo[1] |=  typ; }
    void   SetNoFFactorMethodValid( CalibrationType_t typ=kFFactorMethodValid )   { fInfo[1] &= ~typ; }

    void   SetBlindPixelMethodValid  ( CalibrationType_t typ=kBlindPixelMethodValid )   { fInfo[1] |=  typ; }
    void   SetNoBlindPixelMethodValid( CalibrationType_t typ=kBlindPixelMethodValid )   { fInfo[1] &= ~typ; }

    void   SetMeanTimeInLastBin  ( CalibrationType_t typ=kMeanTimeInLastBin )   { fInfo[1] |=  typ; }
    void   SetNoMeanTimeInLastBin( CalibrationType_t typ=kMeanTimeInLastBin )   { fInfo[1] &= ~typ; }

    void   SetMeanTimeInFirstBin  ( CalibrationType_t typ=kMeanTimeInFirstBin )   { fInfo[1] |=  typ; }
    void   SetNoMeanTimeInFirstBin( CalibrationType_t typ=kMeanTimeInFirstBin )   { fInfo[1] &= ~typ; }

    void   SetLoGainOscillating  ( CalibrationType_t typ=kLoGainOscillating )   { fInfo[1] |=  typ; }
    void   SetNoLoGainOscillating( CalibrationType_t typ=kLoGainOscillating )   { fInfo[1] &= ~typ; }

    void   SetHiGainOscillating  ( CalibrationType_t typ=kHiGainOscillating )   { fInfo[1] |=  typ; }
    void   SetNoHiGainOscillating( CalibrationType_t typ=kHiGainOscillating )   { fInfo[1] &= ~typ; }

    void   SetConversionHiLoValid  ( CalibrationType_t typ=kConversionHiLoValid )   { fInfo[1] |=  typ; }
    void   SetNoConversionHiLoValid( CalibrationType_t typ=kConversionHiLoValid )   { fInfo[1] &= ~typ; }

    void   SetCalcChargeSigmaValid  ( CalibrationType_t typ=kCalcChargeSigmaValid )   { fInfo[1] |=  typ; }
    void   SetNoCalcChargeSigmaValid( CalibrationType_t typ=kCalcChargeSigmaValid )   { fInfo[1] &= ~typ; }

    void   SetCalcChargeRelErrValid  ( CalibrationType_t typ=kCalcChargeRelErrValid )   { fInfo[1] |=  typ; }
    void   SetNoCalcChargeRelErrValid( CalibrationType_t typ=kCalcChargeRelErrValid )   { fInfo[1] &= ~typ; }

    void   SetCalcChargeErrValid  ( CalibrationType_t typ=kCalcChargeErrValid )   { fInfo[1] |=  typ; }
    void   SetNoCalcChargeErrValid( CalibrationType_t typ=kCalcChargeErrValid )   { fInfo[1] &= ~typ; }

    void   SetCalcChargePedestal  ( CalibrationType_t typ=kCalcChargePedestal )   { fInfo[1] |=  typ; }
    void   SetNoCalcChargePedestal( CalibrationType_t typ=kCalcChargePedestal )   { fInfo[1] &= ~typ; }

    void   SetLoGainFitted  ( CalibrationType_t typ=kLoGainFitted )   { fInfo[1] |=  typ; }
    void   SetNoLoGainFitted( CalibrationType_t typ=kLoGainFitted )   { fInfo[1] &= ~typ; }

    void   SetHiGainFitted  ( CalibrationType_t typ=kHiGainFitted )   { fInfo[1] |=  typ; }
    void   SetNoHiGainFitted( CalibrationType_t typ=kHiGainFitted )   { fInfo[1] &= ~typ; }

    // Getter
    Bool_t IsUnsuitableRun(UnsuitableType_t typ=kUnsuitableRun) const { return   fInfo[0]&typ; }
    Bool_t IsSuitableRun(UnsuitableType_t typ=kUnsuitableRun) const   { return !(fInfo[0]&typ); }

    Bool_t IsUnsuitableEvt(UnsuitableType_t typ=kUnsuitableEvt) const { return   fInfo[0]&typ; }
    Bool_t IsSuitableEvt(UnsuitableType_t typ=kUnsuitableEvt) const   { return !(fInfo[0]&typ); }

    Bool_t IsOK() const  { return fInfo[0]==0; }
    Bool_t IsBad() const { return fInfo[0]!=0; }

    Bool_t IsLoGainBad() const { return (fInfo[1]&kLoGainSaturation
                                         || !(fInfo[1]&kConversionHiLoValid)
                                         || fInfo[1]&kLoGainOscillating ); }    
    Bool_t IsHiGainBad() const { return ( fInfo[1]&kHiGainSaturation
                                           && !(fInfo[1]&kConversionHiLoValid) )
                                   || fInfo[1]&kHiGainOscillating ;    }
    Bool_t IsCalibrationSignalOK() const  { return !( fInfo[1]&kCalcChargePedestal
                                                     || !(fInfo[1]&kCalcChargeErrValid)
                                                     || !(fInfo[1]&kCalcChargeRelErrValid)
                                                     || !(fInfo[1]&kCalcChargeSigmaValid)
                                                     || fInfo[1]&kMeanTimeInFirstBin
                                                     || fInfo[1]&kMeanTimeInLastBin ) ;  }
    Bool_t IsCalibrationFitOK() const    { return ( fInfo[1]&kHiGainSaturation && kHiGainFitted )
                                             || ( fInfo[1]&kLoGainSaturation && kLoGainFitted ) ; }
    Bool_t IsCalibrationOscillating() const  { return ( fInfo[1]&kHiGainSaturation && kHiGainOscillating )
                                                 || ( fInfo[1]&kLoGainSaturation && kLoGainOscillating ) ; }
    Bool_t IsCalibrationResultOK() const  {  return ( IsCalibrationSignalOK()
                                                      && !(IsCalibrationOscillating())
                                                      && IsCalibrationFitOK()
                                                      && (!fInfo[1]&kHiGainSaturation && !(IsHiGainBad())
                                                          || fInfo[1]&kHiGainSaturation && !(IsLoGainBad())) );}
    Bool_t IsCalibrationFFactorMethodOK() const  { return ( IsCalibrationResultOK()
                                                            && (fInfo[1]&kFFactorMethodValid)) ; }
    Bool_t IsCalibrationBlindPixelMethodOK() const  { return ( IsCalibrationResultOK()
                                                            && (fInfo[1]&kBlindPixelMethodValid)) ; }
    Bool_t IsCalibrationPINDiodeMethodOK() const  { return ( IsCalibrationResultOK()
                                                            && (fInfo[1]&kPINDiodeMethodValid)) ; }
    Bool_t IsCalibrationCombinedMethodOK() const  { return ( IsCalibrationResultOK()
                                                            && (fInfo[1]&kCombinedMethodValid)) ; }
    
    void Merge(const MBadPixelsPix &pix);

    const TArrayC &GetInfo() const { return fInfo; }

    ClassDef(MBadPixelsPix, 1)	// Storage Container for bad pixel information of a single pixel
};

#endif

