// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#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);

	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;
}

}  // namespace sw
