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

PureBitmap::PureBitmap(const String &strNameBitmap,HINSTANCE hInstance)
: mhBitmap(0)
{
	mhBitmap=::LoadBitmap(hInstance,strNameBitmap);
	if(mhBitmap)::GetObject(mhBitmap,sizeof(BITMAP),(LPSTR)&mBitmap);
}

WORD PureBitmap::operator==(const PureBitmap &somePureBitmap)const
{
	GlobalData<BYTE> bmData;
	GlobalData<BYTE> someBmData;

  if((width()!=somePureBitmap.width())||(height()!=somePureBitmap.height()))return FALSE;
	getBitmapBits(bmData);
	somePureBitmap.getBitmapBits(someBmData);
	if(bmData.size()!=someBmData.size())return FALSE;
	return bmData==someBmData;
}

WORD PureBitmap::operator=(const PureBitmap &somePureBitmap)
{
	PureDevice srcDevice;
	PureDevice dstDevice;

	if(!somePureBitmap.isOkay())return FALSE;
	srcDevice.compatibleDevice();
	dstDevice.compatibleDevice(srcDevice);
	srcDevice.select(somePureBitmap);
	compatibleBitmap(srcDevice,somePureBitmap);
	dstDevice.select(*this);
	::BitBlt((HDC)dstDevice,0,0,somePureBitmap.width(),somePureBitmap.height(),(HDC)srcDevice,0,0,SRCCOPY);
	return TRUE;
}

WORD PureBitmap::operator=(HBITMAP hBitmap)
{
	BITMAP bmBitmap;
	PureDevice dstDevice;
	PureDevice srcDevice;

	if(!hBitmap)return FALSE;
	::GetObject(hBitmap,sizeof(BITMAP),(LPSTR)&bmBitmap);
	srcDevice.compatibleDevice();
	dstDevice.compatibleDevice(srcDevice);
	srcDevice.select(hBitmap);
	compatibleBitmap(srcDevice,bmBitmap.bmWidth,bmBitmap.bmHeight);
	dstDevice.select(*this);
	::BitBlt((HDC)dstDevice,0,0,bmBitmap.bmWidth,bmBitmap.bmHeight,(HDC)srcDevice,0,0,SRCCOPY);
	return TRUE;
}

WORD PureBitmap::loadBitmap(const String &strNameBitmap,HINSTANCE hInstance)
{
	destroyBitmap();
	mhBitmap=::LoadBitmap(hInstance,strNameBitmap);
	if(mhBitmap)::GetObject(mhBitmap,sizeof(BITMAP),(LPSTR)&mBitmap);
	return isOkay();
}

BOOL PureBitmap::createFrom(PureBitmap &sourceBitmap,const Rect &srcRect)
{
  PureDevice srcDevice;
	PureDevice dstDevice;

	if(!sourceBitmap.isOkay())return FALSE;
	srcDevice.compatibleDevice();
	dstDevice.compatibleDevice(srcDevice);
	srcDevice.select(sourceBitmap);
	compatibleBitmap(srcDevice,srcRect.right(),srcRect.bottom());
	dstDevice.select(*this);
	::BitBlt((HDC)dstDevice,0,0,srcRect.right(),srcRect.bottom(),(HDC)srcDevice,srcRect.left(),srcRect.top(),SRCCOPY);
	return TRUE;
}

BOOL PureBitmap::setFrom(PureBitmap &sourceBitmap,const Rect &rect)const
{
  PureDevice srcDevice;
	PureDevice dstDevice;

	if(!sourceBitmap.isOkay()||!isOkay())return FALSE;
	srcDevice.compatibleDevice();
	dstDevice.compatibleDevice(srcDevice);
	srcDevice.select(sourceBitmap);
	dstDevice.select(*this);
	return ::StretchBlt((HDC)dstDevice,rect.left(),rect.top(),rect.right(),rect.bottom(),(HDC)srcDevice,0,0,sourceBitmap.width(),sourceBitmap.height(),SRCCOPY);
}

BOOL PureBitmap::getInto(PureBitmap &dstBitmap,const Rect &rect)const
{
  PureDevice srcDevice;
	PureDevice dstDevice;

	if(!dstBitmap.isOkay()||!isOkay())return FALSE;
	srcDevice.compatibleDevice();
	dstDevice.compatibleDevice(srcDevice);
	srcDevice.select(*this);
	dstDevice.select(dstBitmap);
	return ::StretchBlt((HDC)dstDevice,0,0,dstBitmap.width(),dstBitmap.height(),(HDC)srcDevice,rect.left(),rect.top(),width(),height(),SRCCOPY);
}											

WORD PureBitmap::screenBitmap(const Rect &boundingRect)
{
  RECT rect=((Rect&)boundingRect).getRect();
  return screenBitmap(rect);
}

WORD PureBitmap::screenBitmap(const RECT &boundingRect)
{
	PureDevice screenDevice;
	PureDevice memoryDevice;
	Point pointOne;
	Point pointTwo;
	int xPixels;
	int yPixels;

	if(::IsRectEmpty((RECT FAR*)&boundingRect))return FALSE;
	destroyBitmap();
	screenDevice.displayDevice();
	memoryDevice.compatibleDevice(screenDevice);
	pointOne.x(boundingRect.left);
	pointOne.y(boundingRect.top);
	pointTwo.x(boundingRect.right);
	pointTwo.y(boundingRect.bottom);
	xPixels=::GetDeviceCaps((HDC)screenDevice,HORZRES);
	yPixels=::GetDeviceCaps((HDC)screenDevice,VERTRES);
	if(0>pointOne.x())pointOne.x(0);
	if(0>pointOne.y())pointOne.y(0);
	if(pointTwo.x()>xPixels)pointTwo.x(xPixels);
	if(pointTwo.y()>yPixels)pointTwo.y(yPixels);
	compatibleBitmap(screenDevice,pointTwo.x()-pointOne.x()+1,pointTwo.y()-pointOne.y()+1);
  memoryDevice.select(*this);
	::BitBlt(memoryDevice,0,0,width(),height(),screenDevice,pointOne.x(),pointOne.y(),SRCCOPY);
	return isOkay();
}

WORD PureBitmap::windowBitmap(HWND hDisplayWindow)
{
	PureDevice displayDevice;
	PureDevice memoryDevice;
  Rect windowRect;
	short windowWidth;
  short windowHeight;

	if(!IsWindow(hDisplayWindow))return FALSE;
  ::GetClientRect(hDisplayWindow,(RECT FAR*)&windowRect);
	if(::IsRectEmpty((RECT FAR*)&windowRect))return FALSE;
	destroyBitmap();
  displayDevice=hDisplayWindow;
	memoryDevice.compatibleDevice(displayDevice);
	windowWidth=windowRect.right(); 
	windowHeight=windowRect.bottom();
	compatibleBitmap(displayDevice,windowWidth,windowHeight);
	memoryDevice.select(*this);
	::BitBlt(memoryDevice,0,0,width(),height(),displayDevice,0,0,SRCCOPY);
	return isOkay();
}

DWORD PureBitmap::getBitmapBits(GlobalData<BYTE> &bitmapBytes,BitmapInfo::BitsPerPixel bitsPerPixel,BOOL bottomUp)const
{
	PurePalette systemPalette;
  PureDevice pureDevice;
	BitmapInfo bmInfo;
  DWORD scanLines(0);
	DWORD scanLineWidth;
	WORD scanWidth;
	WORD scanHeight;

  if(!isOkay())return scanLines;
	scanLineWidth=width();
	if(scanLineWidth%2L)scanLineWidth++;
	scanWidth=scanLineWidth;
  scanHeight=height();
	bitmapBytes.size(scanLineWidth*(DWORD)height()*(bitsPerPixel/8));
	systemPalette.systemPalette();
	bmInfo.width(width());
	bmInfo.height(height());
	bmInfo.bitCount(bitsPerPixel);
	if(bitsPerPixel==BitmapInfo::Bit8){bmInfo.colorUsed(256);bmInfo.colorImportant(256);bmInfo=systemPalette;}
	else{bmInfo.colorUsed(0);bmInfo.colorImportant(0);}
	pureDevice.displayDevice();
  scanLines=::GetDIBits(pureDevice,*this,0,bottomUp?height():int(height())*-1,(BYTE*)&bitmapBytes[0],(BITMAPINFO*)bmInfo,DIB_RGB_COLORS);
  return scanLines;
}

DWORD PureBitmap::getBitmapBits(GlobalData<BYTE> &bitmapBytes,BitmapInfo::BitsPerPixel bitsPerPixel,PurePalette &purePalette,BOOL bottomUp)const
{
  PureDevice pureDevice;
	BitmapInfo bmInfo;
  DWORD scanLines(0);
	DWORD scanLineWidth;
	WORD scanWidth;
	WORD scanHeight;

  if(!isOkay())return scanLines;
	scanLineWidth=width();
	if(scanLineWidth%2L)scanLineWidth++;
	scanWidth=scanLineWidth;
  scanHeight=height();
	bitmapBytes.size(scanLineWidth*(DWORD)height()*(bitsPerPixel/8));
	purePalette.systemPalette();
	bmInfo.width(width());
	bmInfo.height(height());
	bmInfo.bitCount(bitsPerPixel);
	if(BitmapInfo::Bit8==bitsPerPixel){bmInfo.colorUsed(256);bmInfo.colorImportant(256);}
	else{bmInfo.colorUsed(0);bmInfo.colorImportant(0);}
	pureDevice.displayDevice();
  scanLines=::GetDIBits(pureDevice,*this,0,bottomUp?height():int(height())*-1,(BYTE*)&bitmapBytes[0],(BITMAPINFO*)bmInfo,DIB_RGB_COLORS);
  if(BitmapInfo::Bit8==bitsPerPixel){bmInfo.colorUsed(256);bmInfo.colorImportant(256);purePalette=bmInfo;}
  return scanLines;
}

bool PureBitmap::getBitmapInfo(BitmapInfo &bmInfo)
{
  PureDevice pureDevice;
	PurePalette systemPalette;
	int scanLines=0;

  if(!isOkay())return scanLines;
	systemPalette.systemPalette();
	bmInfo.width(width());
	bmInfo.height(height());
	bmInfo.bitCount(BitmapInfo::BitsPerPixel(bitsPerPixel()));
	bmInfo=systemPalette;
	pureDevice.displayDevice();
  scanLines=::GetDIBits(pureDevice,*this,0,height(),0,(BITMAPINFO*)bmInfo,DIB_RGB_COLORS);
  return scanLines;
}

DWORD PureBitmap::getBitmapBits(GlobalData<BYTE> &bitmapBytes,BOOL bottomUp)const
{
	PurePalette systemPalette;
  PureDevice pureDevice;
	BitmapInfo bmInfo;
  DWORD scanLines(0);
	DWORD scanLineWidth;
	WORD scanWidth;
	WORD scanHeight;

  if(!isOkay())return scanLines;
	scanLineWidth=width();
	if(scanLineWidth%2L)scanLineWidth++;
	scanWidth=scanLineWidth;
  scanHeight=height();
	bitmapBytes.size(scanLineWidth*(DWORD)height()*(mBitmap.bmBitsPixel/8));
	systemPalette.systemPalette();
	bmInfo.width(width());
	bmInfo.height(height());
	bmInfo.bitCount(BitmapInfo::BitsPerPixel(bitsPerPixel()));
	bmInfo=systemPalette;
	pureDevice.displayDevice();
  scanLines=::GetDIBits(pureDevice,*this,0,bottomUp?height():int(height())*-1,(BYTE*)&bitmapBytes[0],(BITMAPINFO*)bmInfo,DIB_RGB_COLORS);
  return scanLines;
}

DWORD PureBitmap::setBitmapBits(GlobalData<BYTE> &bitmapBytes,BOOL bottomUp)const
{
  DWORD scanLines(0);
	DWORD scanLineWidth;
	DWORD scanWidth;
	DWORD scanHeight;
  PureDevice pureDevice;
	BitmapInfo bmInfo;

  if(!isOkay())return scanLines;
	scanLineWidth=width();
	if(scanLineWidth%2L)scanLineWidth++;
	scanWidth=scanLineWidth;
  scanHeight=height();
	bitmapBytes.size(scanLineWidth*(DWORD)height()*(mBitmap.bmBitsPixel/8));
	PurePalette systemPalette;
	systemPalette.systemPalette();
	bmInfo.width(width());
	bmInfo.height(height());
	bmInfo.bitCount(BitmapInfo::BitsPerPixel(bitsPerPixel()));
	bmInfo=systemPalette;
	pureDevice.displayDevice();
  scanLines=::SetDIBits(pureDevice,*this,0,bottomUp?height():int(height())*-1,(BYTE*)&bitmapBytes[0],(BITMAPINFO*)bmInfo,DIB_RGB_COLORS);
	if(!scanLines)scanLines=::GetLastError();
  return scanLines;
}
