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

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

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

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

namespace
{
	#define LIGHT_NAME_SIZE 40
	#define FIXTURE_NAME_SIZE 40

	// Only point lights
	struct LightInstance
	{
		char szName[LIGHT_NAME_SIZE];
		float fTotalFlux;
		NMVector3f v3Intensity;
		//float fGlaraSize;
		//bool bHeat			: 1;
		//bool bMass			: 1;
		//bool bCastShadows	: 1;
		//bool bSpotLight
		//bool bGlare			: 1;
	};

	struct FixtureInstance
	{
		char szName[FIXTURE_NAME_SIZE];
		NSize_t uLightIndex;
		NMVector3f v3Position;
		//bool bSwitch : 1;
		//bool bGeLight : 1;
	};

	const NIne::NUint32 DATA_VECTOR_REALLOC_SIZE = 4;
}

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

	NIne::NDataVector<LightInstance> aLights;
	NIne::NDataVector<FixtureInstance> aFixtures;

	aLights.Create(DATA_VECTOR_REALLOC_SIZE, DATA_VECTOR_REALLOC_SIZE);
	aFixtures.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_LIGHT_BODY,
		E_FIXTURE_BODY
	};
	
	NUint32 uState = E_HEAD;
	char buffer[2048] = { 0 };
	LightInstance light;
	FixtureInstance fixture;

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

		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)
		{
			char* pName = 0;

			if(strstr(buffer, "Light") != null)
			{
				if(sscanf(buffer, "%s %s", buffer, light.szName) < 2)
				{
					goto InvalidFile;
				}
				
				pName = light.szName;
				uState = E_LIGHT_BODY;
			}
			else if(strstr(buffer, "Fixture") != null)
			{
				if(sscanf(buffer, "%s %s", buffer, fixture.szName) < 2)
				{
					goto InvalidFile;
				}

				pName = fixture.szName;
				uState = E_FIXTURE_BODY;
			}

			// Name fix
			for(NUint32 i = 0; pName != null && i < LIGHT_NAME_SIZE; ++i)
			{
				if(*(pName + i) != 0 && i > 0)
				{
					strcpy(pName, pName + i);
					break;
				}
			}
		}
		else if(uState == E_LIGHT_BODY)
		{
			if(strstr(buffer, "type") != 0)
			{ continue; }
			else if(strstr(buffer, "TotalFlux") != 0)
			{
				if(sscanf(buffer, "%s %f", buffer, &light.fTotalFlux) < 2)
				{
					goto InvalidFile;
				}
			}
			else if(strstr(buffer, "intensity") != 0)
			{
				if(sscanf(buffer, "%s %f %f %f", buffer, &light.v3Intensity.x, &light.v3Intensity.y, &light.v3Intensity.z) < 4)
				{
					goto InvalidFile;
				}
			}
			else if(strstr(buffer, "enddef") != 0)
			{
				aLights.PushElement(light);
				uState = E_HEAD;
			}
		}
		else if(uState == E_FIXTURE_BODY)
		{
			if(strstr(buffer, "GeLight") != null)
			{ continue; }
			if(strstr(buffer, "Light") != 0)
			{
				char szLightName[LIGHT_NAME_SIZE];
				if(sscanf(buffer, "%s %s", buffer, szLightName) < 2)
				{
					goto InvalidFile;
				}

				// Searching for light index
				bool bFound = false;
				for(NSize_t i = 0; !bFound && i < aLights.GetSize(); ++i)
				{
					if(strstr(aLights[i].szName, szLightName) != 0)
					{
						fixture.uLightIndex = i;
						bFound = true;
					}
				}

				if(!bFound)
				{
					goto InvalidFile;
				}
			}
			else if(strstr(buffer, "Position") != 0)
			{
				if(sscanf(buffer, "%s %f %f %f", buffer, &fixture.v3Position.x, &fixture.v3Position.y, &fixture.v3Position.z) < 4)
				{
					goto InvalidFile;
				}
			}
			else if(strstr(buffer, "enddef") != 0)
			{
				aFixtures.PushElement(fixture);
				uState = E_HEAD;
			}
		}
	}

	m_aLights.Create(aFixtures.GetSize());

	for(NSize_t i = 0; i < aFixtures.GetSize(); ++i)
	{
		m_aLights[i].v3Position = aFixtures[i].v3Position;
		m_aLights[i].v3Color = aLights[aFixtures[i].uLightIndex].v3Intensity;
		m_aLights[i].fPower = aLights[aFixtures[i].uLightIndex].fTotalFlux;
	}

	aLights.Release();
	aFixtures.Release();
	m_bLoaded = true;
	fclose(pFile);
	return false;
InvalidFile:
	aLights.Release();
	aFixtures.Release();
	NLogError("Invalid file");
	fclose(pFile);
	return true;
}
/********************************************************/
void OldLights::saveLights(const char* szFile)
{
	FILE* pFile = fopen(szFile, "w");
	if(pFile == null)
	{
		NLogHead();
		NLogMessage("Failed to open file: %s", szFile);
		return;
	}

	fprintf(pFile, "%d\n", m_aLights.GetSize());

	for(NUint32 i = 0; i < m_aLights.GetSize(); ++i)
	{
		fprintf(pFile, "%f %f %f %f %f %f %f\n", 
			m_aLights[i].v3Position.x, m_aLights[i].v3Position.y, m_aLights[i].v3Position.z,
			m_aLights[i].fPower, 
			m_aLights[i].v3Color.x, m_aLights[i].v3Color.y, m_aLights[i].v3Color.z);
	}

	fclose(pFile);
}
/********************************************************/
void OldLights::releaseLights()
{
	m_aLights.Release();
	m_bLoaded = false;
}