#ifndef Geom1_RGBAPalette_H
#define Geom1_RGBAPalette_H
#include <Glasses/ZGlass.h>
#include <Stones/ZColorMark.h>
class RGBAPalette : public ZGlass
{
  MAC_RNR_FRIENDS(RGBAPalette);
public:
  enum LimitAction_e { LA_Cut, LA_Mark, LA_Clip, LA_Wrap };
private:
  void _init();
protected:
  Int_t     mMinInt;  
  Int_t     mMaxInt;  
  Float_t   mMinFlt;  
  Float_t   mMaxFlt;  
  Bool_t    bInterpolate;  
  Bool_t    mShowDefValue; 
  LimitAction_e  mUnderflowAction; 
  LimitAction_e  mOverflowAction;  
  ZColor    mDefaultColor;   
  ZColor    mCutColor;       
  ZColor    mUnderColor;     
  ZColor    mOverColor;      
  UChar_t   mDefaultRGBA[4]; 
  UChar_t   mCutRGBA[4];     
  UChar_t   mUnderRGBA[4];   
  UChar_t   mOverRGBA[4];    
  mutable Int_t                mNBins;
  mutable std::vector<UChar_t> mColorArray;
  vector<ZColorMark> mColorMarks;
public:
  RGBAPalette(const Text_t* n="RGBAPalette", const Text_t* t=0);
  virtual ~RGBAPalette();
  void ClearColorArray();
  void EmitClearCARay() { ClearColorArray(); }
  void EmitRecolDCUORay();
  void SetMinInt(Int_t min);
  void SetMaxInt(Int_t max);
  
  void SetupColorArray() const;
  void SetMarksFromgStyle();                         
  void SetMarksFromPOVFile(const Text_t* file_name); 
  void PrintMarks() const; 
  void PrintArray() const; 
  
  Bool_t   WithinVisibleRange(Int_t val) const;
  const UChar_t* ColorFromValue(Int_t val) const;
  const UChar_t* ColorFromValue(Int_t val, Int_t def_val) const;
  void     ColorFromValue(Int_t val, UChar_t* pix, Bool_t alpha=true) const;
  Bool_t   ColorFromValue(Int_t val, Int_t def_val, UChar_t* pix, Bool_t alpha=true) const;
  const UChar_t* ColorFromValue(Float_t val) const;
  void  ColorFromValue(Float_t val, UChar_t* pix, Bool_t alpha=true) const;
  ZColor MarkToCol(Float_t mark);
  
  static void ColorFromIdx(Short_t ci, UChar_t* col, Bool_t alpha=true);
  static void ColorFromIdx(Float_t f1, Short_t c1, Float_t f2, Short_t c2,
                           UChar_t* col, Bool_t alpha=true);
#include "RGBAPalette.h7"
  ClassDef(RGBAPalette, 1);
}; 
inline Bool_t RGBAPalette::WithinVisibleRange(Int_t val) const
{
  if ((val < mMinInt && mUnderflowAction == LA_Cut) ||
      (val > mMaxInt && mOverflowAction  == LA_Cut))
    return false;
  else
    return true;
}
inline const UChar_t* RGBAPalette::ColorFromValue(Int_t val) const
{
  
  
  if (mColorArray.empty())  SetupColorArray();
  if (val < mMinInt)
  {
    if (mUnderflowAction == LA_Wrap)
      val = (val+1-mMinInt)%mNBins + mMaxInt;
    else if (mUnderflowAction == LA_Clip)
      val = mMinInt;
    else
      return mUnderRGBA;
  }
  else if (val > mMaxInt)
  {
    if (mOverflowAction == LA_Wrap)
      val = (val-1-mMaxInt)%mNBins + mMinInt;
    else if (mOverflowAction == LA_Clip)
      val = mMaxInt;
    else
      return mOverRGBA;
  }
  return &mColorArray[4 * (val - mMinInt)];
}
inline const UChar_t* RGBAPalette::ColorFromValue(Int_t val, Int_t def_val) const
{
  if (val == def_val && mShowDefValue)
    return mDefaultRGBA;
  else
    return ColorFromValue(val);
}
inline void RGBAPalette::ColorFromValue(Int_t val, UChar_t* pix, Bool_t alpha) const
{
  const UChar_t* c = ColorFromValue(val);
  pix[0] = c[0]; pix[1] = c[1]; pix[2] = c[2];
  if (alpha) pix[3] = c[3];
}
inline Bool_t RGBAPalette::ColorFromValue(Int_t val, Int_t def_val, UChar_t* pix, Bool_t alpha) const
{
  if (val == def_val)
  {
    if (mShowDefValue) {
      pix[0] = mDefaultRGBA[0];
      pix[1] = mDefaultRGBA[1];
      pix[2] = mDefaultRGBA[2];
      if (alpha) pix[3] = mDefaultRGBA[3];
      return true;
    } else {
      return false;
    }
  }
  if (WithinVisibleRange(val))
  {
    ColorFromValue(val, pix, alpha);
    return true;
  }
  else
  {
    return false;
  }
}
inline const UChar_t* RGBAPalette::ColorFromValue(Float_t val) const
{
  Int_t vint = mMinInt +
    (Int_t) ((mMaxInt - mMinInt)*(val - mMinFlt)/(mMaxFlt - mMinFlt));
  return ColorFromValue(vint);
}
inline void RGBAPalette::ColorFromValue(Float_t val, UChar_t* pix, Bool_t alpha) const
{
  const UChar_t* c = ColorFromValue(val);
  pix[0] = c[0]; pix[1] = c[1]; pix[2] = c[2];
  if (alpha) pix[3] = c[3];
}
inline ZColor RGBAPalette::MarkToCol(Float_t mark)
{
  
  if (mColorMarks.empty()) return ZColor();
  vector<ZColorMark>::iterator i = mColorMarks.begin();
  if (mark < i->m()) return ZColor(mColorMarks.front());
  ++i;
  while (i != mColorMarks.end() && mark > i->m()) ++i;
  if (i == mColorMarks.end()) return ZColor(mColorMarks.back());
  vector<ZColorMark>::iterator j = i;
  --j;
  if (j == mColorMarks.end()) return ZColor(mColorMarks.back());
  Float_t fi = (mark - j->m())/(i->m() - j->m());
  return fi * ZColor(*i) + (1 - fi) * ZColor(*j);
}
#endif