/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */

#include "SkirmishAILibraryInfo.h"

#include "Interface/aidefines.h"
#include "Interface/SSkirmishAILibrary.h"
#include "SkirmishAIKey.h"
#include "System/Util.h"
#include "System/Info.h"
#include "System/Option.h"
#include "System/Log/ILog.h"

#include "System/FileSystem/VFSModes.h"


static const char* BAD_CHARS = "\t _#";
static const std::string DEFAULT_VALUE = "";

CSkirmishAILibraryInfo::CSkirmishAILibraryInfo(
		const CSkirmishAILibraryInfo& aiInfo)
	: info_keys(aiInfo.info_keys)
	, info_keyLower_key(aiInfo.info_keyLower_key)
	, info_key_value(aiInfo.info_key_value)
	, info_key_description(aiInfo.info_key_description)
	, options(aiInfo.options)
{
}

CSkirmishAILibraryInfo::CSkirmishAILibraryInfo(
		const std::string& aiInfoFile,
		const std::string& aiOptionFile)
{
	std::vector<InfoItem> tmpInfo;
	info_parseInfo(tmpInfo, aiInfoFile);
	std::vector<InfoItem>::iterator ii;
	for (ii = tmpInfo.begin(); ii != tmpInfo.end(); ++ii) {
		// TODO remove this, once we support non-string value types for Skirmish AI info
		info_convertToStringValue(&(*ii));
		SetInfo(ii->key, ii->valueTypeString, ii->desc);
	}

	if (!aiOptionFile.empty()) {
		option_parseOptions(options, aiOptionFile);
	}
}

CSkirmishAILibraryInfo::CSkirmishAILibraryInfo(
		const std::map<std::string, std::string>& aiInfo,
		const std::string& aiOptionLua)
{
	std::map<std::string, std::string>::const_iterator ii;
	for (ii = aiInfo.begin(); ii != aiInfo.end(); ++ii) {
		SetInfo(ii->first, ii->second);
	}

	if (!aiOptionLua.empty()) {
		option_parseOptionsLuaString(options, aiOptionLua);
	}
}

CSkirmishAILibraryInfo::~CSkirmishAILibraryInfo() {}


size_t CSkirmishAILibraryInfo::size() const {
	return info_keys.size();
}
const std::string& CSkirmishAILibraryInfo::GetKeyAt(size_t index) const {

	if (index < info_keys.size()) {
		return *(info_keys.begin() + index);
	} else {
		return DEFAULT_VALUE;
	}
}
const std::string& CSkirmishAILibraryInfo::GetValueAt(size_t index) const {

	if (index < info_keys.size()) {
		return info_key_value.find(GetKeyAt(index))->second;
	} else {
		return DEFAULT_VALUE;
	}
}
const std::string& CSkirmishAILibraryInfo::GetDescriptionAt(size_t index) const {

	if (index < info_keys.size()) {
		return info_key_description.find(GetKeyAt(index))->second;
	} else {
		return DEFAULT_VALUE;
	}
}

SkirmishAIKey CSkirmishAILibraryInfo::GetKey() const {

	const std::string& sn = GetShortName();
	const std::string& v = GetVersion();
	SkirmishAIKey key = SkirmishAIKey(sn, v);

	return key;
}

const std::string& CSkirmishAILibraryInfo::GetDataDir() const {
	return GetInfo(SKIRMISH_AI_PROPERTY_DATA_DIR);
}
const std::string& CSkirmishAILibraryInfo::GetDataDirCommon() const {
	return GetInfo(SKIRMISH_AI_PROPERTY_DATA_DIR_COMMON);
}
const std::string& CSkirmishAILibraryInfo::GetShortName() const {
	return GetInfo(SKIRMISH_AI_PROPERTY_SHORT_NAME);
}
const std::string& CSkirmishAILibraryInfo::GetVersion() const {
	return GetInfo(SKIRMISH_AI_PROPERTY_VERSION);
}
const std::string& CSkirmishAILibraryInfo::GetName() const {
	return GetInfo(SKIRMISH_AI_PROPERTY_NAME);
}
const std::string& CSkirmishAILibraryInfo::GetDescription() const {
	return GetInfo(SKIRMISH_AI_PROPERTY_DESCRIPTION);
}
const std::string& CSkirmishAILibraryInfo::GetURL() const {
	return GetInfo(SKIRMISH_AI_PROPERTY_URL);
}
bool CSkirmishAILibraryInfo::IsLuaAI() const {

	bool isLua = false;

	const std::string& isLuaStr = GetInfo("isLuaAI");
	if (isLuaStr != DEFAULT_VALUE) {
		isLua = StringToBool(isLuaStr);
	}

	return isLua;
}
const std::string& CSkirmishAILibraryInfo::GetInterfaceShortName() const {
	return GetInfo(SKIRMISH_AI_PROPERTY_INTERFACE_SHORT_NAME);
}
const std::string& CSkirmishAILibraryInfo::GetInterfaceVersion() const {
	return GetInfo(SKIRMISH_AI_PROPERTY_INTERFACE_VERSION);
}
const std::string& CSkirmishAILibraryInfo::GetInfo(const std::string& key) const {

	std::map<std::string, std::string>::const_iterator strPair;

	// get real key through lower case key
	strPair = info_keyLower_key.find(StringToLower(key));
	bool found = (strPair != info_keyLower_key.end());

	// get value
	if (found) {
		strPair = info_key_value.find(strPair->second);
		found = (strPair != info_key_value.end());
	}

	if (!found) {
		LOG_L(L_WARNING, "Skirmish AI property '%s' could not be found.",
				key.c_str());
		return DEFAULT_VALUE;
	} else {
		return strPair->second;
	}
}


void CSkirmishAILibraryInfo::SetDataDir(const std::string& dataDir) {
	SetInfo(SKIRMISH_AI_PROPERTY_DATA_DIR, dataDir);
}
void CSkirmishAILibraryInfo::SetDataDirCommon(const std::string& dataDirCommon) {
	SetInfo(SKIRMISH_AI_PROPERTY_DATA_DIR_COMMON, dataDirCommon);
}
void CSkirmishAILibraryInfo::SetShortName(const std::string& shortName) {
	SetInfo(SKIRMISH_AI_PROPERTY_SHORT_NAME, shortName);
}
void CSkirmishAILibraryInfo::SetVersion(const std::string& version) {
	SetInfo(SKIRMISH_AI_PROPERTY_VERSION, version);
}
void CSkirmishAILibraryInfo::SetName(const std::string& name) {
	SetInfo(SKIRMISH_AI_PROPERTY_NAME, name);
}
void CSkirmishAILibraryInfo::SetDescription(const std::string& description) {
	SetInfo(SKIRMISH_AI_PROPERTY_DESCRIPTION, description);
}
void CSkirmishAILibraryInfo::SetURL(const std::string& url) {
	SetInfo(SKIRMISH_AI_PROPERTY_URL, url);
}
void CSkirmishAILibraryInfo::SetLuaAI(const std::string& isLua) {
	SetInfo("isLuaAI", isLua);
}
void CSkirmishAILibraryInfo::SetLuaAI(const bool isLua) {
	SetLuaAI(std::string(isLua ? "yes" : "no"));
}
void CSkirmishAILibraryInfo::SetInterfaceShortName(
		const std::string& interfaceShortName) {
	SetInfo(SKIRMISH_AI_PROPERTY_INTERFACE_SHORT_NAME, interfaceShortName);
}
void CSkirmishAILibraryInfo::SetInterfaceVersion(
		const std::string& interfaceVersion) {
	SetInfo(SKIRMISH_AI_PROPERTY_INTERFACE_VERSION, interfaceVersion);
}
bool CSkirmishAILibraryInfo::SetInfo(const std::string& key,
		const std::string& value, const std::string& description) {

	static const std::string snKey = StringToLower(SKIRMISH_AI_PROPERTY_SHORT_NAME);
	static const std::string vKey = StringToLower(SKIRMISH_AI_PROPERTY_VERSION);

	std::string keyLower = StringToLower(key);
	if (keyLower == snKey || keyLower == vKey) {
		if (value.find_first_of(BAD_CHARS) != std::string::npos) {
		LOG_L(L_WARNING, "Skirmish AI property (%s or %s)\n"
				"contains illegal characters (%s).",
				SKIRMISH_AI_PROPERTY_SHORT_NAME, SKIRMISH_AI_PROPERTY_VERSION,
				BAD_CHARS);
			return false;
		}
	}

	// only add the key if it is not yet present
	if (info_key_value.find(key) == info_key_value.end()) {
		info_keys.push_back(key);
	}
	info_keyLower_key[keyLower] = key;
	info_key_value[key] = value;
	info_key_description[key] = description;

	return true;
}


const std::vector<Option>& CSkirmishAILibraryInfo::GetOptions() const {
	return options;
}
