// StreamReaderAscii.cpp: implementation of the StreamReaderAscii class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include <string.h>
#include <stdio.h>
#include "PGLWad.h"
#include "StreamReaderAscii.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

char * StreamReaderAscii::cStringWhiteSpace	= "\"";
char * StreamReaderAscii::cWhiteSpace	= " \t\n\r,";
char * StreamReaderAscii::cCommentWhiteSpace = "\n";


StreamReaderAscii::StreamReaderAscii()
{
	m_versionNumber			= 0.0f;
	m_whiteSpace			= cWhiteSpace;
	m_versionCheckOn		= true;
}

StreamReaderAscii::~StreamReaderAscii()
{
}

bool StreamReaderAscii::getChar(char & Char)
{
	if(getToken())
	{
		Char = m_tokenBuffer[0];
		return true;
	}
	return false;
}


// attempt to get integer from stream
bool StreamReaderAscii::getInt(int & Int)
{
	if(getToken())
		if (sscanf(m_tokenBuffer,"%i",&Int))
			return true;
	return false;
}


// attempt to get integer from stream
bool StreamReaderAscii::getu32(u32 & ref)
{
	if(getToken())
		if (sscanf(m_tokenBuffer,"%ui",&ref))
			return true;
	return false;
}

//attempt to get float from stream
bool StreamReaderAscii::getFloat(float & Float)
{
	if (getToken())
		if (sscanf(m_tokenBuffer,"%f",&Float))
			return true;
	return false;
}


//attempt to get string from stream (will parse string with quotes but  will return without quotes
// NOTE:  pString is set to allocated memory.  DeAllocation responsibility is returned with string.
bool StreamReaderAscii::getString(char *& String)
{
	if (getToken())
	{
		if (m_tokenIsString)
		{
			char * charptr;
			charptr = new char[strlen(m_tokenBuffer)+1];
			strcpy(charptr, m_tokenBuffer);
			String = charptr;
			return true;
		}
	}
	return false;
}



// this function does return a pointer into the buffer of the class
// it does this for efficiency reasons
bool StreamReaderAscii::getIdentifier(char *& identifierString)
{
	identifierString = m_tokenBuffer;
	if (getToken())
		return true;
	return false;
}


bool StreamReaderAscii::getToEndOfLine(char *& Line)
{
	Line = m_tokenBuffer;
	m_whiteSpace = cCommentWhiteSpace;
	bool hitEndOfFile = false;
	char curChar;
	char * bufferPtr;
	
	bufferPtr = m_tokenBuffer;
	*bufferPtr = '\0';
	
	//check that we are not already at end of file
	if ( m_inFile->atEnd())
	{
		return true;
	}
	
	//get the character
	m_inFile->serialize ( &curChar, 1);
	if ( m_inFile->atEnd())
	{
		hitEndOfFile = true;
	}
	while ((!hitEndOfFile)&&(!isWhiteSpace (curChar))&&(bufferPtr<(m_tokenBuffer+MAXTOKENSIZE-1)))
	{
		//add character to buffer
		(*bufferPtr) = curChar;
		bufferPtr++;
		
		m_inFile->serialize ( &curChar, 1);
		if ( m_inFile->atEnd())
		{
			hitEndOfFile = true;
		}
	}
	
	//the end of the file was reached without getting whitespace
	if (hitEndOfFile && (!isWhiteSpace(curChar)))
	{
		//add that last character
		(*bufferPtr) = curChar;
		bufferPtr++;
	}

	//terminate with \0
	(*bufferPtr) = '\0';

	return true;
}

bool StreamReaderAscii::getBeginSection()
{
	if (getToken())
	{
		if ( m_tokenBuffer[0] == '{')
			return true;
	}
	return false;
}


bool StreamReaderAscii::getEndSection()
{
	if (getToken())
	{
		if ( m_tokenBuffer[0] == '}')
			return true;
	}
	return false;
}


bool StreamReaderAscii::tokenIsBeginSection()
{
	if ( m_tokenBuffer[0] == '{')
		return true;
	return false;
}


bool StreamReaderAscii::isWhiteSpace( char curChar)
{
	char * pWhiteSpace = m_whiteSpace;
	while (*pWhiteSpace != '\0')
	{
		if ((*pWhiteSpace) == curChar)
			return true;
		pWhiteSpace++;
	}
	if (curChar == '\0')
		return true;

	return false;
}


bool StreamReaderAscii::getToken()
{
	bool hitEndOfFile = false;
	//define whitespace
	m_whiteSpace = cWhiteSpace;
	m_tokenIsString = false;
	
	char curChar;
	char * bufferPtr;
	bool isComment = false;

	//read until not whitespace
	//curChar = fgetc(m_inFile);
	m_inFile->serialize ( &curChar, 1);
	if ( m_inFile->atEnd())
		hitEndOfFile = true;

	while ( (!hitEndOfFile) && (isWhiteSpace (curChar)))
	{
		//curChar = fgetc(m_inFile);
		m_inFile->serialize ( &curChar, 1);
		//if (curChar == -1)
		if ( m_inFile->atEnd())
			hitEndOfFile = true;
	}

	if (hitEndOfFile && isWhiteSpace(curChar))
	{   //premature file end
		m_tokenBuffer[0] = '\0';
		return false;
	}

	//check for string start
	if (curChar == '"')
	{
		m_whiteSpace = cStringWhiteSpace;
		//curChar = fgetc(m_inFile);
		m_inFile->serialize ( &curChar, 1);
		
		//if ( curChar == -1)
		if ( m_inFile->atEnd())
			hitEndOfFile = true;
		
		m_tokenIsString = true;
	}

	//check for comment start
	else if ( curChar == '/')
	{
		//curChar = fgetc(m_inFile);
		m_inFile->serialize ( &curChar, 1);
		//if (curChar == -1)
		if ( m_inFile->atEnd())
			hitEndOfFile = true;
		if (curChar == '/')
		{
			isComment = true;
			m_whiteSpace = cCommentWhiteSpace;
		}
	}

	if (hitEndOfFile)
	{	
		if ( !isWhiteSpace(curChar))
		{
			m_tokenBuffer[0] = curChar;
			m_tokenBuffer[1] = '\0';
			return true;
		}
		m_tokenBuffer[0] = '\0';
		return false;
	}

	bufferPtr = m_tokenBuffer;
	
	//copy until whitespace
	while ((!hitEndOfFile)&&(!isWhiteSpace (curChar))&&(bufferPtr<(m_tokenBuffer+MAXTOKENSIZE-1)))
	{
		(*bufferPtr) = curChar;
		bufferPtr++;
		m_inFile->serialize ( &curChar, 1);
		if ( m_inFile->atEnd())
		{
			hitEndOfFile = true;
		}
	}
	
	if (hitEndOfFile && (!isWhiteSpace(curChar)))
	{
		(*bufferPtr) = curChar;
		bufferPtr++;
	}

	//terminate with \0
	(*bufferPtr) = '\0';

	
	if (isComment)
		//bypass comment and return next token
		return getToken();

	
	if ((m_versionCheckOn) && (tokenIsVersion()))
	{
		float versionNumber;
		if (getFloat(versionNumber))
		{
			if(!validateVersion(versionNumber))
			{	
				//bypass all version information
				if (!dumpVersion(versionNumber))
					return false;
			}
		}
		//get next token to return (recursive)
		return getToken();
	}
	if ((m_versionCheckOn) && tokenIsEndVersion())
	{
		//ignore ENDVERSION (all relevant ENDVERSION tokens should be properly addressed inside dump version)
		return getToken();
	}

	return true;
}


void StreamReaderAscii::setVersionNumber(float version)
{
	m_versionNumber = version;
}


bool StreamReaderAscii::dumpVersion(float version)
{
	//the version beginning tag and number are already read
	bool endVersionFound = false;
	float versionNumber;

	m_versionCheckOn = false;

	while (!endVersionFound)
	{
		if (!getToken())
			return false;
		while ((!tokenIsEndVersion()) || m_tokenIsString)
		{
			if (!getToken())
				return false;
		}


		if (getFloat(versionNumber))
			if (versionNumber == version)
				endVersionFound = true;
	}
	m_versionCheckOn = true;
	return true;
}


//returns true if token is the string "VERSION"
bool StreamReaderAscii::tokenIsVersion()
{
	if (!strcmp(m_tokenBuffer,"VERSION"))
		return true;
	return false;
}


//returns true if token is the string "VERSION"
bool StreamReaderAscii::tokenIsEndVersion()
{
	if (!strcmp(m_tokenBuffer,"ENDVERSION"))
		return true;
	return false;
}


//returns false if version number is not supported
bool StreamReaderAscii::validateVersion(float versionNumber)
{
	if (versionNumber <= m_versionNumber)
		return true;
	return false;
}


bool StreamReaderAscii::dumpSection()
{
	//dump until next section
	while (!getEndSection())
	{
		if (tokenIsBeginSection())
		{
			dumpSection();
		}
	}
	return true;
}

