#ifndef _COMMON_MEMFILE_HPP_
#define _COMMON_MEMFILE_HPP_
#ifndef _COMMON_WINDOWS_HPP_
#include <common/windows.hpp>
#endif
#ifndef _COMMON_STRING_HPP_
#include <common/string.hpp>
#endif
#ifndef _COMMON_TYPES_HPP_
#include <common/types.hpp>
#endif
#ifndef _COMMON_INTEL_HPP_
#include <common/intel.hpp>
#endif
#ifndef _COMMON_GLOBALDATA_HPP_
#include <common/gdata.hpp>
#endif

class MemFile
{
public:
  enum SeekFrom{SeekBeginning,SeekCurrent};
  enum ByteOrder{BigEndian,LittleEndian};
	enum {BufferLength=16384};
  MemFile(const String &pathFileName,DWORD lengthBuffer=BufferLength,ByteOrder byteOrder=LittleEndian);
	MemFile(DWORD lengthBuffer,ByteOrder byteOrder=LittleEndian);
	virtual ~MemFile();
	bool rewind(void);
	bool read(BYTE &value);
	bool read(WORD &value);
	bool read(int &value);
	bool read(DWORD &value);
	DWORD read(char *lpBuffer,DWORD lengthData);
	DWORD read(char *lpBuffer,DWORD lengthData,int stopChar);
  DWORD getLine(String &lineString);
	bool write(BYTE value);
	bool write(WORD value);
	bool write(DWORD value);
	bool write(int value);
	bool write(char *lpBuffer,DWORD lengthData);
  bool write(char *lpBuffer);
	bool flushBuffer(void);
  DWORD captureBuffer(GlobalData<BYTE> &memoryBuffer,bool clearDirty);
  DWORD tell(void)const;
	bool seek(LONG offset,SeekFrom seekFrom);
  bool open(DWORD lengthBuffer,ByteOrder byteOrder=LittleEndian);
  void close(void);
	DWORD size(void)const;
	DWORD extent(void)const;
	bool isOkay(void)const;
private:
  enum {CarriageReturn=0x0D,LineFeed=0x0A,NullChar=0x00};
	bool createBuffer(DWORD lengthBuffer);
  bool destroyBuffer(void);

	HGLOBAL mhGlobalBuffer;
	UHUGE *mlpBuffer;
	UHUGE *mlpBufferPointer;
	ByteOrder mByteOrder;
	bool mIsDirty;
	DWORD mMaxExtent;
	DWORD mBufferLength;
	String mPathFileName;
  Intel mIntelData;
};

inline
MemFile::MemFile(const String &pathFileName,DWORD lengthBuffer,ByteOrder byteOrder)
: mPathFileName(pathFileName), mlpBuffer(0), mlpBufferPointer(0), mByteOrder(byteOrder),
  mIsDirty(false), mMaxExtent(0), mBufferLength(0), mhGlobalBuffer(0)
{
  createBuffer(lengthBuffer);
}

inline
MemFile::MemFile(DWORD lengthBuffer,ByteOrder byteOrder)
: mlpBuffer(0), mlpBufferPointer(0), mByteOrder(byteOrder), mIsDirty(false),
  mMaxExtent(0), mBufferLength(0), mhGlobalBuffer(0)
{
  createBuffer(lengthBuffer);
}

inline
MemFile::~MemFile()
{
  close();
}

inline
bool MemFile::open(DWORD lengthBuffer,ByteOrder byteOrder)
{
  close();
	mByteOrder=byteOrder;
	return createBuffer(lengthBuffer);
}

inline
void MemFile::close()
{
	if(mIsDirty)flushBuffer();
  destroyBuffer();
	if(!mPathFileName.isNull())mPathFileName=String("");
}

inline
bool MemFile::isOkay(void)const
{
  return (mhGlobalBuffer?true:false);
}

inline
DWORD MemFile::tell(void)const
{
	if(!isOkay())return FALSE;
  return mlpBufferPointer-mlpBuffer;
}

inline
bool MemFile::read(BYTE &value)
{
	if(!isOkay())return false;
  if(mlpBufferPointer-mlpBuffer>=mMaxExtent)return false;
	value=*(mlpBufferPointer++);
  return true;
}

inline
bool MemFile::read(WORD &value)
{
  BYTE byteValue;

	if(!isOkay())return false;
	if(!read(byteValue))return false;
	value=byteValue;
	if(!read(byteValue))return false;
  value|=((WORD)byteValue)<<8;
	if(BigEndian==mByteOrder)value=mIntelData.intelData(value);
	return true;
}

inline
bool MemFile::read(int &value)
{
  return read((DWORD&)value);
}

inline
bool MemFile::read(DWORD &value)
{
	WORD wordValue;

	if(!isOkay())return false;
	if(!read(wordValue))return false;
	value=wordValue;
	if(!read(wordValue))return false;
	value|=((DWORD)wordValue)<<16;
	if(BigEndian==mByteOrder)value=mIntelData.intelData(value);
  return true;
}

inline
bool MemFile::write(BYTE value)
{
	if(!isOkay())return false;

  if(mMaxExtent>=mBufferLength)return false;
	*(mlpBufferPointer++)=value;
	if(mlpBufferPointer-mlpBuffer>mMaxExtent)mMaxExtent=mlpBufferPointer-mlpBuffer;
  mIsDirty=true;
	return true;
}

inline
bool MemFile::write(WORD value)
{
	BYTE byteValue;

  if(!isOkay())return false;
	if(BigEndian==mByteOrder)value=mIntelData.intelData(value);
	byteValue=(BYTE)(value&0x00FF);
	if(!write(byteValue))return false;
	byteValue=(BYTE)(value>>8);
  if(!write(byteValue))return false;
  return true;
}

inline
bool MemFile::write(int value)
{
  return write((DWORD)value);
}

inline
bool MemFile::write(char *lpBuffer)
{
  if(!lpBuffer)return false;
	return write(lpBuffer,::strlen(lpBuffer));
}

inline
DWORD MemFile::size(void)const
{
  return (mlpBufferPointer-mlpBuffer);
}

inline
DWORD MemFile::extent(void)const
{
  return mMaxExtent;
}


#endif
