#include <common/bminfo.hpp>
#include <common/purepal.hpp>

BitmapInfo &BitmapInfo::operator=(const BitmapInfo &someBitmapInfo)
{
	createInfo(someBitmapInfo.rgbColors());
	planes(someBitmapInfo.planes());
	width(someBitmapInfo.width());
	height(someBitmapInfo.height());
	bitCount(someBitmapInfo.bitCount());
	compression(someBitmapInfo.compression());
	sizeImage(someBitmapInfo.sizeImage());
	xPelsPerMeter(someBitmapInfo.xPelsPerMeter());
	yPelsPerMeter(someBitmapInfo.yPelsPerMeter());
	colorUsed(someBitmapInfo.colorUsed());
	colorImportant(someBitmapInfo.colorImportant());
	for(int itemIndex=0;itemIndex<someBitmapInfo.rgbColors();itemIndex++)operator[](itemIndex)=((BitmapInfo&)someBitmapInfo)[itemIndex];
	return *this;
}

BitmapInfo &BitmapInfo::operator=(const BITMAPINFO &someBITMAPINFO)
{
  createInfo(someBITMAPINFO.bmiHeader.biClrImportant);
	planes(someBITMAPINFO.bmiHeader.biPlanes);
	width(someBITMAPINFO.bmiHeader.biWidth);
	height(someBITMAPINFO.bmiHeader.biHeight);
	bitCount(BitsPerPixel(someBITMAPINFO.bmiHeader.biBitCount));
	compression(BiCompression(someBITMAPINFO.bmiHeader.biCompression));
	sizeImage(someBITMAPINFO.bmiHeader.biSizeImage);
	xPelsPerMeter(someBITMAPINFO.bmiHeader.biXPelsPerMeter);
	yPelsPerMeter(someBITMAPINFO.bmiHeader.biYPelsPerMeter);
	colorUsed(someBITMAPINFO.bmiHeader.biClrUsed);
	colorImportant(someBITMAPINFO.bmiHeader.biClrImportant);
	for(int itemIndex=0;itemIndex<someBITMAPINFO.bmiHeader.biClrImportant;itemIndex++)
	{
	  RGBQuad &rgbQuad=operator[](itemIndex);
		rgbQuad.red(someBITMAPINFO.bmiColors[itemIndex].rgbRed);
		rgbQuad.green(someBITMAPINFO.bmiColors[itemIndex].rgbGreen);
		rgbQuad.blue(someBITMAPINFO.bmiColors[itemIndex].rgbBlue);
	}
	return *this;
}

BitmapInfo &BitmapInfo::operator=(const PurePalette &somePurePalette)
{
	WORD paletteEntries(somePurePalette.paletteEntries());
	PaletteEntry paletteEntry;

	if(!paletteEntries)return *this;
  rgbColors(paletteEntries);
	for(WORD paletteIndex=0;paletteIndex<paletteEntries;paletteIndex++)
	{
		paletteEntry=somePurePalette.paletteEntry(paletteIndex);
		mlpBitmapInfo->bmiColors[paletteIndex].rgbRed=paletteEntry.red();
		mlpBitmapInfo->bmiColors[paletteIndex].rgbGreen=paletteEntry.green();
		mlpBitmapInfo->bmiColors[paletteIndex].rgbBlue=paletteEntry.blue();
		mlpBitmapInfo->bmiColors[paletteIndex].rgbReserved=0;
	}
  return *this;
}

WORD BitmapInfo::operator==(const BitmapInfo &someBitmapInfo)const
{
	if(rgbColors()!=someBitmapInfo.rgbColors())return FALSE;
	if (!(planes()==someBitmapInfo.planes())||
			!(width()==someBitmapInfo.width())||
			!(height()==someBitmapInfo.height())||
			!(bitCount()==someBitmapInfo.bitCount())||
			!(compression()==someBitmapInfo.compression())||
			!(sizeImage()==someBitmapInfo.sizeImage())||
			!(xPelsPerMeter()==someBitmapInfo.xPelsPerMeter())||
			!(yPelsPerMeter()==someBitmapInfo.yPelsPerMeter())||
			!(colorUsed()==someBitmapInfo.colorUsed())||
			!(colorImportant()==someBitmapInfo.colorImportant()))return FALSE;
	for(int itemIndex=0;itemIndex<rgbColors();itemIndex++)
	  if(!(((BitmapInfo&)*this).operator[](itemIndex)==((BitmapInfo&)someBitmapInfo)[itemIndex]))return FALSE;
  return TRUE;
}

void BitmapInfo::rgbColors(DWORD rgbColors)
{
	BitmapInfo bitmapInfo(*this);

	createInfo(rgbColors);
	planes(bitmapInfo.planes());
	width(bitmapInfo.width());
	height(bitmapInfo.height());
	bitCount(bitmapInfo.bitCount());
	compression(bitmapInfo.compression());
	sizeImage(bitmapInfo.sizeImage());
	xPelsPerMeter(bitmapInfo.xPelsPerMeter());
	yPelsPerMeter(bitmapInfo.yPelsPerMeter());
	colorUsed(rgbColors);
	colorImportant(rgbColors);
}

void BitmapInfo::createInfo(DWORD rgbColors)
{
	destroyInfo();
  if(!rgbColors)rgbColors=1;
	mhGlobalHandle=::GlobalAlloc(GMEM_FIXED|GMEM_ZEROINIT,sizeof(BITMAPINFO)+(sizeof(RGBQUAD)*(rgbColors-1)));
	mlpBitmapInfo=(BITMAPINFO*)::GlobalLock(mhGlobalHandle);
	mlpBitmapInfo->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
	bitCount(BitsPerPixel(DefaultBitCount));
	compression(BiRGB);
	planes(DefaultPlanes);
	colorUsed(rgbColors);
  colorImportant(rgbColors);
	mRGBColors=rgbColors;
}
 
void BitmapInfo::destroyInfo(void)
{
	if(!mhGlobalHandle)return;
	::GlobalUnlock(mhGlobalHandle);
	::GlobalFree(mhGlobalHandle);
	mhGlobalHandle=0;
	mlpBitmapInfo=0;
  mRGBColors=0;
}

void BitmapInfo::verifyDimensions(void)
{
	DWORD desiredHeight(height()<0?-height():height());
  DWORD desiredWidth(width());
	DWORD imageExtent;

  imageExtent=(((((LONG)desiredWidth*8)+31)&~31)>>3)*(LONG)desiredHeight;
	if(imageExtent==(LONG)desiredWidth*(LONG)desiredHeight)return;
	else desiredWidth=(WORD)(imageExtent/(LONG)desiredHeight);
	width(desiredWidth);
}

String BitmapInfo::toString(void)const
{
  String strCompression;
  String str;
	str+=String("[BitmapInfo::toString]planes=")+String().fromInt(planes())+String("\n");
	str+=String("[BitmapInfo::toString]width=")+String().fromInt(width())+String("\n");
	str+=String("[BitmapInfo::toString]height=")+String().fromInt(height())+String("\n");
	str+=String("[BitmapInfo::toString]bitCount=")+String().fromInt(bitCount())+String("\n");
  if(BiRGB==compression())strCompression="BI_RGB";
	else if(BiBitFields==compression())strCompression="BI_BITFIELDS";
	else if(BiRLE8==compression())strCompression="BI_RLE8";
	else if(BiRLE4==compression())strCompression="BI_RLE4";
	else strCompression=makeCompressionString();
	str+=String("[BitmapInfo::toString]compression=")+strCompression+String("\n");
	str+=String("[BitmapInfo::toString]sizeImage=")+String().fromInt(sizeImage())+String("\n");
	str+=String("[BitmapInfo::toString]xPelsPerMeter=")+String().fromInt(xPelsPerMeter())+String("\n");
	str+=String("[BitmapInfo::toString]yPelsPerMeter=")+String().fromInt(yPelsPerMeter())+String("\n");
	str+=String("[BitmapInfo::toString]colorUsed=")+String().fromInt(colorUsed())+String("\n");
	str+=String("[BitmapInfo::toString]colorImportant=")+String().fromInt(colorImportant())+String("\n");
  return str;
}

String BitmapInfo::makeCompressionString(void)const
{
  String strCompression;

  strCompression.reserve(5);
	((char*)strCompression)[0]=(BYTE)(compression()&0xFF);
	((char*)strCompression)[1]=(BYTE)((compression()>>0x08)&0xFF);
	((char*)strCompression)[2]=(BYTE)((compression()>>0x10)&0xFF);
	((char*)strCompression)[3]=(BYTE)((compression()>>0x18)&0xFF);
	return strCompression;
}

