
#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);
	}

	inline const PixelType *Pixel(int x, int y) const // lukas - missing!
	{
		return (PixelType*)(Data + x*StepX + y*StepY);
	}

protected:
	TUniversalBmpBase(const TUniversalBmpBase &other); // lukas - this class will crash if copied; do not copy / use pointers
	TUniversalBmpBase &operator =(const TUniversalBmpBase &other); // lukas - this class will crash if copied; do not copy / use pointers
};

typedef TUniversalBmpBase<uint8_t>	TUniversalBmpByte; // lukas - polite people will not use unsigned char
typedef TUniversalBmpByte			TUniversalBmp;     // first version compatibility
typedef TUniversalBmpBase<int32_t>	TUniversalBmpInt;  // lukas - on some platforms "int" will not be 32-bit int!
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 = bytespp; // lukas - bug!! was "bytesp" (undefined)

	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 // !_UNIVERSAL_BMP_H_
