// SwiftShader Software Renderer
//
// Copyright(c) 2005-2012 TransGaming Inc.
//
// All rights reserved. No part of this software may be copied, distributed, transmitted,
// transcribed, stored in a retrieval system, translated into any human or computer
// language by any means, or disclosed to third parties without the explicit written
// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
// or implied, including but not limited to any patent rights, are granted to you.
//

#include "Configurator.hpp"

#include <iostream>
#include <fstream>

using namespace std;

#include <stdio.h>
#include <stdarg.h>
#include <ctype.h>

#if defined(__unix__)
#include <unistd.h>
#endif

namespace sw
{
	Configurator::Configurator(string iniPath)
	{
		path = iniPath;

		readFile();
	}

	Configurator::~Configurator()
	{
	}

	bool Configurator::readFile()
	{
		#if defined(__unix__)
			if(access(path.c_str(), R_OK) != 0)
			{
				return false;
			}
		#endif

		fstream file(path.c_str(), ios::in);
		if(file.fail()) return false;

		string line;
		string keyName;

		while(getline(file, line))
		{
			if(line.length())
			{
				if(line[line.length() - 1] == '\r')
				{
					line = line.substr(0, line.length() - 1);
				}

				if(!isprint(line[0]))
				{
					printf("Failing on char %d\n", line[0]);
					file.close();
					return false;
				}

				string::size_type pLeft = line.find_first_of(";#[=");

				if(pLeft != string::npos)
				{
					switch(line[pLeft])
					{
					case '[':
						{
							string::size_type pRight = line.find_last_of("]");

							if(pRight != string::npos && pRight > pLeft)
							{
								keyName = line.substr(pLeft + 1, pRight - pLeft - 1);
								addKeyName(keyName);
							}
						}
						break;
					case '=':
						{
							string valueName = line.substr(0, pLeft);
							string value = line.substr(pLeft + 1);
							addValue(keyName, valueName, value);
						}
						break;
					case ';':
					case '#':
						// Ignore comments
						break;
					}
				}
			}
		}

		file.close();

		if(names.size())
		{
			return true;
		}

		return false;
	}

	void Configurator::writeFile(std::string title)
	{
		#if defined(__unix__)
			if(access(path.c_str(), W_OK) != 0)
			{
				return;
			}
		#endif

		fstream file(path.c_str(), ios::out);
		if(file.fail()) return;

		file << "; " << title << endl << endl;

		for(unsigned int keyID = 0; keyID < sections.size(); keyID++)
		{
			file << "[" << names[keyID] << "]" << endl;

			for(unsigned int valueID = 0; valueID < sections[keyID].names.size(); valueID++)
			{
				file << sections[keyID].names[valueID] << "=" << sections[keyID].values[valueID] << endl;
			}

			file << endl;
		}

		file.close();
	}

	int Configurator::findKey(string keyName) const
	{
		for(unsigned int keyID = 0; keyID < names.size(); keyID++)
		{
			if(names[keyID] == keyName)
			{
				return keyID;
			}
		}

		return -1;
	}

	int Configurator::findValue(unsigned int keyID, string valueName) const
	{
		if(!sections.size() || keyID >= sections.size())
		{
			return -1;
		}

		for(unsigned int valueID = 0; valueID < sections[keyID].names.size(); ++valueID)
		{
			if(sections[keyID].names[valueID] == valueName)
			{
				return valueID;
			}
		}

		return -1;
	}

	unsigned int Configurator::addKeyName(string keyName)
	{
		names.resize(names.size() + 1, keyName);
		sections.resize(sections.size() + 1);
		return (unsigned int)names.size() - 1;
	}

	void Configurator::addValue(string const keyName, string const valueName, string const value)
	{
		int keyID = findKey(keyName);
		bool create = true;

		if(keyID == -1)
		{
			keyID = addKeyName(keyName);
		}

		int valueID = findValue(keyID, valueName);
		
		if(valueID == -1)
		{
			sections[keyID].names.resize(sections[keyID].names.size() + 1, valueName);
			sections[keyID].values.resize(sections[keyID].values.size() + 1, value);
		}
		else
		{
			sections[keyID].values[valueID] = value;
		}
	}

	string Configurator::getValue(string keyName, string valueName, string defaultValue) const
	{
		int keyID = findKey(keyName);
		if(keyID == -1) return defaultValue;
		int valueID = findValue((unsigned int)keyID, valueName);
		if(valueID == -1) return defaultValue;

		return sections[keyID].values[valueID];
	}

	int Configurator::getInteger(string keyName, string valueName, int defaultValue) const
	{
		char svalue[256];

		sprintf(svalue, "%d", defaultValue);

		return atoi(getValue(keyName, valueName, svalue).c_str()); 
	}

	bool Configurator::getBoolean(string keyName, string valueName, bool defaultValue) const
	{
		return getInteger(keyName, valueName, (int)defaultValue) != 0;
	}

	double Configurator::getFloat(string keyName, string valueName, double defaultValue) const
	{
		char svalue[256];

		sprintf(svalue, "%f", defaultValue);

		return atof(getValue(keyName, valueName, svalue).c_str()); 
	}

	unsigned int Configurator::getFormatted(string keyName, string valueName, char *format,
											void *v1, void *v2, void *v3, void *v4,
											void *v5, void *v6, void *v7, void *v8,
											void *v9, void *v10, void *v11, void *v12,
											void *v13, void *v14, void *v15, void *v16)
	{
		string value = getValue(keyName, valueName);

		if(!value.length()) return false;

		unsigned int nVals = sscanf(value.c_str(), format,
									v1, v2, v3, v4, v5, v6, v7, v8,
									v9, v10, v11, v12, v13, v14, v15, v16);

		return nVals;
	}
}
