#include "stdio.h"
#include "stdlib.h"
#include "ctype.h"
#include "string.h"
#include "DynVector.h"
#include "ConfiguratorNode.h"
#include "Configurator.h"


Configurator::Configurator()
{
	m_Block = 0;
	*m_Error = 0;
}

Configurator::Configurator(const char *File)
{
	m_Block = 0;
	*m_Error = 0;
	this->Load(File);
}
Configurator::~Configurator()
{
	free((void *)m_Block);
	m_Block = 0;
}

void Configurator::Load(const char *File)
{
	FILE *fp = 0;
	
	if(fopen_s(&fp, File, "r") || !fp)
	{
		strcpy_s(m_Error, 256, "Could not open file.");
		return;
	}

	if(m_Block)
	{
		free((void *)m_Block);
	}
	m_Block = (char *)malloc(1);
	*m_Block = 0;

	char Chunk[32];
	while(fgets(Chunk, 32, fp))
	{
		register unsigned int newLen = strlen(m_Block) + strlen(Chunk) + 1;
		m_Block = (char *)realloc(m_Block, newLen);
		strcat_s(m_Block, newLen, Chunk);
	}

	fclose(fp);
}

const char *Configurator::checkError()
{
	return *m_Error == 0 ? 0 : m_Error;
}

bool Configurator::Parse(ConfiguratorNode *Global, const char *Block, int lineStart)
{
	if(!Block) Block = m_Block;
	int Comment = 0;
	int Stage = 0;
	int braceCount = 0;
	int lineNumber = lineStart;
	int blockLineNumber = 0;

	char *subBlock = (char *)malloc(1);
	*subBlock = 0;
	char subBlockTemp[32];
	int subBlockIterator = 0;

	char blockName[32];
	int blockNameIterator = 0;

	char keyData[256];
	int keyDataIterator = 0;

	for(const char *x = Block; *x; x++)
	{
		if(*x == '\n') lineNumber++;
		if(Comment == 0 && (*x == ';' || *x == '#' || (*x == '/' && *(x+1) == '/')))
		{
			Comment = 1;
			continue;
		}
		if(Comment == 1 && *x == '\n')
		{
			Comment = 0;
			continue;
		}
		if(Comment == 0 && *x == '/' && *(x+1) == '*')
		{
			Comment = 3;
			continue;
		}
		if(Comment == 3 && *x == '*' && *(x+1) == '/')
		{
			x++;
			Comment = 0;
			continue;
		}
		if(Comment > 0) continue;

		if(Stage == 0) //read untill the first non-space char
		{
			if(isspace(*x)) continue;
			
			Stage = 1;
		}
		if(Stage == 1) //Read untill the first space char or '=' or '{' is found. 
		{
			if(isspace(*x)) 
			{
				Stage = 2;
				continue;
			}

			if(*x == '=')
			{
				blockName[blockNameIterator] = 0;
				blockNameIterator = 0;
				Stage = 3;
				continue;
			}
			if(*x == '{')
			{
				blockName[blockNameIterator] = 0;
				blockNameIterator = 0;
				Stage = 4;
				continue;
			}
			blockName[blockNameIterator++] = *x;
		}
		if(Stage == 2) //read whitespace untill '=' or '{'
		{
			if(isspace(*x)) continue;

			if(*x == '=')
			{
				blockName[blockNameIterator] = 0;
				blockNameIterator = 0;
				Stage = 3;
				continue;
			}
			else if(*x == '{')
			{
				blockName[blockNameIterator] = 0;
				blockNameIterator = 0;
				blockLineNumber = lineNumber+1;
				Stage = 4;
				continue;
			}
			else
			{
				sprintf_s(m_Error, 256, "Error (Line: %d): Unexpected symbol '%c'. Expected '=' or '{'.", lineNumber, *x);
				return 0;
			}
		}
		if(Stage == 3 || Stage == 4) //Read untill the first non-whitespace character.
		{
			if(isspace(*x)) continue;

			Stage += 2;
		}
		if(Stage == 5) //Read a key untill \n
		{
			if(*x == '\n')
			{
				keyData[keyDataIterator] = 0;
				keyDataIterator = 0;
				Global->Add_Key(blockName, keyData);
				Stage = 0;
				continue;
			}	
			keyData[keyDataIterator++] = *x;
		}
		if(Stage == 6) //Read a whole block, counting { and }.
		{
			if(*x == '{')
			{
				braceCount++;
			}
			if(*x == '}')
			{
				if(braceCount == 0)
				{
					subBlockTemp[subBlockIterator] = 0;
					unsigned int newLen = strlen(subBlock) + strlen(subBlockTemp) + 1;
					subBlock = (char *)realloc((void *)subBlock, newLen);
					strcat_s(subBlock, newLen, subBlockTemp);

					Global->Add_Level(blockName);
					printf("Parsing %s starting on line %d\n", blockName, blockLineNumber);
					if(!this->Parse(Global->Next_Level(blockName), subBlock, blockLineNumber)) return 0;
					subBlockIterator = 0;
					*subBlock = 0;
					Stage = 0;
					continue;
				}
				braceCount--;
			}
			if(subBlockIterator >= 31)
			{
				subBlockTemp[subBlockIterator] = 0;
				register unsigned int newLen = strlen(subBlock) + strlen(subBlockTemp) + 1;
				subBlock = (char *)realloc((void *)subBlock, newLen);
				strcat_s(subBlock, newLen, subBlockTemp);
				subBlockIterator = 0;
			}
			subBlockTemp[subBlockIterator++] = *x;
		}
	}
	return 1;
}