#include <common/file.hpp>

File::File(void)
: mpFilePointer(0)
{
}

File::File(String pathFileName,String access)
  : mpFilePointer(0)
{
  open(pathFileName,access);
}

File::File(const File &someFile)
  : mpFilePointer(0)
{
  *this=someFile;
}

File::~File()
{
  close();
}

File &File::operator=(const File &someFile)
{
  open(someFile.pathFileName(),someFile.access());
  return *this;
}

bool File::operator==(const File &someFile)
{
  return (pathFileName()==someFile.pathFileName());
}

bool File::open(String pathFileName,String access)
{
  close();
	if(pathFileName.isNull())return false;
  mpFilePointer=::fopen(pathFileName,access);
  if(!mpFilePointer)return FALSE;
  mPathFileName=pathFileName;
  mAccess=access;  
	return TRUE;
}

bool File::close(void)
{
  if(!mpFilePointer)return FALSE;
  ::fclose(mpFilePointer);
  mpFilePointer=0;
	return TRUE;
}

const String &File::pathFileName(void)const
{
  return mPathFileName;
}

const String &File::access(void)const
{
  return mAccess;
}

bool File::isOkay(void)const
{
  return (mpFilePointer?TRUE:FALSE);
}

bool File::write(const String &string)
{
  return write(string.str(),string.length());
}

bool File::write(void *pData,DWORD extent)
{
  if(!isOkay()||!pData||!extent)return FALSE;
  if(!::fwrite(pData,extent,1,mpFilePointer))return FALSE;
  return TRUE;
}

DWORD File::write(BYTE value)
{
  return write((void*)&value,sizeof(value));
}

DWORD File::write(WORD value)
{
  return write((void*)&value,sizeof(value));
}

DWORD File::write(DWORD value)
{
  return write((void*)&value,sizeof(value));
}

DWORD File::write(int value)
{
  return write((void*)&value,sizeof(value));
}

DWORD File::write(double value)
{
  return write((void*)&value,sizeof(value));
}

DWORD File::write(const void *lpBuffer,DWORD lengthData)
{
  return write((void*)lpBuffer,lengthData);
}

bool File::writeLine(const String &lineString)
{
  char crlf[2]={'\r','\n'};
  if(!isOkay()||lineString.isNull())return FALSE;
  if(!::fwrite((char*)((String&)lineString),lineString.length(),1,mpFilePointer))return FALSE;
  if(!::fwrite(crlf,sizeof(crlf),1,mpFilePointer))return FALSE;
  return TRUE;
}

bool File::flush(void)
{
  if(!isOkay())return false;
	::fflush(mpFilePointer);
	return true;
}

DWORD File::length(void)const
{
  DWORD currentPosition;
	DWORD length;

  if(!isOkay())return 0;
	currentPosition=tell();
	seek(0,SeekEnd);
	length=tell();
	seek(currentPosition,SeekSet);
	return length;
}

DWORD File::tell(void)const
{
	fpos_t pos;
  if(!isOkay())return FALSE;
	if(::fgetpos(mpFilePointer,&pos))return FALSE;
	return pos;
}

bool File::eof(void)const
{
  if(!isOkay())return FALSE;
  return feof(mpFilePointer);
}

bool File::rewind(void)
{
  if(!isOkay())return FALSE;
  ::rewind(mpFilePointer);
	return TRUE;
}

bool File::seek(long pos,SeekMethod seekMethod)const
{
  if(!isOkay())return FALSE;
  if(-1==::fseek(mpFilePointer,pos,seekMethod))return FALSE;
  return TRUE;  
}

DWORD File::read(int &value)
{
  return read((void*)&value,sizeof(int));
}

DWORD File::read(double &value)
{
  return read((void*)&value,sizeof(double));
}

DWORD File::read(void *pData,int extent)
{
  if(!isOkay()||!pData||!extent)return 0;
  return ::fread((char*)pData,1,extent,mpFilePointer);
}

DWORD File::read(BYTE &value)
{
  return read((void*)&value,sizeof(BYTE));
}

DWORD File::read(WORD &value)
{
  return read((void*)&value,sizeof(WORD));
}

DWORD File::read(DWORD &value)
{
  return read((void*)&value,sizeof(DWORD));
}

DWORD File::read(char *lpBuffer,WORD lengthData,int stopChar)
{
	BYTE tempChar;

	for(int bytesRead=0;bytesRead<lengthData-1;bytesRead++)
	{
		if(!read(tempChar))return FALSE;
		if(tempChar==stopChar)break;
		*(lpBuffer++)=tempChar;
	}
  *(lpBuffer)=0;
  if(!bytesRead)return FALSE;
	return TRUE;
}

DWORD File::readLine(String &lineString)
{
  int granularity(1024);
	int blockLength(granularity);
	BYTE charByte;
	BYTE *ptrLine;
	WORD bytesRead(0);

	lineString.reserve(blockLength);
	ptrLine=(BYTE*)(char*)lineString;
	while(TRUE)
	{
	  if(!read(charByte))break;
		if(bytesRead>=blockLength-1)
		{
		  *ptrLine=0;
			String tmpString(lineString);
			int nextIndex(ptrLine-(BYTE*)(char*)lineString);
			lineString.reserve(blockLength+granularity);
			::memcpy((char*)lineString,(char*)tmpString,blockLength);
			blockLength+=granularity;
			ptrLine=(BYTE*)(char*)lineString+nextIndex;
		}
		if(CarriageReturn==charByte)
		{
		  if(!read(charByte))break;
			if(LineFeed==charByte)
			{
			  *ptrLine=0;
				return TRUE;
			}
		}
		else if(LineFeed==charByte)
		{
		  *ptrLine=0;
			return TRUE;
		}
		else if(NullChar==charByte)
		{
		  *ptrLine++=0;
			return bytesRead;
		}
		else if(TabChar==charByte)
		{
		  *ptrLine++=' ';
			bytesRead++;
		  continue;
		}
		else 
		{
		  *ptrLine++=charByte;
			bytesRead++;
		}
	}
	return bytesRead;
}

bool File::operator+=(DWORD sizeIncrement)
{
  if(!isOkay())return false;
	return seek(sizeIncrement,SeekCur);
}

bool File::operator++(void)
{
  if(!isOkay())return false;
	return seek(1,SeekCur);
}

bool File::operator++(int postFixDummy)   // postfix works the same as prefix
{
  if(!isOkay())return false;
	return seek(1,SeekCur);
}

bool File::operator-=(DWORD sizeDecrement)
{
  if(!isOkay())return false;
	return seek(-((int)sizeDecrement),SeekCur);
}

bool File::operator--(void)
{
  if(!isOkay())return false;
	return seek(-1,SeekCur);
}

bool File::operator--(int postFixDummy)  // postfix works the same as prefix
{
  if(!isOkay())return false;
	return seek(-1,SeekCur);
}



