// This may look like C code, but it is really -*- C++ -*-
//     Classes ArrayAdapter           R. Ansari  05/98
// LAL (Orsay) / IN2P3-CNRS  DAPNIA/SPP (Saclay) / CEA


#ifndef PARRADAPTER_SEEN
#define PARRADAPTER_SEEN

#include "machdefs.h"
#include "lut.h"
#include "pipixutils.h"

#include <string> 
#include <vector> 

class P1DArrayAdapter {
public :
                  P1DArrayAdapter(int sz=0);
  virtual         ~P1DArrayAdapter();
 
  virtual double  Value(int i) = 0;
  inline  int     Size() { return (mSize) ; }
  virtual void    DefineXCoordinate(double x0, double dx);
  virtual double  X(int i);

//   Methode de decodage des options - Implementation par defaut ne fait rien
  virtual int DecodeOptionString(vector<string> & opt, bool rmdecopt=true);
//   liste des options sous forme text - Implementation par defaut ne fait rien
  virtual int OptionToString(vector<string> & opt) const;
     
protected :
  int mSize;
  double mOx, mDx;
};

// Cette classe est un adaptateur pour les PIImages et 
// autres classes de PI qui operent sur des structures 
// de type Tableaux 2-D (images, ...) 
class P2DArrayAdapter;

typedef char * (* P2DAA_InfoStringFunc) (P2DArrayAdapter * aa, int ix, int iy);
/* Longueur de retour de P2DAA_InfoString : 128 char */
 
class P2DArrayAdapter {
public :
                  P2DArrayAdapter(int sx=0, int sy=0);
  virtual 	  ~P2DArrayAdapter();

  void  	  ConfigureAxes(bool invx=false, bool invy=false, bool exy=false,
                                int sx=-1, int sy=-1);

  inline void     GetAxesConfiguration(bool& invx, bool& invy, bool& exy)
                               { invx = invX; invy = invY; exy = eXY; }

  virtual void    DefineXYCoordinates(double x0, double y0, double dx, double dy);
// Doit etre defini par les classes derivees
  virtual double  Value(int ix, int iy) = 0;
// Peut etre redefini pour les classes derivees, pour une optimisation par exemple     
  virtual double  MeanVal(int ix1, int ix2, int jy1, int jy2);   

  virtual void    XYfromxy(int ix, int iy, double& x, double& y);

  virtual char *  InfoString(int ix, int iy);

  inline  void    SetInfoStringFunction(P2DAA_InfoStringFunc isf)
                  { ISFunc = isf; }

  inline  int     XSize() { return ( eXY ? sY : sX ) ; }
  inline  int     YSize() { return ( eXY ? sX : sY ) ; }

  inline  void    XYCoord(int i, int j, double& x, double& y)
                         { int ix, iy;  IJ2xy(i, j, ix, iy); 
                           XYfromxy(ix, iy, x, y); }
  inline  void    Coord(int i, int j, double& x, double& y)
                       { int ix, iy;  double f; IJ2xy(i, j, ix, iy); 
                       XYfromxy(ix, iy, x, y); if (eXY) {f=x; x=y; y=f; } }
  inline  double  operator() (int i, int j) 
                         { int ix, iy;  IJ2xy(i, j, ix, iy); 
                         return Value(ix, iy); }
  inline void     IJ2xy(int i, int j, int& x, int& y)
                  { if  (eXY) {int ii = i; i = j; j = ii; }
                  x = i*sgnX+offX; y = j*sgnY+offY; 
                  return; }

//    Calcul Min-Max, Moy-Sig
  virtual int     CheckDyn(double& min, double& max, double& moy, double& sig, int& nbnul, int& nbsat, int vit=10);
//    Calcul AutoLut
  virtual void    ComputeLut_PicHisto(double& min, double& max, bool htail, 
				      double nbsig=1., double fracmax=0.95);
//    Calcul stable Range
  virtual int     ComputeLut_Range(double& min,double& max,double fracmin=0.,double fracmax=0.,int nmax=10000);

//    Calcul pixmap avec un LUT
  virtual void ComputePixmap(LUT* lut, int ofx, int ofy, int zm, 
                             int xwsz, int ywsz, PIPixColIdx & pixc);

//   Methode de decodage des options - Implementation par defaut ne fait rien
  virtual int DecodeOptionString(vector<string> & opt, bool rmdecopt=true);
//   liste des options sous forme text - Implementation par defaut ne fait rien
  virtual int OptionToString(vector<string> & opt) const;

protected :
  int sX, sY;
  double mOx, mDx, mOy, mDy;
  int sgnX, sgnY;
  int offX, offY;
  bool invX, invY, eXY;

  P2DAA_InfoStringFunc ISFunc;

};

//  Adaptateur de tableau 1D pour pointeur de type T *

template <class T> 
class P1DAdapter : public P1DArrayAdapter {
public :
                  P1DAdapter(T* data, int sz, bool ad=false) :
                    P1DArrayAdapter(sz)
                    { aDel = ad; mData = data; }

  virtual 	  ~P1DAdapter() { if ( (aDel) && (mData) ) delete[] mData; }
  virtual double  Value(int i) 
                    {  if ( (i < 0) || (i >= mSize) ) return(0.); 
                    return(mData[i]); }
protected :
  bool aDel;
  T* mData;
};


//  Adaptateur de tableau 2D pour pointeur de type T *
template <class T> 
class P2DAdapter : public P2DArrayAdapter {
public :
                  P2DAdapter(T* data, int sx, int sy, bool ad=false) :
                    P2DArrayAdapter(sx, sy)
                    { aDel = ad; mData = data; }

  virtual 	  ~P2DAdapter() { if ( (aDel) && (mData) ) delete[] mData; }
  virtual double  Value(int ix, int iy) 
                    {  if ( (ix < 0)  || (iy < 0) || (ix >= sX) || (iy >= sY) ) return(0.); 
                    return(mData[ix+iy*sX]); }
  virtual double  MeanVal(int ix1, int ix2, int jy1, int jy2)  
    {
    int ec;
    if (ix1>ix2) { ec=ix1; ix1=ix2; ix2=ec; }
    if (jy1>jy2) { ec=jy1; jy1=jy2; jy2=ec; }    
    double ss = 0.;
    for(int j=jy1; j<=jy2; j++) 
      for(int i=ix1; i<=ix2; i++)  ss += (double)(mData[i+j*sX]);
    ss /= (double)((jy2-jy1+1)*(ix2-ix1+1));
    return ss;  
    }   

protected :
  bool aDel;
  T* mData;
};

//  Adaptateur de tableau 2D pour tableau RGB 

class P2DPixRGBAdapter : public P2DArrayAdapter {
public :
          P2DPixRGBAdapter(PIPixRGBArray * rgbp, bool ad=false) :
             P2DArrayAdapter(rgbp->XSize(), rgbp->YSize() )
                { aDel = ad; mPix = rgbp; }
  virtual ~P2DPixRGBAdapter() { if ( (aDel) && (mPix) ) delete mPix; }

  virtual double  Value(int ix, int iy) 
    {  
    if ( (ix < 0)  || (iy < 0) || (ix >= sX) || (iy >= sY) ) return(0.); 
    PIPixRGB rgb = (*mPix)(ix, iy);
    return ( ((double)rgb.blue*256.+(double)rgb.green)*256.+(double)rgb.red );
    }
  virtual double  MeanVal(int ix1, int ix2, int jy1, int jy2)  
    {
    int ec;
    if (ix1>ix2) { ec=ix1; ix1=ix2; ix2=ec; }
    if (jy1>jy2) { ec=jy1; jy1=jy2; jy2=ec; }    
    int r = 0;
    int g = 0;
    int b = 0;
    for(int j=jy1; j<=jy2; j++) 
      for(int i=ix1; i<=ix2; i++)  {
      	PIPixRGB rgb = (*mPix)(i, j);
      	r += rgb.red;  g += rgb.green;   b += rgb.blue; 
      }
    int n = (jy2-jy1+1)*(ix2-ix1+1);   
    r /= n; g /= n; b /= n;
    return ( ((double)b*256.+(double)g)*256.+(double)r );  
    }   
                    
protected :
  bool aDel;
  PIPixRGBArray* mPix;
};



#endif
