#ifndef _COMMON_BITMAP_HPP_
#define _COMMON_BITMAP_HPP_
#include <stdio.h>
#ifndef _COMMON_WINDOWS_HPP_
#include <common/windows.hpp>
#endif
#ifndef _COMMON_TYPES_HPP_
#include <common/types.hpp>
#endif
#ifndef _COMMON_STRING_HPP_
#include <common/string.hpp>
#endif
#ifndef _COMMON_BITMAPDATA_HPP_
#include <common/bmdata.hpp>
#endif
#ifndef _COMMON_PUREPALETTE_HPP_
#include <common/purepal.hpp>
#endif
#ifndef _COMMON_GLOBALDATA_HPP_
#include <common/gdata.hpp>
#endif
#ifndef _COMMON_BITMAPINFO_HPP_
#include <common/bminfo.hpp>
#endif
#ifndef _COMMON_BITMAPOVERLAY_HPP_
#include <common/boverlay.hpp>
#endif

class MemFile;

class Bitmap : public BitmapData
{
public:
	enum {MaxColors=256,BitCount=8,Planes=1};
	Bitmap(void);
	Bitmap(const Bitmap &someBitmap);
	Bitmap(const String &pathFileName);
	Bitmap(const String &pathFileName,HGLOBAL hGlobalImage,HGLOBAL hGlobalBitmapInfo);
	Bitmap(const String &pathFileName,WORD bitmapWidth,WORD bitmapHeight,WORD bitmapColors=MaxColors,WORD bitCount=BitCount);
  Bitmap(const String &pathFileName,BitmapInfo &infoData,GlobalData<BYTE> &imageData);
	~Bitmap();
  Bitmap &rotateRight(void);
  Bitmap &rotateLeft(void);
	WORD operator=(const String &pathFileName);
	Bitmap &operator=(const Bitmap &someBitmap);
	WORD operator+=(const BitmapOverlay &someBitmapOverlay);
	WORD operator==(const Bitmap &someBitmap)const;
	WORD width(void)const;
	WORD height(void)const;
	WORD planes(void)const;
	WORD bitCount(void)const;
	DWORD getImageExtent(void)const;
	void setByte(WORD row,WORD col,BYTE byteValue);
	BYTE getByte(WORD row,WORD col)const;
	WORD getRow(WORD row,char FAR *lpRowData);
	WORD setRow(WORD row,char FAR *lpRowData);
	WORD getCol(WORD col,char FAR *lpColData);
	WORD setCol(WORD col,char FAR *lpColData);
	void setBits(BYTE byteValue);
	WORD displayBitmap(HWND hDisplayWindow,HDC hDC=(HDC)0,int isActive=FALSE,int conforming=FALSE)const;
  BOOL draw(PureDevice &pureDevice,const Rect &dstRect,const Point &srcPoint);
	bool saveBitmap(void);
	bool saveBitmap(MemFile &memFile);
	bool saveBitmap(const String &pathFileName);
	HBITMAP createBitmap(PureDevice &somePureDevice);
	WORD setPalette(HPALETTE hPalette,WORD remapBitmap=TRUE);
	HPALETTE getPalette(void)const;
	BOOL isValidBitmap(const String &pathFileName)const;
	WORD isOkay(void)const;
  void *ptrData(void);
	void upsideDown(void);
	HGLOBAL lockedImageData(void)const;
	HGLOBAL lockedBitmapInfo(void)const;
private:
	enum Mode{Read,Write,Idle};
	enum {Signature=0x4D42};
	void mapPalette(PurePalette &purePalette);
	void closeFile(void);
	void readPalette(void);
	void setPalette(void);
	void decodeImage(void);
	void getRequiredWidth(WORD &desiredWidth,WORD desiredHeight);
	void getRequiredWidth(DWORD &desiredWidth,DWORD desiredHeight);
	void copyBitmap(const Bitmap &someBitmap);
	void copyBits(UHUGE *destination,UHUGE *source,unsigned long length)const;
	void setBits(UHUGE *lpChar,unsigned char charValue,unsigned long length)const;
	DWORD imageExtent(void)const;
	WORD processBitmap(const String &pathFileName);

	String mFileName;
	WORD mMaxColors;
	Mode mCurrentMode;
	BITMAPFILEHEADER mBitmapFileHeader;
	PurePalette mBitmapPalette;
	const LONG mBlockSize;
	HFILE mhFile;
	DWORD mImageExtent;
	DWORD mWidth;
	DWORD mHeight;
};

inline
DWORD Bitmap::imageExtent(void)const
{
	BITMAPINFO *lpBitmapInfo=getInfoPtr();
	return (((((lpBitmapInfo->bmiHeader.biWidth*lpBitmapInfo->bmiHeader.biBitCount)+31)&~31)>>3)*lpBitmapInfo->bmiHeader.biHeight);
}

inline
DWORD Bitmap::getImageExtent(void)const
{
  return mImageExtent;
}

inline
WORD Bitmap::isOkay(void)const
{
	return BitmapData::isOkay();
}

inline
HGLOBAL Bitmap::lockedImageData(void)const
{
  return getDataHnd();
}

inline
HGLOBAL Bitmap::lockedBitmapInfo(void)const
{
  return getInfoHnd();
}

inline
WORD Bitmap::operator==(const Bitmap &someBitmap)const
{
	return mFileName==someBitmap.mFileName;
}

inline
WORD Bitmap::width(void)const
{
	return (WORD)mWidth;
}

inline
WORD Bitmap::height(void)const
{
	return (WORD)mHeight;
}

inline
void Bitmap::closeFile(void)
{
	if(HFILE_ERROR!=mhFile){::_lclose(mhFile);mhFile=HFILE_ERROR;}
}

inline
void Bitmap::setBits(BYTE byteValue)
{
  setBits(getDataPtr(),byteValue,(LONG)width()*(LONG)height());
}

inline
BYTE Bitmap::getByte(WORD row,WORD col)const
{
	UHUGE *lpBitmapData;
  lpBitmapData=getDataPtr();
	if(row>=height()||col>=width())return FALSE;
	UHUGE *lpImage;
	lpImage=(lpBitmapData+((LONG)width()*(LONG)height()));
	return *((lpImage-(((LONG)row*(LONG)width())+(LONG)width()))+(LONG)col);
}

inline
void Bitmap::setByte(WORD row,WORD col,BYTE byteValue)
{
	UHUGE *lpBitmapData;
  lpBitmapData=getDataPtr();
	if(row>=height()||col>=width())return;
	UHUGE *lpImage;
	lpImage=(lpBitmapData+((LONG)width()*(LONG)height()));
	*((lpImage-(((LONG)row*(LONG)width())+(LONG)width()))+(LONG)col)=byteValue;
}

inline
WORD Bitmap::planes(void)const
{
	if(!isOkay())return FALSE;
	return getInfoPtr()->bmiHeader.biPlanes;
}

inline
WORD Bitmap::bitCount(void)const
{
	if(!isOkay())return FALSE;
  return getInfoPtr()->bmiHeader.biBitCount;
}

inline
void *Bitmap::ptrData(void)
{
  return getDataPtr();
}
#endif

