#ifndef __Rasters_h
#define __Rasters_h

#include "types.h"

#ifdef _MSC_VER
 #pragma warning (disable : 4250)
 #pragma warning (disable : 4100)
#endif


#ifdef __cplusplus
extern "C" {
#endif

unsigned NearAvailPlanes(unsigned n);

void Conv8_1(BYTE *Dest, const BYTE *Src, unsigned Size1D);
void Conv8_16(WORD *Dest, const BYTE *Src, unsigned Size1D);
void Conv8_32(DWORD *Dest, const BYTE *Src, unsigned Size1D);
void Conv16_1(BYTE *Dest, const WORD *Src, unsigned Size1D);
void Conv16_8(BYTE *Dest, const WORD *Src, unsigned Size1D);
void Conv16_32(DWORD *Dest, const WORD *Src, unsigned Size1D);
void Conv32_8(BYTE *Dest, const DWORD *Src, unsigned Size1D);
void Conv32_16(WORD *Dest, const DWORD *Src, unsigned Size1D);


#ifdef __cplusplus
}

void AbstractError(const char *Name=NULL);


/** Base class for 1D data. */
class Raster1DAbstract
{
public: short UsageCount;
	unsigned Size1D;
	void *Data1D;

	Raster1DAbstract(void) {Size1D=UsageCount=0;Data1D=NULL;};
	virtual ~Raster1DAbstract() 		{Erase1DStub();};

	virtual void Allocate1D(int NewSize1D);
	virtual void Erase(void)		{Erase1DStub();};
	virtual void Erase1D(void)		{Erase1DStub();};
	virtual void Cleanup(void);
	void Erase1DStub(void);

	virtual DWORD GetValue1D(unsigned x) const {return(0);};
	virtual double GetValue1Dd(unsigned x) const {return(GetValue1D(x));};
	virtual void SetValue1D(unsigned x, DWORD NewValue) {AbstractError("SetValue1D");};
	virtual void SetValue1Dd(unsigned x, double NewValue) {AbstractError("SetValue1Dd");};

#ifdef _REENTRANT
        virtual DWORD PTR_GetValue1D(const void *RAW_Data1D, unsigned x) const {return(0);};
	virtual double PTR_GetValue1Dd(const void *RAW_Data1D, unsigned x) const {return(PTR_GetValue1D(RAW_Data1D,x));};
	virtual void PTR_SetValue1D(void *RAW_Data1D, unsigned x, DWORD NewValue) const {AbstractError("RAW_SetValue1D");};
	virtual void PTR_SetValue1Dd(void *RAW_Data1D, unsigned x, double NewValue) const {AbstractError("RAW_SetValue1Dd");};
#endif

	virtual int GetPlanes(void) const {return(0);};
	virtual unsigned GetSize1D(void) const {return(Size1D);};
        virtual char Channels(void) const {return 1;};
	void *GetRow(void)          {return(Data1D);};

/*This set of functions copy internal data in the proper format to the given buffer.*/
	virtual void Get(Raster1DAbstract &R1) const;

	virtual void Get24BitRGB(void *Buffer24Bit) const;

/*This set of functions receives given data and stores them to the internal structure.*/
	virtual void Set(const Raster1DAbstract &R1);

/*Bitwise operation with raster buffer*/
	virtual void Peel1Bit(void *Buffer1Bit, char plane);
	virtual void Join1Bit(void *Buffer1Bit, char plane);
	virtual void Peel8Bit(BYTE *Buffer8Bit, char plane8);
	virtual void Join8Bit(BYTE *Buffer8Bit, char plane8);

	virtual Raster1DAbstract *GetPalette(void) {return(NULL);}
	virtual void SetPalette(Raster1DAbstract *NewPalette) {AbstractError("SetPalette");}
	friend Raster1DAbstract *CreateRaster1D(unsigned SizeX, int Planes);
};
Raster1DAbstract *CreateRaster1D(unsigned SizeX, int Planes);


class Raster1DAbstractRGB: virtual public Raster1DAbstract
{
public:
  virtual DWORD GetValue1DRAW(unsigned x) const {AbstractError("GetValue1DRAW");return 0;};
  virtual void SetValue1DRAW(unsigned x, DWORD NewValue) {AbstractError("SetValue1DRAW");};

  virtual unsigned GetSize1D(void) const {return(Size1D);};
  virtual char Channels(void) const {return 3;};

  virtual void Set(const Raster1DAbstract &R1);

  unsigned R(unsigned x) const {return(GetValue1DRAW(3*x));}
  unsigned G(unsigned x) const {return(GetValue1DRAW(3*x+1));}
  unsigned B(unsigned x) const {return(GetValue1DRAW(3*x+2));}

  void R(unsigned x, unsigned newR) {SetValue1DRAW(3*x,newR);};
  void G(unsigned x, unsigned newG) {SetValue1DRAW(3*x+1,newG);};
  void B(unsigned x, unsigned newB) {SetValue1DRAW(3*x+2,newB);};

  friend Raster1DAbstractRGB *CreateRaster1DRGB(unsigned SizeX, unsigned Planes);
};
Raster1DAbstractRGB *CreateRaster1DRGB(unsigned SizeX, int Planes);

class Raster1DAbstractRGBA: virtual public Raster1DAbstract
{
public:
  virtual DWORD GetValue1DRAW(unsigned x) const {AbstractError("GetValue1DRAW");return 0;};
  virtual void SetValue1DRAW(unsigned x, DWORD NewValue) {AbstractError("SetValue1DRAW");};

  virtual unsigned GetSize1D(void) const {return(Size1D);};
  virtual char Channels(void) const {return 4;};

  virtual void Set(const Raster1DAbstract &R1);

  unsigned R(unsigned x) const {return(GetValue1DRAW(4*x));}
  unsigned G(unsigned x) const {return(GetValue1DRAW(4*x+1));}
  unsigned B(unsigned x) const {return(GetValue1DRAW(4*x+2));}
  unsigned A(unsigned x) const {return(GetValue1DRAW(4*x+3));}

  void R(unsigned x, unsigned newR) {SetValue1DRAW(4*x,newR);};
  void G(unsigned x, unsigned newG) {SetValue1DRAW(4*x+1,newG);};
  void B(unsigned x, unsigned newB) {SetValue1DRAW(4*x+2,newB);};
  void A(unsigned x, unsigned newA) {SetValue1DRAW(4*x+3,newA);};

  friend Raster1DAbstractRGBA *CreateRaster1DRGBA(unsigned SizeX, int Planes);
};


class Raster2DAbstract: virtual public Raster1DAbstract
{
public: unsigned Size2D;
	void **Data2D;

	Raster2DAbstract(void) {Size2D=0;Data2D=NULL;}
	virtual ~Raster2DAbstract() 			{Erase2DStub();}

	virtual void Allocate2D(unsigned NewSize1D, unsigned NewSize2D);
	virtual void Erase(void)			{Erase2DStub();}
	virtual void Erase2D(void)			{Erase2DStub();}
	virtual void Cleanup(void);

	DWORD GetValue2D(unsigned Offset1D, unsigned Offset2D);
	double GetValue2Dd(unsigned Offset1D, unsigned Offset2D);
	void SetValue2D(unsigned Offset1D, unsigned Offset2D, long x);
	void SetValue2Dd(unsigned Offset1D, unsigned Offset2D, double x);

#if defined(_REENTRANT) && defined(RASTER_3D)
        DWORD PTR_GetValue2D(const void **RAW_Data2D, unsigned Offset1D, unsigned Offset2D) const;
	double PTR_GetValue2Dd(const void **RAW_Data2D, unsigned Offset1D, unsigned Offset2D) const;
	void PTR_SetValue2D(void **RAW_Data2D, unsigned Offset1D, unsigned Offset2D, DWORD NewValue) const;
	void PTR_SetValue2Dd(void **RAW_Data2D, unsigned Offset1D, unsigned Offset2D, double NewValue) const;
#endif

	void *GetRow(unsigned Offset2D)   {if(Data2D==NULL || Offset2D>=Size2D) return(NULL);return(Data2D[Offset2D]);}

	Raster1DAbstract *GetRowRaster(unsigned Offset2D);

	friend Raster2DAbstract *CreateRaster2D(unsigned SizeX, unsigned SizeY, int Planes);

protected:
	void Erase2DStub(void);
};

Raster2DAbstract *CreateRaster2D(unsigned SizeX, unsigned SizeY, int Planes);


class Raster2DAbstractRGB: virtual public Raster2DAbstract, virtual public Raster1DAbstractRGB
{
public:
	virtual DWORD GetValue2DRAW(unsigned Offset1D, unsigned Offset2D);
	virtual void SetValue2DRAW(unsigned Offset1D, unsigned Offset2D, DWORD x);

	unsigned R(unsigned x, unsigned y) {return(GetValue2DRAW(3*x,y));}
	unsigned G(unsigned x, unsigned y) {return(GetValue2DRAW(3*x+1,y));}
	unsigned B(unsigned x, unsigned y) {return(GetValue2DRAW(3*x+2,y));}

	void R(unsigned x, unsigned y, unsigned newR) {SetValue2DRAW(3*x,y,newR);};
	void G(unsigned x, unsigned y, unsigned newG) {SetValue2DRAW(3*x+1,y,newG);};
	void B(unsigned x, unsigned y, unsigned newB) {SetValue2DRAW(3*x+2,y,newB);};

	friend Raster2DAbstractRGB *CreateRaster2DRGB(unsigned SizeX, unsigned SizeY, int Planes);
};

Raster2DAbstractRGB *CreateRaster2DRGB(unsigned SizeX, unsigned SizeY, int Planes);


class Raster2DAbstractRGBA: virtual public Raster2DAbstract, virtual public Raster1DAbstractRGBA
{
public:
	virtual DWORD GetValue2DRAW(unsigned Offset1D, unsigned Offset2D);
	virtual void SetValue2DRAW(unsigned Offset1D, unsigned Offset2D, DWORD x);

	unsigned R(unsigned x, unsigned y) {return(GetValue2DRAW(4*x,y));}
	unsigned G(unsigned x, unsigned y) {return(GetValue2DRAW(4*x+1,y));}
	unsigned B(unsigned x, unsigned y) {return(GetValue2DRAW(4*x+2,y));}
	unsigned A(unsigned x, unsigned y) {return(GetValue2DRAW(4*x+3,y));}

	void R(unsigned x, unsigned y, unsigned newR) {SetValue2DRAW(4*x,y,newR);};
	void G(unsigned x, unsigned y, unsigned newG) {SetValue2DRAW(4*x+1,y,newG);};
	void B(unsigned x, unsigned y, unsigned newB) {SetValue2DRAW(4*x+2,y,newB);};
	void A(unsigned x, unsigned y, unsigned newA) {SetValue2DRAW(4*x+3,y,newA);};

	friend Raster2DAbstractRGBA *CreateRaster2DRGBA(unsigned SizeX, unsigned SizeY, int Planes);
};

Raster2DAbstractRGBA *CreateRaster2DRGBA(unsigned SizeX, unsigned SizeY, int Planes);




class Raster2DColorAbstract: public Raster1DAbstract
{
public: Raster1DAbstract *palette;

	virtual Raster1DAbstract *GetPalette(void) {return(palette);}
	virtual void SetPalette(Raster1DAbstract *NewPalette) {if(palette!=NULL) delete(palette); palette=NewPalette;}
};


#ifdef RASTER_3D
class Raster3DAbstract: virtual public Raster2DAbstract
	{
public: unsigned Size3D;
	void ***Data3D;

	Raster3DAbstract(void) {Size3D=0;Data3D=NULL;}
	virtual ~Raster3DAbstract() 			{Erase3DStub();}

	virtual void Allocate3D(unsigned NewSize1D, unsigned NewSize2D, unsigned NewSize3D);
	virtual void Erase(void)			{Erase3DStub();}
	virtual void Erase3D(void)			{Erase3DStub();}
        virtual void Cleanup(void);

	DWORD GetValue3D(unsigned Offset1D, unsigned Offset2D, unsigned Offset3D);
        double GetValue3Dd(unsigned Offset1D, unsigned Offset2D, unsigned Offset3D);
	void SetValue3D(unsigned Offset1D, unsigned Offset2D, unsigned Offset3D, DWORD x);
        void SetValue3Dd(unsigned Offset1D, unsigned Offset2D, unsigned Offset3D, double x);
	void *GetRow(unsigned Offset3D)   {if(Data3D==NULL || Offset3D>=Size3D) return(NULL);return(Data3D[Offset3D]);}
	Raster2DAbstract *GetRowRaster(unsigned Offset3D);

	void Erase3DStub(void);

	friend Raster3DAbstract *CreateRaster3D(unsigned SizeX, unsigned SizeY, unsigned SizeZ, int Planes);
	};
Raster3DAbstract *CreateRaster3D(unsigned SizeX, unsigned SizeY, unsigned SizeZ, int Planes);
#endif

/* ---------- Global class Image --------- */

/*Definition of errors while Loading/Saving File(s)*/
#define ErrOK		  0
#define ErrOpenFile	 -1
#define ErrReadFile	 -2
#define ErrWriteFile	 -3
#define ErrBadFileFormat -4

#define ErrNoMem	-10



#ifndef RGBQuad_DEFINED
#define RGBQuad_DEFINED
typedef struct
	{
	unsigned R,G,B,O;
	} RGBQuad;
#endif


struct RGB_Record
   {
   BYTE Red;
   BYTE Green;
   BYTE Blue;
   };



class APalette: virtual public Raster1DAbstractRGB
	{
public: virtual void Get(unsigned index, RGBQuad *RGB);
	friend APalette *BuildPalette(unsigned Indices, char type);
	};
APalette *BuildPalette(unsigned Indices, char type=0);


typedef enum
{
  ImageNone = 0,	 //-none,
  ImageGray = 0x100,	 //1-gray,
  ImagePalette = 0x200,	 //2-palette,
  ImageTrueColor = 0x300, //3-true color - RGB
  ImagePaletteF=0x2000,	 //there is used abundant palette
  ImageReal =   0x4000,  //Real numbers are used
  ImageSigned = 0x8000	 //image uses signed numbers
} IMAGE_TYPE;


class Image
	{
public: Raster2DAbstract *Raster;
	APalette *Palette;
	Image *Next;
	float x,y,dx,dy,RotAngle;
	char *Comment;

	Image(void): Comment(NULL)  {RotAngle=x=y=dx=dy=0;Raster=NULL;Next=NULL;Palette=NULL;};
	Image(const Image & I);
	Image(Raster2DAbstract *NewRaster): Comment(NULL) {x=y=dx=dy=0;Next=NULL;Palette=NULL;if((Raster=NewRaster)!=NULL) Raster->UsageCount++;};
	~Image(void) {Erase();};
	IMAGE_TYPE ImageType(void) const;   // 0-none, 1-gray, 2-palette, 3-true color

	Raster2DAbstract *operator=(Raster2DAbstract *NewRaster);
	Image &operator=(const Image & I);

	DWORD GetPixel(unsigned Offset1D, unsigned Offset2D) const {return(Raster==NULL?0:Raster->GetValue2D(Offset1D,Offset2D));};
	DWORD GetPixelRGB(unsigned Offset1D, unsigned Offset2D) const;
	
	void SetPixel(unsigned SizeX, unsigned SizeY, DWORD x) {if(Raster) Raster->SetValue2D(SizeX,SizeY,x);};

	void Create(unsigned SizeX, unsigned SizeY, int Planes);
	void Erase(void);
	void AttachRaster(Raster2DAbstract *NewRaster);
        void AttachPalette(APalette *NewPalette);
	};


void Flip1D(Raster2DAbstract *r2D);
void Flip2D(Raster2DAbstract *r2D);
int ReducePalette(Image *Img, unsigned maxColors);
int GrayPalette(Raster1DAbstractRGB *Palette,int Planes=0);
int FillGray(Raster1DAbstractRGB *Palette,int Planes);


/* -----File format loader dynamical list------ */
typedef Image (* TLoadPicture)(const char *Name);
typedef int (*TSavePicture)(const char *Name, const Image &Img);

class TImageFileHandler
	{
private:static TImageFileHandler *First;
	TImageFileHandler *Previous;
	TImageFileHandler *Next;

	const char *Extension;
        const char *Description;

public: TImageFileHandler(const char *NewShortKey, TLoadPicture LoadPicture_XXX = NULL, TSavePicture SavePicture_XXX=NULL, const char *NewDescription=NULL);
	~TImageFileHandler();

	TLoadPicture LoadPicture;
	TSavePicture SavePicture;
	const char *extension() {return(Extension);}
	const char *description() {return(Description);}

	static TImageFileHandler *first() {return(First);}
	TImageFileHandler *next() {return(Next);}
	};

int SavePicture(const char *Name,const Image &Img);
Image LoadPicture(const char *Name);

#endif // C++


#endif //__Rasters_h
