#ifndef MARS_MBadPixelsPix
#define MARS_MBadPixelsPix

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

#ifndef ROOT_TArrayI
#include <TArrayI.h>
#endif

class MBadPixelsPix : public MParContainer
{
private:
    TArrayI fInfo;

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

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

    static const Int_t fgRunMask; // All types which are not event wise determined

    // All types are initialized to normal behaviour
    enum CalibrationType_t {
      kHiGainSaturation         = BIT(1),
      kLoGainSaturation         = BIT(2),
      kHiGainNotFitted          = BIT(3),
      kLoGainNotFitted          = BIT(4), 
      kChargeIsPedestal         = BIT(5),
      kChargeErrNotValid        = BIT(6),
      kChargeRelErrNotValid     = BIT(7),
      kChargeSigmaNotValid      = BIT(8),
      kConvHiLoNotValid         = BIT(9),      
      kHiGainOscillating        = BIT(10),
      kLoGainOscillating        = BIT(11),
      kMeanTimeInFirstBin       = BIT(12),
      kMeanTimeInLastBin        = BIT(13), 
      kNotCalibrated            = BIT(14)   
    };
    
    void Reset();
    void Clear(Option_t *o="");
    void Copy(TObject &object) const
    {
        static_cast<MBadPixelsPix&>(object).fInfo = fInfo;
    }

    // Setter
    void SetUnsuitable(UnsuitableType_t typ) { fInfo[0] |= typ; }

    // Calibration
    void SetHiGainSaturation         () { fInfo[1] |= kHiGainSaturation; }
    void SetLoGainSaturation         () { fInfo[1] |= kLoGainSaturation; }
    void SetNotCalibrated           () { fInfo[1] |= kNotCalibrated; }
    void SetMeanTimeInLastBin        () { fInfo[1] |= kMeanTimeInLastBin; }
    void SetMeanTimeInFirstBin       () { fInfo[1] |= kMeanTimeInFirstBin; }
    void SetLoGainOscillating        () { fInfo[1] |= kLoGainOscillating; }
    void SetHiGainOscillating        () { fInfo[1] |= kHiGainOscillating; }
    void SetConvHiLoNotValid         () { fInfo[1] |= kConvHiLoNotValid; }
    void SetChargeSigmaNotValid      () { fInfo[1] |= kChargeSigmaNotValid; }
    void SetChargeRelErrNotValid     () { fInfo[1] |= kChargeRelErrNotValid; }
    void SetChargeErrNotValid        () { fInfo[1] |= kChargeErrNotValid; }
    void SetChargeIsPedestal         () { fInfo[1] |= kChargeIsPedestal; }
    void SetLoGainNotFitted          () { fInfo[1] |= kLoGainNotFitted; }
    void SetHiGainNotFitted          () { fInfo[1] |= kHiGainNotFitted; }

    // Getter
    Bool_t IsUnsuitable(UnsuitableType_t typ) const { return fInfo[0]&typ; }

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

    Bool_t IsHiGainSaturation         () const      { return fInfo[1] & kHiGainSaturation ;        }
    Bool_t IsLoGainSaturation         () const      { return fInfo[1] & kLoGainSaturation ;        }
    Bool_t IsNotCalibrated            () const      { return fInfo[1] & kNotCalibrated;            }
    Bool_t IsMeanTimeInLastBin        () const      { return fInfo[1] & kMeanTimeInLastBin;        }
    Bool_t IsMeanTimeInFirstBin       () const      { return fInfo[1] & kMeanTimeInFirstBin;       }
    Bool_t IsLoGainOscillating        () const      { return fInfo[1] & kLoGainOscillating;        }
    Bool_t IsHiGainOscillating        () const      { return fInfo[1] & kHiGainOscillating;        }
    Bool_t IsConvHiLoNotValid         () const      { return fInfo[1] & kConvHiLoNotValid;         }
    Bool_t IsChargeSigmaNotValid      () const      { return fInfo[1] & kChargeSigmaNotValid;      }
    Bool_t IsChargeRelErrNotValid     () const      { return fInfo[1] & kChargeRelErrNotValid;     }
    Bool_t IsChargeErrNotValid        () const      { return fInfo[1] & kChargeErrNotValid;        }
    Bool_t IsChargeIsPedestal         () const      { return fInfo[1] & kChargeIsPedestal;         }
    Bool_t IsLoGainNotFitted          () const      { return fInfo[1] & kLoGainNotFitted;          }
    Bool_t IsHiGainNotFitted          () const      { return fInfo[1] & kHiGainNotFitted;          }

    Bool_t IsLoGainBad() const { return IsLoGainSaturation() || IsConvHiLoNotValid() || IsLoGainOscillating() ;}
    Bool_t IsHiGainBad() const { return (IsHiGainSaturation() && IsConvHiLoNotValid()) || IsHiGainOscillating(); }

    Bool_t IsCalibrationSignalOK() const  { return !( IsChargeIsPedestal()
                                                      || IsChargeErrNotValid()
                                                      || IsChargeRelErrNotValid()
                                                      || IsChargeSigmaNotValid()
                                                      || IsMeanTimeInFirstBin()
                                                      || IsMeanTimeInLastBin() );  }
    Bool_t IsCalibrationFitOK()       const    { return !( (!IsHiGainSaturation() && IsHiGainNotFitted())
                                                      || ( IsHiGainSaturation() && IsLoGainNotFitted()) ); }
    Bool_t IsCalibrationOscillating() const  { return ( !IsHiGainSaturation() && IsHiGainOscillating()) 
                                                  || ( IsHiGainSaturation() && IsLoGainOscillating()) ; }
    Bool_t IsCalibrationResultOK()    const  {  return !IsUnsuitable(kUnsuitableRun) &&
                                                        IsCalibrationSignalOK()
                                                    && !IsCalibrationOscillating()
                                                         && IsCalibrationFitOK()
                                                   && (   (!IsHiGainSaturation() && !IsHiGainBad())
                                                       || (IsHiGainSaturation() && !IsLoGainBad()) ) ;}

    void Merge(const MBadPixelsPix &pix);

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

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

#endif

