// **********************************************************************
//                            OpenAlchemist
//                        ---------------------
//
//  File        : SkinsManager.cpp
//  Description : 
//  Author      : Guillaume Delhumeau <guillaume.delhumeau@gmail.com>
//  License     : GNU General Public License 2 or higher
//
// **********************************************************************

#include "SkinsManager.h"
#include "memory.h"
#include "misc.h"
#include <boost/filesystem.hpp>

/************************************************************************/
/* Constructor                                                          */
/************************************************************************/
SkinsManager::SkinsManager()
{
	_p_common_resources = common_resources_get_instance();
}

/************************************************************************/
/* Init                                                                 */
/************************************************************************/
void SkinsManager::init()
{
	_load_registred_skins();
	_scan_skins_path(get_skins_path());
	_scan_skins_path(get_user_skins_path());
	_sort_skins();
	_scan_elements_path(get_elements_path());
	_sort_elements();
}

/************************************************************************/
/* Terminate                                                            */
/************************************************************************/
void SkinsManager::term()
{
	_save_registred_skins();
	for(unsigned int i = 0; i < _skins.size(); ++i)
	{
		my_delete(_skins[i]);
	}
	_skins.clear();
}

void SkinsManager::reload_skin_logo()
{
	for (auto itr : _skins)
	{
		itr->load_logo(_p_common_resources->p_gc);
	}
}

/************************************************************************/
/* Set skin element                                                     */
/************************************************************************/
void SkinsManager::set_skin_elements(unsigned int element)
{
	for(unsigned int i = 0; i < _skins.size(); ++i)
	{
		if(_skins[i] -> get_filename() == _p_common_resources -> skin)
		{
			if(_skins[i] -> get_unlocked_elements() < element)
				_skins[i] -> set_unlocked_elements(element);
		}
	}
}
/************************************************************************/
/* Load registred skins                                                 */
/************************************************************************/
void SkinsManager::_load_registred_skins()
{
	// Fist we load Skin propreties saved in the conf file
	std::string path = get_save_path();
	std::string file_path = path + get_path_separator() + "skins";

	_skins.clear();
	FILE *file = fopen(file_path.c_str(), "rb");
	if (file)
	{
		while (!feof(file))
		{
			uint32_t len;
			if (1 == fread(&len, sizeof(len), 1, file))
			{
				char *s = (char *)malloc(len + 1);
				if (len == fread(s, 1, len, file))
				{
					s[len] = 0;
					unsigned char unlocked_elements;
					std::string skin_filename = s;
					if (1 == fread(&unlocked_elements, 1, 1, file))
					{
						try
						{
							Skin * p_skin = NULL;
							p_skin = my_new Skin(skin_filename, _p_common_resources->p_gc);
							p_skin->set_unlocked_elements(unlocked_elements);
							_skins.push_back(p_skin);
						}
						catch (...)
						{
							std::cout << "We don't use " << skin_filename << 
								" because it doesn't exist." << std::endl;
						}
					}
				}
				free(s);
			}
		}
		fclose(file);
	}
}

/************************************************************************/
/* Scan skins path                                                      */
/************************************************************************/
void SkinsManager::_scan_skins_path(std::string path)
{
	if (boost::filesystem::exists(path))
	{
		boost::filesystem::path p(path);
		for (boost::filesystem::directory_iterator itr(p); itr != boost::filesystem::directory_iterator(); itr++)
		{
			std::string filename = itr->path().string();
			if (strcmp(filename.c_str() + filename.length() - 4, ".zip") == 0)
			{
				bool found = false;
				for(unsigned int i = 0; i < _skins.size(); ++i)
				{
					if(_skins[i]->get_filename() == filename)
					{
						found = true;
						break;
					}
				}
				if(!found)
				{
					try
					{
						Skin * p_skin = my_new Skin(filename, _p_common_resources->p_gc);
						_skins.push_back(p_skin);
					}
					catch (...)
					{
						std::cout << "Skin " << filename << " is not valid." << std::endl;
					}
				}
			}
		}
	}
}

/************************************************************************/
/* Sort skins                                                           */
/************************************************************************/
void SkinsManager::_sort_skins()
{
	// Sorting skin list by alphabetical order (bubble sort)
	for(unsigned int i=0; i<_skins.size(); ++i)
	{
		for(unsigned int j=i+1; j<_skins.size(); ++j)
		{
			if(_skins[i]->get_filename().compare(_skins[j]->get_filename())>0)
			{
				Skin * p_sk = _skins[i];
				_skins[i] = _skins[j];
				_skins[j] = p_sk;
			}
		}
	}
}

/************************************************************************/
/* Save registred skins                                                 */
/************************************************************************/
void SkinsManager::_save_registred_skins()
{
	// Saving progression skin file
	std::string file_path = get_save_path() + get_path_separator() +
		"skins";
	FILE *file = fopen(file_path.c_str(), "wb");
	if (file)
	{
		for(unsigned int i = 0; i < _skins.size(); ++i)
		{
			uint32_t len = _skins[i]->get_filename().length();
			fwrite(&len, sizeof(len), 1, file);
			fwrite(_skins[i]->get_filename().c_str(), 1, len, file);
			unsigned char unlocked_elements = _skins[i]->get_unlocked_elements();
			fwrite(&unlocked_elements, 1, 1, file);
		}
		fclose(file);
	}
	else
	{
		std::cout << "Error while reading " << file_path <<
			"file, probably doesn't exist yet." << std::endl;
	}
}

/************************************************************************/
/* Scan elements path                                                      */
/************************************************************************/
void SkinsManager::_scan_elements_path(std::string path)
{
	if (boost::filesystem::exists(path))
	{
		boost::filesystem::path p(path);
		for (boost::filesystem::directory_iterator itr(p); itr != boost::filesystem::directory_iterator(); itr++)
		{
			std::string filename = itr->path().string();
			if (strcmp(filename.c_str() + filename.length() - 4, ".zip") == 0)
			{
				bool found = false;
				for(unsigned int i = 0; i < _skins.size(); ++i)
				{
					if(_skins[i]->get_filename() == itr->path().filename())
					{
						found = true;
						break;
					}
				}
				if(!found)
				{
					try
					{
						Element * p_element = my_new Element(filename, itr->path().filename().string(), _p_common_resources->p_gc);
						_elements.push_back(p_element);
					}
					catch (...)
					{
						std::cout << "Element " << filename << " is not valid." << std::endl;
					}
				}
			}
		}
	}
}

/************************************************************************/
/* Sort elements                                                           */
/************************************************************************/
void SkinsManager::_sort_elements()
{
	// Sorting element list by alphabetical order (bubble sort)
	for(unsigned int i=0; i<_elements.size(); ++i)
	{
		for(unsigned int j=i+1; j<_elements.size(); ++j)
		{
			if(_elements[i]->get_name().compare(_elements[j]->get_name())>0)
			{
				Element * p_el = _elements[i];
				_elements[i] = _elements[j];
				_elements[j] = p_el;
			}
		}
	}
}
