/*********************************************************************

Name:		Raytracer
Author:		Kamil Szatkowski "Netrix" (C)
Website:	http://www.netrix.org.pl/
License:	GNU GPL

*********************************************************************/
#include "Attributes.hpp"
#include "NLib/nLogger.hpp"
#include <stdio.h>
#include <string.h>
using namespace NIne;

#pragma warning(disable: 4996)	// fopen deprecated on windows

namespace
{
	const NIne::NUint32 DATA_VECTOR_REALLOC_SIZE = 4;
}

Attributes::Attributes()
: m_bLoaded(false)
{
}
/********************************************************/
bool Attributes::loadAttributes(const char* szFile)
{
	NAssert(m_bLoaded == false, "Release file first");

	m_aAttributes.Create(DATA_VECTOR_REALLOC_SIZE, DATA_VECTOR_REALLOC_SIZE);

	FILE* pFile = fopen(szFile, "r");
	if(pFile == null)
	{
		NLogHead();
		NLogMessage("Failed to open file: %s", szFile);
		return true;
	}

	// States
	enum
	{
		E_HEAD,
		E_BODY
	};
	
	NUint32 uState = E_HEAD;
	NUint32 uLine = 0;
	char buffer[2048] = { 0 };
	AttributeInstance attr;

	while(!ferror(pFile) && !feof(pFile))
	{
		fgets(buffer, sizeof(buffer), pFile);	// read line
		uLine++;

		if(0 == buffer[0] || 0xA == buffer[0] || 0xD == buffer[0])
		{ continue; }
		else if(buffer[0] == '/' && buffer[1] == '/')
		{ continue;	}
		else if(buffer[0] == ';' && buffer[1] == ';')
		{ continue;	}
		else if(uState == E_HEAD)
		{
			if(sscanf(buffer, "%s %s", buffer, attr.name) < 2 || strstr(buffer, "Attr") == null)
			{
				uState = __LINE__;
				goto InvalidFile;
			}
			// Name fix
			for(NUint32 i = 0; i < ATTRIBUTE_NAME_SIZE; ++i)
			{
				if(attr.name[i] != 0 && i > 0)
				{
					strcpy(attr.name, attr.name + i);
					break;
				}
			}

			memset(&attr, 0, sizeof(AttributeInstance));
			++uState;
		}
		else if(uState == E_BODY)
		{
			/*
			in case of error, place tolower here
			*/

			if(strstr(buffer, "kd") != 0)
			{
				if(sscanf(buffer, "%s %f", buffer, &attr.kd) < 2)
				{
					uState = __LINE__;
					goto InvalidFile;
				}
			}
			else if(strstr(buffer, "ks") != 0)
			{
				if(sscanf(buffer, "%s %f", buffer, &attr.ks) < 2)
				{
					uState = __LINE__;
					goto InvalidFile;
				}
			}
			else if(strstr(buffer, "kts") != 0)
			{
				if(sscanf(buffer, "%s %f", buffer, &attr.kts) < 2)
				{
					uState = __LINE__;
					goto InvalidFile;
				}
			}
			else if(strstr(buffer, "ktd") != 0)
			{
				if(sscanf(buffer, "%s %f", buffer, &attr.ktd) < 2)
				{
					uState = __LINE__;
					goto InvalidFile;
				}
			}
			else if(strstr(buffer, "ka") != 0)
			{
				if(sscanf(buffer, "%s %f", buffer, &attr.ka) < 2)
				{
					uState = __LINE__;
					goto InvalidFile;
				}
			}
			else if(strstr(buffer, "kf") != 0)
			{
				if(sscanf(buffer, "%s %f", buffer, &attr.kf) < 2)
				{
					uState = __LINE__;
					goto InvalidFile;
				}
				attr.kf = 1.0f - attr.kf;
			}
			else if(strstr(buffer, "gs") != 0)
			{
				if(sscanf(buffer, "%s %d", buffer, &attr.gs) < 2)
				{
					uState = __LINE__;
					goto InvalidFile;
				}
			}
			else if(strstr(buffer, "gm") != 0)
			{
				if(sscanf(buffer, "%s %d", buffer, &attr.gm) < 2)
				{
					uState = __LINE__;
					goto InvalidFile;
				}
			}
			else if(strstr(buffer, "SelfLuminance") != 0)
			{
				if(sscanf(buffer, "%s %f", buffer, &attr.selfLuminance) < 2)
				{
					uState = __LINE__;
					goto InvalidFile;
				}
			}
			else if(strstr(buffer, "SelfLumDirection") != 0)
			{
				if(strstr(buffer, "Pos") != 0)
				{
					attr.selfLumDir = true;
				}
			}
			else if(strstr(buffer, "Ft") != 0)
			{
				if(sscanf(buffer, "%s %f", buffer, &attr.ft) < 2)
				{
					uState = __LINE__;
					goto InvalidFile;
				}
			}
			else if(strstr(buffer, "OneSheet") != 0)
			{
				if(strstr(buffer, "on") != 0)
				{
					attr.oneSheet = true;
				}
			}
			else if(strstr(buffer, "eta") != 0)
			{
				if(sscanf(buffer, "%s %f", buffer, &attr.eta) < 2)
				{
					uState = __LINE__;
					goto InvalidFile;
				}
			}
			else if(strstr(buffer, "highlight") != 0)
			{ continue; }
			else if(strstr(buffer, "color") != 0)
			{
				NUint32 r, g, b;
				if(sscanf(buffer, "%s %d %d %d", buffer, &r, &g, &b) < 4)
				{
					uState = __LINE__;
					goto InvalidFile;
				}
				attr.color.x = (float)r / 255.0f;
				attr.color.y = (float)g / 255.0f;
				attr.color.z = (float)b / 255.0f;
			}
			else if(strstr(buffer, "reflection") != 0)
			{
				if(strstr(buffer, "on") != 0)
				{
					attr.reflection = true;
				}
			}
			else if(strstr(buffer, "indirect") != 0)
			{
				if(strstr(buffer, "on") != 0)
				{
					attr.indirect = true;
				}
			}
			else if(strstr(buffer, "mirror") != 0)
			{
				if(strstr(buffer, "on") != 0)
				{
					attr.mirror = true;
				}
			}
			else if(strstr(buffer, "shadowcast") != 0)
			{
				if(strstr(buffer, "on") != 0)
				{
					attr.shadowcast = true;
				}
			}
			else if(strstr(buffer, "shadowfall") != 0)
			{
				if(strstr(buffer, "on") != 0)
				{
					attr.shadowfall = true;
				}
			}
			else if(strstr(buffer, "shading") != 0)
			{
				if(strstr(buffer, "smooth") != 0)
				{
					attr.smoothShading = true;
				}
			}
			else if(strstr(buffer, "enddef") != 0)
			{
				m_aAttributes.PushElement(attr);
				uState = E_HEAD;
			}
			else
			{ continue;	}
		}
	}

	m_bLoaded = true;
	fclose(pFile);
	return false;
InvalidFile:
	NLogHead(); NLogMessage("Error occured while reading line: %u, in Attributes.cpp:%u\n", uLine, uState);
	fclose(pFile);
	return true;
}
/********************************************************/
void Attributes::releaseAttributes()
{
	m_aAttributes.Release();
	m_bLoaded = false;
}