#include <common/bminfo.hpp>
#include <common/bitmap.hpp>
#include <common/array.hpp>
#include <common/memfile.hpp>
#include <bsptree/rgbtree.hpp>
#define MaxBlock 64000L

Bitmap::Bitmap(void)
: mhFile(HFILE_ERROR), mCurrentMode(Idle), mMaxColors(0), mImageExtent(0),
	mBlockSize(MaxBlock), mWidth(0), mHeight(0)
{
}

Bitmap::Bitmap(const Bitmap &someBitmap)
: mMaxColors(someBitmap.mMaxColors), mFileName(someBitmap.mFileName),
	mImageExtent(someBitmap.mImageExtent), mBlockSize(someBitmap.mBlockSize),
  mhFile(HFILE_ERROR), mCurrentMode(Write), mWidth(0), mHeight(0)
{
	if(!someBitmap.isOkay())return;
	copyBitmap(someBitmap);
}

Bitmap::Bitmap(const String &pathFileName)
: mhFile(HFILE_ERROR), mMaxColors(0), mCurrentMode(Read), mImageExtent(0),
  mBlockSize(MaxBlock), mWidth(0), mHeight(0)
{
	processBitmap(pathFileName);
}

Bitmap::Bitmap(const String &pathFileName,HGLOBAL hGlobalImage,HGLOBAL hGlobalBitmapInfo)
: mhFile(HFILE_ERROR), mMaxColors(0), mCurrentMode(Write), mImageExtent(0),
  mBlockSize(MaxBlock), mWidth(0), mHeight(0)
{
	DWORD sizeBitmapInfo;
	DWORD sizeBitmapImage;
	BITMAPINFO FAR *lpSourceBitmapInfo;
	UHUGE *lpSourceImage;

	if(!hGlobalImage||!hGlobalBitmapInfo)return;
	if(pathFileName.isNull())return;
	mFileName=pathFileName;
	sizeBitmapInfo=::GlobalSize(hGlobalBitmapInfo);
	sizeBitmapImage=::GlobalSize(hGlobalImage);
	reserveInfo(sizeBitmapInfo);
	lpSourceBitmapInfo=(BITMAPINFO FAR*)::GlobalLock(hGlobalBitmapInfo);
	copyBits((UHUGE*)getInfoPtr(),(UHUGE*)lpSourceBitmapInfo,sizeBitmapInfo);
	::GlobalUnlock(hGlobalBitmapInfo);
  mImageExtent=imageExtent();
	if(mImageExtent!=sizeBitmapImage)mImageExtent=sizeBitmapImage;
  reserveData(mImageExtent);
	lpSourceImage=(UHUGE*)::GlobalLock(hGlobalImage);
  copyBits(getDataPtr(),lpSourceImage,mImageExtent);
	::GlobalUnlock(hGlobalImage);
	if(!(mMaxColors=(WORD)getInfoPtr()->bmiHeader.biClrUsed))mMaxColors=1<<getInfoPtr()->bmiHeader.biBitCount;
	mWidth=getInfoPtr()->bmiHeader.biWidth;
	mHeight=getInfoPtr()->bmiHeader.biHeight;
	setPalette();
}

Bitmap::Bitmap(const String &pathFileName,BitmapInfo &infoData,GlobalData<BYTE> &imageData)
: mhFile(HFILE_ERROR), mMaxColors(0), mCurrentMode(Write), mImageExtent(0),
	mBlockSize(MaxBlock), mWidth(0), mHeight(0)
{
	DWORD sizeBitmapInfo;
	DWORD sizeBitmapImage;
	BITMAPINFO FAR *lpSourceBitmapInfo;
	UHUGE *lpSourceImage;

	if(!imageData.size())return;
	if(pathFileName.isNull())return;
	mFileName=pathFileName;
	sizeBitmapInfo=(sizeof(BITMAPINFO)-sizeof(RGBQUAD))+(infoData.rgbColors()*sizeof(RGBQUAD));
	sizeBitmapImage=imageData.size();
	reserveInfo(sizeBitmapInfo);
	copyBits((UHUGE*)getInfoPtr(),(UHUGE*)((BITMAPINFO*)infoData),sizeBitmapInfo);
	mImageExtent=imageExtent();
	if(mImageExtent!=sizeBitmapImage)mImageExtent=sizeBitmapImage;
	reserveData(mImageExtent);
	copyBits(getDataPtr(),(BYTE*)&imageData[0],mImageExtent);
	if(BitmapInfo::Bit8==getInfoPtr()->bmiHeader.biBitCount&&!(mMaxColors=(WORD)getInfoPtr()->bmiHeader.biClrUsed))mMaxColors=1<<getInfoPtr()->bmiHeader.biBitCount;
	mWidth=getInfoPtr()->bmiHeader.biWidth;
	mHeight=getInfoPtr()->bmiHeader.biHeight;
  if(BitmapInfo::Bit8==getInfoPtr()->bmiHeader.biBitCount)setPalette();
}

Bitmap::Bitmap(const String &pathFileName,WORD bitmapWidth,WORD bitmapHeight,WORD bitmapColors,WORD bitCount)
: mhFile(HFILE_ERROR), mMaxColors(bitmapColors), mCurrentMode(Write),
	mImageExtent(0), mBlockSize(MaxBlock), mWidth(0), mHeight(0)
{
	BITMAPINFOHEADER bitmapInfoHeader;
	LONG rgbQuadBytes(bitmapColors*sizeof(RGBQUAD));
	UHUGE *lpPtr;

	if(!bitmapWidth||!bitmapHeight||!bitmapColors||pathFileName.isNull())return;
	getRequiredWidth(bitmapWidth,bitmapHeight);
	mFileName=pathFileName;
	bitmapInfoHeader.biSize=sizeof(BITMAPINFOHEADER);
	mWidth=bitmapInfoHeader.biWidth=bitmapWidth;
	mHeight=bitmapInfoHeader.biHeight=bitmapHeight;
	bitmapInfoHeader.biPlanes=Planes;
	bitmapInfoHeader.biBitCount=bitCount;
	bitmapInfoHeader.biCompression=BI_RGB;
	bitmapInfoHeader.biSizeImage=0;
	bitmapInfoHeader.biXPelsPerMeter=0;
	bitmapInfoHeader.biYPelsPerMeter=0;
	bitmapInfoHeader.biClrUsed=bitmapColors;
	bitmapInfoHeader.biClrImportant=bitmapColors;
	reserveInfo(0,bitmapColors);
	copyBits((UHUGE*)getInfoPtr(),(UHUGE*)&bitmapInfoHeader,sizeof(BITMAPINFOHEADER));
	lpPtr=((UHUGE*)getInfoPtr())+sizeof(BITMAPINFOHEADER);
	setBits(lpPtr,0,rgbQuadBytes);
  mImageExtent=imageExtent();
	lpPtr=reserveData(mImageExtent);
	setBits(lpPtr,0,mImageExtent);
}

Bitmap::~Bitmap()
{
  closeFile();
}

WORD Bitmap::operator+=(const BitmapOverlay &someBitmapOverlay)
{
	Bitmap &sourceBitmap=((BitmapOverlay&)someBitmapOverlay).bitmap();
	Point placementPoint(((BitmapOverlay&)someBitmapOverlay).placementPoint());
	UHUGE *lpSrcData;
	UHUGE *lpDstData;
	UHUGE *lpSrcPtr;
	UHUGE *lpDstPtr;
	LONG srcWidth;
	LONG srcHeight;
	LONG dstWidth;
	LONG dstHeight;
	LONG copyRows;
  LONG copyCols;

	if(!isOkay()||!sourceBitmap.isOkay())return FALSE;
  mCurrentMode=Write;
	srcWidth=copyCols=sourceBitmap.getInfoPtr()->bmiHeader.biWidth;
	srcHeight=copyRows=sourceBitmap.getInfoPtr()->bmiHeader.biHeight;
	dstWidth=getInfoPtr()->bmiHeader.biWidth;
	dstHeight=getInfoPtr()->bmiHeader.biHeight;
	if(placementPoint.x()<0)placementPoint.x(0);
	if(placementPoint.y()<0)placementPoint.y(0);
	if(placementPoint.x()>=dstWidth)return FALSE;
	if(placementPoint.y()>=dstHeight)return FALSE;
	if((LONG)placementPoint.x()+srcWidth>dstWidth)copyCols=dstWidth-placementPoint.x();
	if((LONG)placementPoint.y()+srcHeight>dstHeight)copyRows=dstHeight-placementPoint.y();
	upsideDown();
  sourceBitmap.upsideDown();
	lpSrcData=sourceBitmap.getDataPtr();
	lpDstData=getDataPtr();
	for(LONG srcRow=0;srcRow<copyRows;srcRow++)
	{
		lpSrcPtr=(lpSrcData+(srcWidth*srcRow));
		lpDstPtr=(lpDstData+(((srcRow+(LONG)placementPoint.y())*dstWidth)+(LONG)placementPoint.x()));
    copyBits(lpDstPtr,lpSrcPtr,copyCols);
	}
	upsideDown();
  sourceBitmap.upsideDown();
  return TRUE;
}

void Bitmap::upsideDown(void)
{
	LONG width(getInfoPtr()->bmiHeader.biWidth);
	LONG height(getInfoPtr()->bmiHeader.biHeight);
	UHUGE *lpSrc=getDataPtr();
	UHUGE *lpDst;
	HGLOBAL hGlobalTemp;

	hGlobalTemp=::GlobalAlloc(GMEM_ZEROINIT|GMEM_MOVEABLE,width*height);
	lpDst=(UHUGE*)::GlobalLock(hGlobalTemp);
	for(LONG rowIndex=0;rowIndex<height;rowIndex++)
		copyBits(lpDst+(rowIndex*width),(lpSrc+(height-rowIndex)*width)-width,width);
	if(BitmapData::Keep==getDataType())copyBits(lpSrc,lpDst,width*height);
	else setData(hGlobalTemp,lpDst);
}

void Bitmap::copyBitmap(const Bitmap &someBitmap)
{
	DWORD sizeBitmapInfo;
	DWORD sizeBitmapData;

	sizeBitmapInfo=::GlobalSize(someBitmap.getInfoHnd());
	sizeBitmapData=::GlobalSize(someBitmap.getDataHnd());
	reserveData(sizeBitmapData);
	reserveInfo(sizeBitmapInfo);
	copyBits((UHUGE*)reserveInfo(sizeBitmapInfo),(UHUGE*)someBitmap.getInfoPtr(),sizeBitmapInfo);
  copyBits((UHUGE*)reserveData(sizeBitmapData),(UHUGE*)someBitmap.getDataPtr(),sizeBitmapData);
	mWidth=getInfoPtr()->bmiHeader.biWidth;
	mHeight=getInfoPtr()->bmiHeader.biHeight;
	mBitmapPalette=someBitmap.getPalette();
}

WORD Bitmap::operator=(const String &pathFileName)
{
	int returnCode;

	mCurrentMode=Read;
	returnCode=processBitmap(pathFileName);
	return returnCode;
}

Bitmap &Bitmap::operator=(const Bitmap &someBitmap)
{
	if(!someBitmap.isOkay())return *this;
  if(getDataType()==BitmapData::Keep)return *this;
  mCurrentMode=someBitmap.mCurrentMode;
	mMaxColors=someBitmap.mMaxColors;
	mFileName=someBitmap.mFileName;
	mImageExtent=someBitmap.mImageExtent;
	copyBitmap(someBitmap);
	return *this;
}

WORD Bitmap::processBitmap(const String &pathFileName)
{
	OFSTRUCT ofStruct;

	mFileName=pathFileName;
	if(HFILE_ERROR==(mhFile=::OpenFile(pathFileName,&ofStruct,OF_READ)))return FALSE;
	::_lread(mhFile,&mBitmapFileHeader,sizeof(BITMAPFILEHEADER));
	if(Signature!=mBitmapFileHeader.bfType){closeFile();return FALSE;}
	readPalette();
	decodeImage();
  closeFile();
	return TRUE;
}

BOOL Bitmap::isValidBitmap(const String &pathFileName)const
{
	HFILE hFile;
	OFSTRUCT ofStruct;
	BITMAPFILEHEADER bitmapFileHeader;

	if(pathFileName.isNull())return FALSE;
	if(HFILE_ERROR==(hFile=::OpenFile(pathFileName,&ofStruct,OF_READ)))return FALSE;
	::_lread(hFile,&bitmapFileHeader,sizeof(BITMAPFILEHEADER));
	::_lclose(hFile);
	if(Signature!=bitmapFileHeader.bfType)return FALSE;
  return TRUE;
}

HPALETTE Bitmap::getPalette(void)const
{
  return mBitmapPalette.getPalette();
}

WORD Bitmap::setPalette(HPALETTE hPalette,WORD remapBitmap)
{
	BITMAPINFOHEADER bitmapInfoHeader;

	if(!isOkay()||!hPalette)return FALSE;
	PurePalette purePalette(hPalette);
	if(mBitmapPalette==purePalette)return FALSE;
  if(remapBitmap)mapPalette(purePalette);
	mBitmapPalette=purePalette;
	mMaxColors=mBitmapPalette.paletteEntries();
	::memcpy(&bitmapInfoHeader,getInfoPtr(),sizeof(BITMAPINFOHEADER));
  reserveInfo(0,mMaxColors);
	::memcpy(getInfoPtr(),&bitmapInfoHeader,sizeof(BITMAPINFOHEADER));
	getInfoPtr()->bmiHeader.biClrUsed=0;
  getInfoPtr()->bmiHeader.biClrImportant=0;
	for(int itemIndex=0;itemIndex<mMaxColors;itemIndex++)
	{
		getInfoPtr()->bmiColors[itemIndex].rgbRed=mBitmapPalette[itemIndex].red();
		getInfoPtr()->bmiColors[itemIndex].rgbGreen=mBitmapPalette[itemIndex].green();
		getInfoPtr()->bmiColors[itemIndex].rgbBlue=mBitmapPalette[itemIndex].blue();
    getInfoPtr()->bmiColors[itemIndex].rgbReserved=0;
	}
	return TRUE;
}

void Bitmap::mapPalette(PurePalette &purePalette)
{
  Array<RGBIndex> rgbIndexVector;
	WORD paletteEntries;
	RGBTree paletteTree;
	RGBColor rgbColor;
	RGBIndex rgbIndex;

	paletteEntries=purePalette.paletteEntries();
	rgbIndexVector.size(paletteEntries);
	for(int paletteIndex=0;paletteIndex<paletteEntries;paletteIndex++)
	{
		rgbColor=purePalette[paletteIndex];
		rgbIndex=RGBIndex(rgbColor,paletteIndex);
		rgbIndexVector[paletteIndex]=rgbIndex;
	}
	paletteTree.insertItems(rgbIndexVector);
	for(int mapIndex=0;mapIndex<mImageExtent;mapIndex++)
	{
		paletteIndex=*(getDataPtr()+mapIndex);
		rgbColor=mBitmapPalette[paletteIndex];
		RGBIndex searchIndex(rgbColor,paletteIndex);
		if(paletteTree.searchItem(searchIndex,RGBTree::SearchNearest))
			*(getDataPtr()+mapIndex)=searchIndex.paletteIndex();
	}
}

void Bitmap::setPalette(void)
{
	RGBColor rgbColor;

 	if(!isOkay())return;
	for(int paletteIndex=0;paletteIndex<mMaxColors;paletteIndex++)
	{
		rgbColor.red(getInfoPtr()->bmiColors[paletteIndex].rgbRed);
		rgbColor.green(getInfoPtr()->bmiColors[paletteIndex].rgbGreen);
		rgbColor.blue(getInfoPtr()->bmiColors[paletteIndex].rgbBlue);
		mBitmapPalette.setPaletteColor(paletteIndex,rgbColor,PaletteEntry::NullFlag);
	}
	return;
}

void Bitmap::readPalette(void)
{
	RGBQUAD FAR *lpRGBQuad;
	BITMAPINFOHEADER bitmapInfoHeader;

	if(HFILE_ERROR==mhFile||Read!=mCurrentMode)return;
	::_lread(mhFile,&bitmapInfoHeader,sizeof(BITMAPINFOHEADER));
	if(!(mMaxColors=(WORD)bitmapInfoHeader.biClrUsed))mMaxColors=1<<bitmapInfoHeader.biBitCount;
  reserveInfo(0,mMaxColors);
	::memcpy(getInfoPtr(),&bitmapInfoHeader,sizeof(BITMAPINFOHEADER));
	mWidth=getInfoPtr()->bmiHeader.biWidth;
  mHeight=getInfoPtr()->bmiHeader.biHeight;
  getRequiredWidth(mWidth,mHeight);

	for(int i=0;i<mMaxColors;i++)
	{
		lpRGBQuad=(RGBQUAD FAR *)&(getInfoPtr()->bmiColors[i]);
		::_lread(mhFile,lpRGBQuad,sizeof(RGBQUAD));
    mBitmapPalette.setPaletteColor(i,RGBColor(lpRGBQuad->rgbRed,lpRGBQuad->rgbGreen,lpRGBQuad->rgbBlue),PaletteEntry::NullFlag);
	}
}

void Bitmap::decodeImage(void)
{
	switch(getInfoPtr()->bmiHeader.biCompression)
	{
		case BI_RGB :
			mImageExtent=imageExtent();
			reserveData(mImageExtent);
			::_llseek(mhFile,(mBitmapFileHeader.bfOffBits),0);
			::_hread(mhFile,getDataPtr(),mImageExtent);
			break;
		case BI_RLE4 :
			closeFile();
			::MessageBox(::GetFocus(),(LPSTR)"BI_RLE4 is not supported at this time.\nPlease try an uncompressed bitmap.",(LPSTR)"ERROR",MB_ICONEXCLAMATION);
			break;
		case BI_RLE8 :
			closeFile();
			::MessageBox(::GetFocus(),(LPSTR)"BI_RLE8 is not supported at this time.\nPlease try an uncompressed bitmap.",(LPSTR)"ERROR",MB_ICONEXCLAMATION);
			break;
	}
}

HBITMAP Bitmap::createBitmap(PureDevice &somePureDevice)
{
	HBITMAP hBitmap;

  if(!isOkay())return FALSE;
	hBitmap=::CreateDIBitmap(somePureDevice,(BITMAPINFOHEADER FAR*)getInfoPtr(),
		CBM_INIT,getDataPtr(),(BITMAPINFO FAR*)getInfoPtr(),DIB_RGB_COLORS);
	return hBitmap;
}

WORD Bitmap::displayBitmap(HWND hDisplayWindow,HDC hDC,int isActive,int conforming)const
{
	RECT windowRect;
	HPALETTE hOldPalette;
	WORD windowWidth;
	WORD windowHeight;
	int suppliedDC;

	if(!isOkay()||!::IsWindow(hDisplayWindow))return FALSE;
	::GetClientRect(hDisplayWindow,(RECT FAR *)&windowRect);
  windowWidth=windowRect.right;
	windowHeight=windowRect.bottom;
	if(!hDC){suppliedDC=FALSE;hDC=::GetDC(hDisplayWindow);}
  if(isActive)hOldPalette=::SelectPalette(hDC,mBitmapPalette.getPalette(),FALSE);
	else hOldPalette=::SelectPalette(hDC,mBitmapPalette.getPalette(),TRUE);
	::RealizePalette(hDC);
	if(conforming)::StretchDIBits(hDC,0,0,windowRect.right,windowRect.bottom,0,0,
		width(),height(),getDataPtr(),(BITMAPINFO *)getInfoPtr(),DIB_RGB_COLORS,SRCCOPY);
	else
	{
		::StretchDIBits(hDC,0,0,width()>windowWidth?windowWidth:width(),
			height()>windowHeight?windowHeight:height(),0,0,width(),height(),
			getDataPtr(),(BITMAPINFO *)getInfoPtr(),DIB_RGB_COLORS,SRCCOPY);
	}
	if(isActive)::SelectPalette(hDC,hOldPalette,FALSE);
	else ::SelectPalette(hDC,hOldPalette,TRUE);
	if(!suppliedDC)::ReleaseDC(hDisplayWindow,hDC);
	return TRUE;
}

BOOL Bitmap::draw(PureDevice &pureDevice,const Rect &dstRect,const Point &srcPoint)
{
  if(!isOkay())return FALSE;
	::StretchDIBits(pureDevice,dstRect.left(),dstRect.top(),dstRect.right(),dstRect.bottom(),srcPoint.x(),srcPoint.y(),dstRect.right(),dstRect.bottom(),getDataPtr(),(BITMAPINFO *)getInfoPtr(),DIB_RGB_COLORS,SRCCOPY);
	return TRUE;
}

bool Bitmap::saveBitmap(void)
{
	BITMAPFILEHEADER bitmapFileHeader;
	OFSTRUCT ofStruct;

	if(!isOkay())return false;
	if((HFILE_ERROR==mhFile)&&(HFILE_ERROR==(mhFile=::OpenFile(mFileName,&ofStruct,OF_WRITE|OF_CREATE))))return false;
	::memset(&bitmapFileHeader,0,sizeof(BITMAPFILEHEADER));
	bitmapFileHeader.bfType=Signature;
	bitmapFileHeader.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)+(sizeof(RGBQUAD)*(mMaxColors-1))+mImageExtent;
	bitmapFileHeader.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)+(sizeof(RGBQUAD)*(mMaxColors-1));
	::_lwrite(mhFile,(char*)&bitmapFileHeader,sizeof(BITMAPFILEHEADER));
	::_lwrite(mhFile,(char*)getInfoPtr(),sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)+(sizeof(RGBQUAD)*(mMaxColors-1)));
	::_hwrite(mhFile,(char*)getDataPtr(),mImageExtent);
	closeFile();
	return true;
}

bool Bitmap::saveBitmap(MemFile &memFile)
{
	BITMAPFILEHEADER bitmapFileHeader;
	OFSTRUCT ofStruct;

	if(!isOkay())return false;
	if((HFILE_ERROR==mhFile)&&(HFILE_ERROR==(mhFile=::OpenFile(mFileName,&ofStruct,OF_WRITE|OF_CREATE))))return false;
	::memset(&bitmapFileHeader,0,sizeof(BITMAPFILEHEADER));
	bitmapFileHeader.bfType=Signature;
	bitmapFileHeader.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)+(sizeof(RGBQUAD)*(mMaxColors-1))+mImageExtent;
	bitmapFileHeader.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)+(sizeof(RGBQUAD)*(mMaxColors-1));
	if(!memFile.write((char*)&bitmapFileHeader,sizeof(BITMAPFILEHEADER)))return false;
  if(!memFile.write((char*)getInfoPtr(),sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)+(sizeof(RGBQUAD)*(mMaxColors-1))))return false;
  if(!memFile.write((char*)getDataPtr(),mImageExtent))return false;
	return true;
}

bool Bitmap::saveBitmap(const String &pathFileName)
{
	if(!isOkay())return false;
	mFileName=pathFileName;
  return saveBitmap();
}

void Bitmap::copyBits(UHUGE *destination,UHUGE *source,unsigned long length)const
{
	for(unsigned long count=0;count<length;count++)*destination++=*source++;
}

void Bitmap::setBits(UHUGE *lpChar,unsigned char charValue,unsigned long length)const
{
	for(unsigned long count=0;count<length;count++)*lpChar++=charValue;
}

void Bitmap::getRequiredWidth(WORD &desiredWidth,WORD desiredHeight)
{
	DWORD imageExtent;

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

void Bitmap::getRequiredWidth(DWORD &desiredWidth,DWORD desiredHeight)
{
	DWORD imageExtent;

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

Bitmap &Bitmap::rotateRight(void)
{
	Bitmap tempBitmap(mFileName,height(),width());
	
  tempBitmap.setPalette(getPalette(),FALSE);
	for(int rowIndex=0;rowIndex<height();rowIndex++)
		for(int colIndex=0;colIndex<width();colIndex++)
			tempBitmap.setByte(colIndex,(height()-1)-rowIndex,getByte(rowIndex,colIndex));
	*this=tempBitmap;
  return *this;
}

Bitmap &Bitmap::rotateLeft(void)
{
	Bitmap tempBitmap(mFileName,height(),width());
	
	tempBitmap.setPalette(getPalette(),FALSE);
	for(int rowIndex=0;rowIndex<height();rowIndex++)
		for(int colIndex=0;colIndex<width();colIndex++)
			tempBitmap.setByte((width()-1)-colIndex,rowIndex,getByte(rowIndex,colIndex));
	*this=tempBitmap;
  return *this;
}

WORD Bitmap::getRow(WORD row,char FAR *lpRowData)
{
	if(!isOkay()||row>=height()||!lpRowData)return FALSE;
	UHUGE *lpImage=getDataPtr()+mImageExtent;
	copyBits((UHUGE*)lpRowData,(lpImage-(((LONG)row*(LONG)width())+(LONG)width())),width());
  return TRUE;
}

WORD Bitmap::setRow(WORD row,char FAR *lpRowData)
{
	if(!isOkay()||row>=height()||!lpRowData)return FALSE;
	UHUGE *lpImage=getDataPtr()+mImageExtent;
	copyBits((UHUGE*)(lpImage-(((LONG)row*(LONG)width())+(LONG)width())),(UHUGE*)lpRowData,width());
  return TRUE;
}

WORD Bitmap::getCol(WORD col,char FAR *lpColData)
{
  if(!isOkay()||col>=width()||!lpColData)return FALSE;
	UHUGE *lpImage=getDataPtr()+mImageExtent;
	lpImage=(lpImage-(LONG)width())+(LONG)col;
	for(short rowIndex=0;rowIndex<height();rowIndex++)
	{
		*lpColData=*lpImage;
		lpImage-=(LONG)width();
		lpColData++;
	}
	return TRUE;
}

WORD Bitmap::setCol(WORD col,char FAR *lpColData)
{
	if(!isOkay()||col>=width()||!lpColData)return FALSE;
	UHUGE *lpImage=getDataPtr()+mImageExtent;
	lpImage=(lpImage-(LONG)width())+(LONG)col;
	for(short rowIndex=0;rowIndex<height();rowIndex++)
	{
		*lpImage=*lpColData;
		lpImage-=(LONG)width();
    lpColData++;
	}
  return TRUE;
}

