/////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include "CINIStrTable.h"

/////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool CINIStrTable::LoadLine(FILE *fp, char *szInputString, int iMaxLength)
{
	int iCharsRead = false;
	if(!fp)return false;
	memset(szInputString, false, iMaxLength);
	
	while(iCharsRead < iMaxLength)
	{
		szInputString[iCharsRead] = fgetc(fp);
		if(feof(fp))
		{
			szInputString[iCharsRead] = false;
			return false;
		}
		if(szInputString[iCharsRead] == '\r')szInputString[iCharsRead] = false;
		if(szInputString[iCharsRead] == '\n')
		{
			szInputString[iCharsRead] = false;
			break;
		}
		iCharsRead++;
	}
	szInputString[iCharsRead] = false;
	return true;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool CINIStrTable::ProcessLine(char *szInputString, int iLine)
{
	char szText[MAX_STRTABLE_STRING];
	char *szInputStringPtr = szInputString, *szEndTextPtr;
	int iIndex, iDiff, iValue = false;

	if(!strlen(szInputStringPtr))
	{
		return false;
	}

	// Must have a 'name = value' expression
	if(!strchr(szInputStringPtr, '='))
	{
		return false;
	}

	// Skip any prefixed spaces
	while(*szInputStringPtr == ' ')szInputStringPtr++;

	// Check if it's a commented out line
	if(*szInputStringPtr == ';')return false;
	if(*szInputStringPtr == '\'')return false;
	if(szInputStringPtr[0] == '/' && szInputStringPtr[1] == '/')return false;
	if(szInputStringPtr[0] == '\\' && szInputStringPtr[1] == '\\')return false;

	// Read in the name
	szEndTextPtr = strchr(szInputStringPtr, '=');
	if(!szEndTextPtr)return false;
	iDiff = szEndTextPtr - szInputStringPtr;
	memcpy(szText, szInputStringPtr, iDiff);
	szText[iDiff] = false;
	szInputStringPtr += strlen(szText) + 1;

	// Remove any trailing spaces
	iIndex = strlen(szText) - 1;
	while(iIndex && szText[iIndex] == ' '){szText[iIndex] = false; iIndex--;}

	// Is there anything else left?
	if(!strlen(szText))return false;

	SetEntryColumn(iLine, "Name", szText);

	while(true)
	{
		// Skip any prefixed spaces
		while(*szInputStringPtr == ' ')szInputStringPtr++;
		if(*szInputStringPtr == false)return true;

		// Read in the name
		szEndTextPtr = strchr(szInputStringPtr, ';');
		if(!szEndTextPtr)szEndTextPtr = strchr(szInputStringPtr, '\0');
		if(!szEndTextPtr)return true;
		iDiff = szEndTextPtr - szInputStringPtr;
		memcpy(szText, szInputStringPtr, iDiff);
		szText[iDiff] = false;
		szInputStringPtr += strlen(szText) + 1;

		// Remove any trailing spaces
		iIndex = strlen(szText) - 1;
		while(iIndex && szText[iIndex] == ' '){szText[iIndex] = false; iIndex--;}

		SetEntryColumn(iLine, ++iValue, szText);
	}

	return false;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool CINIStrTable::SaveToFile(char *szFilename)
{
	int iValue = false, iNumColumns;
	char *Value;

	if(!strlen(szFilename))
	{
		return false;
	}

	FILE *fp = fopen(szFilename, "wb");

	if(!fp)
	{
		return false;
	}

	for(int iEntry = 0; iEntry < iNumEntries; iEntry++)
	{
		fprintf(fp, "%s=", GetEntryColumn(iEntry, "Name"));
		iValue = false;
		iNumColumns = iGetNumEntryColumns(iEntry) - 1;

		for(int iColumn = 0; iColumn < iNumColumns; iColumn++)
		{
			Value = GetEntryColumn(iEntry, ++iValue);
			if(Value)
			{
				fprintf(fp, "%s", Value);
				if(iColumn < iNumColumns - 1)
					{
						fputc(';', fp);
					}
			}
		}

		fprintf(fp, "%s", "\r\n");
	}

	fclose(fp);

	return false;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool CINIStrTable::LoadFromFile(char *szFilename)
{
	char szLine[MAX_STRTABLE_STRING];
	int iLine = false;

	ClearColumns();
	ClearEntries();

	if(!SetColumn(0, "Name"))return false;
	if(!SetColumn(1, "Value"))return false;

	if(!strlen(szFilename))
	{
		return false;
	}

	FILE *fp = fopen(szFilename, "rb");

	if(!fp)
	{
		return false;
	}

	while(LoadLine(fp, szLine, sizeof(szLine)))
	{
		if(ProcessLine(szLine, iLine))iLine++;
	}

	ProcessLine(szLine, iLine);

	fclose(fp);

	return false;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool CINIStrTable::CreateNew(void)
{
	ClearColumns();
	ClearEntries();

	if(!SetColumn(0, "Name"))return false;
	if(!SetColumn(1, "Value"))return false;

	return true;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////