#ifndef _COMMON_BITMAPINFO_HPP_
#define _COMMON_BITMAPINFO_HPP_
#ifndef _COMMON_EXCEPTION_HPP_
#include <common/except.hpp>
#endif
#ifndef _COMMON_WINDOWS_HPP_
#include <common/windows.hpp>
#endif
#ifndef _COMMON_RGBQUAD_HPP_
#include <common/rgbquad.hpp>
#endif

class PurePalette;

class BitmapInfo
{
public:
	enum BitsPerPixel{Bit8=8,Bit16=16,Bit24=24,TrueColor=24,Bit32=32};
	enum BiCompression{BiRGB=BI_RGB,BiBitFields=BI_BITFIELDS,BiRLE8=BI_RLE8,BiRLE4=BI_RLE4};
	BitmapInfo(void);
	BitmapInfo(const BitmapInfo &someBitmapInfo);
	BitmapInfo(const BITMAPINFO &someBITMAPINFO);
	virtual ~BitmapInfo();
	BitmapInfo &operator=(const BitmapInfo &someBitmapInfo);
  BitmapInfo &operator=(const BITMAPINFO &someBITMAPINFO);
	BitmapInfo &operator=(const PurePalette &somePurePalette);
	WORD operator==(const BitmapInfo &someBitmapInfo)const;
	RGBQuad &operator[](int itemIndex);
	operator BITMAPINFO&(void);
	operator BITMAPINFO*(void);
	operator BITMAPINFOHEADER*(void);
	operator BITMAPINFOHEADER&(void);
	operator RGBQUAD*(void);
	WORD planes(void)const;
	void planes(WORD planes);
	LONG width(void)const;
	void width(LONG width);
	LONG height(void)const;
	void height(LONG height);
	BitsPerPixel bitCount(void)const;
	void bitCount(BitsPerPixel bitCount);
	BiCompression compression(void)const;
  void compression(BiCompression compression);
	void compression(DWORD compression);
	DWORD sizeImage(void)const;
	void sizeImage(DWORD sizeImage);
	LONG xPelsPerMeter(void)const;
	void xPelsPerMeter(LONG xPelsPerMeter);
	LONG yPelsPerMeter(void)const;
	void yPelsPerMeter(LONG yPelsPerMeter);
	DWORD colorUsed(void)const;
	void colorUsed(DWORD colorUsed);
	DWORD colorImportant(void)const;
	void colorImportant(DWORD colorImportant);
	DWORD rgbColors(void)const;
  void rgbColors(DWORD rgbColors);
	DWORD imageExtent(void)const;
  void verifyDimensions(void);
  String toString(void)const;
	BITMAPINFO &getBITMAPINFO(void);
	BITMAPINFOHEADER &getBITMAPINFOHEADER(void);
private:
	enum {DefaultColors=0x100,DefaultCompression=BI_RGB,DefaultBitCount=Bit8,DefaultPlanes=0x01};
	void createInfo(DWORD rgbColors);
	void destroyInfo(void);
  String makeCompressionString(void)const;

	BITMAPINFO *mlpBitmapInfo;
	HGLOBAL mhGlobalHandle;
	DWORD mRGBColors;
};

inline
BitmapInfo::BitmapInfo(void)
: mlpBitmapInfo(0), mhGlobalHandle(0), mRGBColors(0)
{
	createInfo(DefaultColors);
}

inline
BitmapInfo::BitmapInfo(const BitmapInfo &someBitmapInfo)
: mlpBitmapInfo(0), mhGlobalHandle(0), mRGBColors(0)
{
	*this=someBitmapInfo;
}

inline
BitmapInfo::BitmapInfo(const BITMAPINFO &someBITMAPINFO)
: mlpBitmapInfo(0), mhGlobalHandle(0), mRGBColors(0)
{
  *this=someBITMAPINFO;
}

inline
BitmapInfo::~BitmapInfo()
{
	destroyInfo();
}

inline
BitmapInfo::operator BITMAPINFO&(void)
{
	return *mlpBitmapInfo;
}

inline
BitmapInfo::operator BITMAPINFO*(void)
{
	return mlpBitmapInfo;
}

inline
BitmapInfo::operator BITMAPINFOHEADER&(void)
{
	return mlpBitmapInfo->bmiHeader;
}

inline
BitmapInfo::operator BITMAPINFOHEADER*(void)
{
	return &mlpBitmapInfo->bmiHeader;
}

inline
BitmapInfo::operator RGBQUAD*(void)
{
	return mlpBitmapInfo->bmiColors;
}

inline
RGBQuad &BitmapInfo::operator[](int itemIndex)
{
	if(!(itemIndex<rgbColors()))throw(BoundaryError());
	return (RGBQuad&)mlpBitmapInfo->bmiColors[itemIndex];
}

inline
BITMAPINFO &BitmapInfo::getBITMAPINFO(void)
{
  return *mlpBitmapInfo;
}

inline
BITMAPINFOHEADER &BitmapInfo::getBITMAPINFOHEADER(void)
{
  return mlpBitmapInfo->bmiHeader;
}

inline
WORD BitmapInfo::planes(void)const
{
  return mlpBitmapInfo->bmiHeader.biPlanes;
}

inline
void BitmapInfo::planes(WORD planes)
{
  mlpBitmapInfo->bmiHeader.biPlanes=planes;
}

inline
LONG BitmapInfo::width(void)const
{
  return mlpBitmapInfo->bmiHeader.biWidth;
}

inline
void BitmapInfo::width(LONG width)
{
	mlpBitmapInfo->bmiHeader.biWidth=width;
  sizeImage(imageExtent());
}

inline
LONG BitmapInfo::height(void)const
{
  return mlpBitmapInfo->bmiHeader.biHeight;
}

inline
void BitmapInfo::height(LONG height)
{
	mlpBitmapInfo->bmiHeader.biHeight=height;
  sizeImage(imageExtent());
}

inline
BitmapInfo::BitsPerPixel BitmapInfo::bitCount(void)const
{
  return BitsPerPixel(mlpBitmapInfo->bmiHeader.biBitCount);
}

inline
void BitmapInfo::bitCount(BitsPerPixel bitCount)
{
	mlpBitmapInfo->bmiHeader.biBitCount=int(bitCount);
  sizeImage(imageExtent());
}

inline
BitmapInfo::BiCompression BitmapInfo::compression(void)const
{
  return BiCompression(mlpBitmapInfo->bmiHeader.biCompression);
}

inline
void BitmapInfo::compression(BiCompression compression)
{
  mlpBitmapInfo->bmiHeader.biCompression=compression;
}

inline
void BitmapInfo::compression(DWORD compression)   // backward compatibility
{
  mlpBitmapInfo->bmiHeader.biCompression=compression;
}

inline
DWORD BitmapInfo::sizeImage(void)const
{
  return mlpBitmapInfo->bmiHeader.biSizeImage;
}

inline
void BitmapInfo::sizeImage(DWORD sizeImage)
{
	mlpBitmapInfo->bmiHeader.biSizeImage=sizeImage;
}

inline
LONG BitmapInfo::xPelsPerMeter(void)const
{
  return mlpBitmapInfo->bmiHeader.biXPelsPerMeter;
}

inline
void BitmapInfo::xPelsPerMeter(LONG xPelsPerMeter)
{
  mlpBitmapInfo->bmiHeader.biXPelsPerMeter=xPelsPerMeter;
}

inline
LONG BitmapInfo::yPelsPerMeter(void)const
{
  return mlpBitmapInfo->bmiHeader.biYPelsPerMeter;
}

inline
void BitmapInfo::yPelsPerMeter(LONG yPelsPerMeter)
{
  mlpBitmapInfo->bmiHeader.biYPelsPerMeter=yPelsPerMeter;
}

inline
DWORD BitmapInfo::colorUsed(void)const
{
	return mlpBitmapInfo->bmiHeader.biClrUsed;
}

inline
void BitmapInfo::colorUsed(DWORD colorUsed)
{
	mlpBitmapInfo->bmiHeader.biClrUsed=colorUsed;
}

inline
DWORD BitmapInfo::colorImportant(void)const
{
  return mlpBitmapInfo->bmiHeader.biClrImportant;
}

inline
void BitmapInfo::colorImportant(DWORD colorImportant)
{
  mlpBitmapInfo->bmiHeader.biClrImportant=colorImportant;
}

inline
DWORD BitmapInfo::rgbColors(void)const
{
	return mRGBColors;
}

inline
DWORD BitmapInfo::imageExtent(void)const
{
	return (((((width()*(long)bitCount())+31)&~31)>>3)*height());
}
#endif
