/*
 * inifile.cpp
 *
 *  Created on: 17 дек. 2014 г.
 *      Author: ivanov.i
 */

#ifdef _ATL_DLL
#include "stdafx.h"
#endif

#include <list>
#include <string>     // std::string, std::stol
#include <iostream>
#include <fstream>      // std::ifstream
#include <sstream>

#include "inifile.h"
#include "stdTools.h"
#include "ascii.h" //Зачем коментил потом раскоментил? (раскоментил потому что буква "я" не конвертируется функцией WStringToString)

//******************************************************************************
TIniFile::TIniFile()
{
	path="";
	first=NULL;
	last=NULL;
}
//------------------------------------------------------------------------------
TIniFile::~TIniFile()
{
	TIniWStruct* inistrdel;
	TIniWStruct* inistr = first;
	while (inistr!=NULL)
	{
		inistrdel=inistr;
		inistr=inistr->next;
		delete inistrdel;
	}
}
//------------------------------------------------------------------------------
bool TIniFile::Load(std::wstring path)
{
	return Load(Utility::WStringToString(path, std::locale("")));
}
//------------------------------------------------------------------------------
bool TIniFile::Load(std::string path)
{
	this->path = path;
	first = NULL;

	std::ifstream fin(path.c_str());
	if (fin.is_open())
	{
		std::string str;
		std::wstring section;
		while (std::getline(fin, str))
		{
			if (str.find('[') != std::string::npos)
			{
				section = Utility::convUTF8ToUTF16(Utility::BeforeLast(Utility::AfterFirst(str, '['), ']'));
			}
			if (str.find('=') != std::string::npos)
			{
				TIniWStruct* inistr = new TIniWStruct();
				inistr->next = NULL;
				inistr->section = section;
				inistr->ident = Utility::convUTF8ToUTF16(Utility::BeforeFirst(str, '='));
				Utility::TrimW(inistr->ident);
				inistr->value = Utility::convUTF8ToUTF16(Utility::AfterFirst(str, '='));
				Utility::TrimW(inistr->value);

				if (first == NULL)
				{
					first = inistr;
					last = inistr;
				}
				else
				{
					last->next = inistr;
					last = inistr;
				}
			}
		}
		fin.close();
	}
	else
		return false;
	return true;
}
//------------------------------------------------------------------------------
bool TIniFile::getSection(std::string Section) //Есть ли заданая секция в iti файле
{
	TIniWStruct* inistr = first;
	while (inistr!=NULL)
	{
		if (inistr->section==Utility::StringToWString(Section,std::locale("")))
		{
			return true;
		}
		inistr=inistr->next;
	}
	return false;
}
//------------------------------------------------------------------------------^M
//Получить список идентификаторов по секции^M
std::list<std::string> TIniFile::getIdents(std::string Section)
{
	std::list<std::string> list;
	TIniWStruct* inistr = first;
	while (inistr!=NULL)
	{
		if (inistr->section==Utility::StringToWString(Section,std::locale("")))
		{
			list.push_back(Utility::WStringToString(inistr->ident, std::locale("")));
		}
		inistr=inistr->next;
	}
	return list;
}
//------------------------------------------------------------------------------
std::wstring TIniFile::ReadString(std::wstring Section, std::wstring Ident, std::wstring Default)
{
	TIniWStruct* inistr = first;
	while (inistr != NULL)
	{
		if ((inistr->section == Section) && (inistr->ident == Ident))
		{
			return inistr->value;
		}
		inistr = inistr->next;
	}
	return Default;
}
//------------------------------------------------------------------------------
std::string TIniFile::ReadString(std::string Section,std::string Ident,std::string Default)
{
	TIniWStruct* inistr = first;
	while (inistr!=NULL)
	{
		if ((inistr->section==Utility::StringToWString(Section, std::locale(""))) && (inistr->ident==Utility::StringToWString(Ident, std::locale(""))))
		{
			return Utility::WStringToString(inistr->value, std::locale(""));
		}
		inistr=inistr->next;
	}
	return Default;
}
//------------------------------------------------------------------------------
long TIniFile::ReadLong(std::string Section,std::string Ident,std::string Default)
{
	long result;
	std::stringstream ss;
	ss << ReadString(Section,Ident,Default);
	ss >> result;
	return result;
}
//------------------------------------------------------------------------------
long TIniFile::ReadLong(const char* Section, const char* Ident, const char* Default)
{
	return ReadLong(std::string(Section), std::string(Ident), std::string(Default));
}
//------------------------------------------------------------------------------
unsigned int TIniFile::ReadUInt(std::string Section,std::string Ident,std::string Default)
{
	unsigned int result;
	std::stringstream ss;
	ss << ReadString(Section,Ident,Default);
	ss >> result;
	return result;
}
//------------------------------------------------------------------------------
void TIniFile::WriteUInt(std::string Section,std::string Ident,unsigned int Value)
{
	std::stringstream ss;
	ss << Value;
	WriteString(Section,Ident,ss.str());
}
//------------------------------------------------------------------------------
float TIniFile::ReadFloat(std::string Section,std::string Ident,std::string Default)
{
	float result;
	std::stringstream ss;
	ss << ReadString(Section,Ident,Default);
	ss >> result;
	return result;
}
//------------------------------------------------------------------------------
//Default: "0" или "1"
bool TIniFile::ReadBool(std::string Section,std::string Ident,std::string Default)
{
	std::string rez=ReadString(Section,Ident,Default);
	if(rez=="1") return true;
	if(rez=="0") return false;
	return false;
}
//------------------------------------------------------------------------------
void TIniFile::WriteString(std::string Section,std::string Ident,std::string Value)
{
	//ищем старое значение в заданной секции
	bool b=false;
	TIniWStruct* lastSel = NULL;
	TIniWStruct* inistr = first;
	while (inistr!=NULL)
	{
		if(inistr->section==Utility::StringToWString(Section, std::locale("")))
		{
			lastSel=inistr;
			if(inistr->ident==Utility::StringToWString(Ident, std::locale("")))
			{	inistr->value=Utility::StringToWString(Value, std::locale(""));
				b=true;
			}
		}
		inistr=inistr->next;
	}
	//если не найденно то добавляем новое значение
	if (!b)
	{
		TIniWStruct* inistr= new TIniWStruct;
		inistr->next=NULL;
		inistr->section= Utility::StringToWString(Section, std::locale(""));
		inistr->ident= Utility::StringToWString(Ident, std::locale(""));
		inistr->value= Utility::StringToWString(Value, std::locale(""));

		if (first==NULL)
		{
			first=inistr;
			last=inistr;
		}else
		{
			if(lastSel==NULL)
			{
				last->next=inistr;
				last=inistr;
			}
			else
			{
				if(last==lastSel){
					last=inistr;
				}
				inistr->next=lastSel->next;
				lastSel->next=inistr;
			}
		}
	}
}
//------------------------------------------------------------------------------
void TIniFile::WriteString(std::wstring Section, std::wstring Ident, std::wstring Value)
{
	//Пробегаемся по структуре и пытаемся заменить старое значение в секции
	bool b = false;
	TIniWStruct* lastSel = NULL;
	TIniWStruct* inistr = first;
	while (inistr != NULL)
	{
		if (inistr->section == Section)
		{
			lastSel = inistr;
			if (inistr->ident == Ident)
			{
				inistr->value = Value;
				b = true;
			}
		}
		inistr = inistr->next;
	}
	//если не найденно то добавляем новое значение
	if (!b)
	{
		TIniWStruct* inistr = new TIniWStruct;
		inistr->next = NULL;
		inistr->section = Section;
		inistr->ident = Ident;
		inistr->value = Value;

		if (first == NULL)
		{
			first = inistr;
			last = inistr;
		}
		else
		{
			if (lastSel == NULL)
			{
				last->next = inistr;
				last = inistr;
			}
			else
			{
				inistr->next = lastSel->next;
				lastSel->next = inistr;
			}
		}
	}
}
//------------------------------------------------------------------------------
bool TIniFile::Save()
{
	bool result=false;
	try
	{
		FILE *file = fopen(path.c_str(), "w");
		if(file)
		{
			std::wstring LastSection=L"";
			TIniWStruct* inistr = first;
			while (inistr!=NULL)
			{
				if (inistr->section!=LastSection)
				{
					fputs("[",file);
					fputs(Utility::convUTF16ToUTF8(inistr->section).c_str(), file);
					fputs("]\n",file);
					LastSection=inistr->section;
				}
				fputs(Utility::convUTF16ToUTF8(inistr->ident).c_str(),file);
				fputs("=",file);
				fputs(Utility::convUTF16ToUTF8(inistr->value).c_str(),file);
				fputs("\n",file);
				inistr=inistr->next;
			}
			fclose(file);
			result=true;
		}
	}catch(...)
	{}
	return result;
}
//------------------------------------------------------------------------------
void TIniFile::WriteLong(std::string Section,std::string Ident,long Value)
{
	std::stringstream ss;
	ss << Value;
	WriteString(Section,Ident,ss.str());
}
//------------------------------------------------------------------------------
void TIniFile::WriteBool(std::string Section, std::string Ident, bool Value)
{
	std::string v;
	if (Value) v = "1"; else v = "0";
	WriteString(Section, Ident, v);
}
//------------------------------------------------------------------------------
// Save binary data by converting it to Base64 beforehand.
void TIniFile::WriteBase64(std::string Section, std::string Ident, char* Value, int Size)
{

	std::string base64;
}
//------------------------------------------------------------------------------
void TIniFile::WriteFloat(std::string Section,std::string Ident,float Value)
{
	std::stringstream ss;
	ss.precision(7); //Поменял с 4 на 6 так как сохраняю широту и долготу
	ss << std::fixed << Value;
	WriteString(Section,Ident,ss.str());
}
//------------------------------------------------------------------------------
void TIniFile::WriteDouble(std::string Section,std::string Ident,double Value){
	std::stringstream ss;
	ss.precision(7); //Поменял с 4 на 6 так как сохраняю широту и долготу
	ss << std::fixed << Value;
	WriteString(Section,Ident,ss.str());
}
//------------------------------------------------------------------------------
JSON::JSON(std::wstring data)
{
	first = NULL;
	last = NULL;

	while (true)
	{
		//std::cout << data << std::endl;;

		Utility::CutBeforeWFirst(data, '"');
		std::wstring ident = Utility::CutBeforeWFirst(data, '"');
		std::wstring value;

		size_t startpos = data.find_first_not_of(L" :\t\f\n\r");
		if (startpos != std::string::npos)
		{
			//Если следующий символ это " то это строка
			if (data[startpos] == '"')
			{
				//Читаем и вырезаем строку
				size_t i;
				for (i = startpos + 1; i<data.size(); i++)
				{
					if (data[i] != '"') value += data[i];
					else if (data[i - 1] == '\\') value[value.size() - 1] = '"';
					else break;
				}
				data.erase(0, i + 1);
			}
			else
			{
				//Читаем и вырезаем циферки
				Utility::CutBeforeWFirst(data, ':');
				value = Utility::CutBeforeWFirst(data, ',');
				Utility::TrimW(value);
			}

			//std::cout << "(" <<ident << "=" << value << ")" << std::endl;;
			if (ident != L"")
			{
				TIniWStruct* inistr = new TIniWStruct;
				inistr->next = NULL;
				inistr->section = L"";
				inistr->ident = ident;
				inistr->value = value;
				if (first == NULL)
				{
					first = inistr;
					last = inistr;
				}
				else
				{
					last->next = inistr;
					last = inistr;
				}
			}

		}
		else
		{
			break;
		}
	}
}
//------------------------------------------------------------------------------
std::string JSON::ReadAString(std::wstring Ident,std::wstring Default)
{
	std::wstring str = ReadString(Ident,Default);
	//std::string rez = Utility::WStringToString(str, std::locale("")); //en_US.UTF-8 я не конвертирует поэтому использую самодельную функцию
	std::string rez = toKAZASCII(str);
	return rez;
}
//------------------------------------------------------------------------------
std::wstring JSON::ReadString(std::wstring Ident,std::wstring Default)
{
	TIniWStruct* inistr = first;
	while (inistr!=NULL)
	{
		if (inistr->ident==Ident)
		{
			return inistr->value;
		}
		inistr=inistr->next;
	}
	return Default;
}
//------------------------------------------------------------------------------
long JSON::ReadLong(std::wstring Ident,std::wstring Default)
{
	long result;
	std::wstringstream ss;
	ss << ReadString(Ident,Default);
	ss >> result;
	return result;
}
//------------------------------------------------------------------------------
char JSON::ReadChar(std::wstring Ident,std::wstring Default)
{
	return (char)ReadString(Ident,Default)[0];
}
//------------------------------------------------------------------------------
double JSON::ReadDouble(std::wstring Ident,std::wstring Default)
{
	double result;
	std::wstringstream ss;
	ss << ReadString(Ident,Default);
	ss >> result;
	return result;
}
//------------------------------------------------------------------------------
