
#ifndef _UNIVERSAL_BMP_H_
#define _UNIVERSAL_BMP_H_

  template <typename PixelType>
  class TUniversalBmpBase
  {
    public:
    TUniversalBmpBase()
    :MaxX(0),
     MaxY(0),
     Data(0),
     ExternalData(false){};
    void New(int x, int y, int valuepp, int bytespp=0, int bytespl=0);
    void Set(int x, int y, int valuepp, PixelType *ExtData, int bytespp=0, int bytespl=0);
    void Set(TUniversalBmpBase<PixelType> &Original);
    void SetTransposed(TUniversalBmpBase<PixelType> &Original);
    void Delete();
    ~TUniversalBmpBase();
    int MaxX;
    int MaxY;              // Size of image in pixels
    int StepX;             // bytes between pixels
    int StepY;             // bytes between lines
    int ValuesPerPixel;    // Number of PixelType values
    char *Data;
    bool ExternalData;     // data are external, not to be deleted

    inline PixelType *Pixel(int x, int y)
    {
      return (PixelType*)(Data + x*StepX + y*StepY);
    }
  };


typedef TUniversalBmpBase<unsigned char> TUniversalBmpByte;
typedef TUniversalBmpByte                TUniversalBmp;     // first version compatibility
typedef TUniversalBmpBase<int>           TUniversalBmpInt;
typedef TUniversalBmpBase<float>         TUniversalBmpFloat;

  /*
    // before template
  class TUniversalBmpInt : public TUniversalBmp
  {
    public:
    void New(int x, int y, int valuespp)
    {
      TUniversalBmp::New(x, y, sizeof(int)*valuespp);
    }
    inline int *Pixel(int x, int y)
    {
      return (int*) TUniversalBmp::Pixel(x, y);
    }
  };
  */

template <typename PixelType>
void TUniversalBmpBase<PixelType>::New(int x, int y, int valuepp, int bytespp, int bytespl)
{
  Delete();

  ValuesPerPixel = valuepp;
  MaxX = x;
  MaxY = y;

  if ( unsigned(bytespp) < sizeof(PixelType)*valuepp ) bytespp = sizeof(PixelType)*valuepp;
  StepX = bytespp;

  if ( bytespl < bytespp * x ) bytespl = bytespp * x;
  StepY = bytespl;

  Data = new char[StepY*y];
  ExternalData = false;
}

template <typename PixelType>
void TUniversalBmpBase<PixelType>::Set(int x, int y, int valuepp, PixelType *ExtData, int bytespp, int bytespl)
{
  Delete();

  ValuesPerPixel = valuepp;
  MaxX = x;
  MaxY = y;

  if ( bytespp == 0 ) bytespp = sizeof(PixelType)*valuepp;
  StepX = bytepp;

  if ( bytespl == 0 ) bytespl = bytespp * x;
  StepY = bytespl;

  Data = ExtData;
  ExternalData = true;
}

template <typename PixelType>
void TUniversalBmpBase<PixelType>::Set(TUniversalBmpBase<PixelType> &Original)
{
  Delete();
  ValuesPerPixel = Original.ValuesPerPixel;
  MaxX =  Original.MaxX;
  MaxY =  Original.MaxY;
  StepX = Original.StepX;
  StepY = Original.StepY;
  Data =  Original.Data;
  ExternalData = true;
}

template <typename PixelType>
void TUniversalBmpBase<PixelType>::SetTransposed(TUniversalBmpBase<PixelType> &Original)
{
  Delete();
  ValuesPerPixel = Original.ValuesPerPixel;
  MaxX =  Original.MaxY;
  MaxY =  Original.MaxX;
  StepX = Original.StepY;
  StepY = Original.StepX;
  Data =  Original.Data;
  ExternalData = true;
}

template <typename PixelType>
void TUniversalBmpBase<PixelType>::Delete()
{
  if (!ExternalData &&(Data != 0))
  {
    delete [] Data;
    Data = 0;
    MaxX = 0;
    MaxY = 0;
  }
}

template <typename PixelType>
TUniversalBmpBase<PixelType>::~TUniversalBmpBase()
{
  Delete();
}



#endif