#include "Load.h"
#include "Item.h"
#include "Townsfolk.h"
#include "Animation.h"
#include "Artisan.h"
#include "Buildings.h"
#include "Wildling.h"
#include "Tile.h"
#include <string>
#include <Resource/File.h>
#include <Engine/OS.h>
#include "Object.h"
#include "Constants.h"
#include "Map.h"
#include "../Instantiation.h"


namespace assets {
	std::vector<gge::resource::File*> loadedFiles;
	gge::resource::File *mapFile=NULL;
	assets::Map *mapProvider=NULL;

	template<class T_, class R_>
	void loadResource(gge::utils::SortedCollection<gge::resource::Base>::Iterator it, T_&(*fn)(R_&)) {
		for(;it.IsValid();it.Next()) {
			T_ &t=fn(dynamic_cast<R_&>(*it));
			T_::list[t.ID]=&t;
		}
	}

	template<class T_>
	void loadDataArrays(gge::utils::SortedCollection<gge::resource::Base>::Iterator it, T_&(*fn)(gge::resource::DataArray&)) {
		loadResource<T_, gge::resource::DataArray>(it, fn);
	}

	template<class T_>
	void loadFolders(gge::utils::SortedCollection<gge::resource::Base>::Iterator it, T_&(*fn)(gge::resource::Folder&)) {
		loadResource<T_, gge::resource::Folder>(it, fn);
	}

	void loadFile(gge::resource::File &file) {
		//this is the file identifier
		std::string id=file.Root().Get<gge::resource::Folder>(0).Get<gge::resource::DataArray>(0).getString(0);

		if(id=="trinlibr:consts") {
			assets::constants::general::load(file.Root().Get<gge::resource::DataArray>(1));
			assets::constants::stats::load(file.Root().Get<gge::resource::DataArray>(2));
			assets::constants::crafting::load(file.Root().Get<gge::resource::DataArray>(3));
			assets::constants::gold::load(file.Root().Get<gge::resource::DataArray>(4));
			assets::constants::happiness::load(file.Root().Get<gge::resource::DataArray>(5));
			assets::constants::combat::load(file.Root().Get<gge::resource::DataArray>(6));
			assets::constants::human::load(file.Root().Get<gge::resource::DataArray>(7));
			assets::constants::leveling::load(file.Root().Get<gge::resource::DataArray>(8));
		}
		else if(id=="trinlibr:anims") {
			loadFolders(file.Root().Subitems.First()+2, &AnimationProvider::loadNew);
		}
		else if(id=="trinlibr:artisan") {
			loadDataArrays(file.Root().Subitems.First()+1, &Artisan::loadNew);
		}
		else if(id=="trinlibr:townbld") {
			loadDataArrays(file.Root().Subitems.First()+1, &TownBuilding::loadNew);
		}
		else if(id=="trinlibr:milbld") {
			loadDataArrays(file.Root().Subitems.First()+1, &MilitaryBuilding::loadNew);
		}
		else if(id=="trinlibr:obstacle") {
			loadDataArrays(file.Root().Subitems.First()+1, &Obstacle::loadNew);
		}
		else if(id=="trinlibr:den") {
			loadFolders(file.Root().Subitems.First()+1, &Den::loadNew);
		}
		else if(id=="trinlibr:townsfolk") {
			loadDataArrays(file.Root().Subitems.First()+1, &Townfolks::loadNew);
		}
		else if(id=="trinlibr:item") {
			loadDataArrays(file.Root().Subitems.First()+1, &Item::loadNew);
		}
		else if(id=="trinlibr:tiles") {
			loadFolders(file.Root().Subitems.First()+1, &TileInfo::loadNew);
		}
		else if(id=="trinlibr:wildling") {
			loadDataArrays(file.Root().Subitems.First()+1, &Wildling::loadNew);
		}
	}

	void loadRecursive(const std::string &path) {
		gge::os::filesystem::DirectoryIterator dir(path);
		for(;dir.IsValid();dir.Next()) {
			if(*dir=="." || *dir=="..") continue;
			if(gge::os::filesystem::IsDirectoryExists(dir)) {
				loadRecursive(path+"/"+*dir);
			}
			else if(dir->substr(dir->length()-4)==".gor") {
				gge::resource::File &file=*new gge::resource::File;
				file.AddGameLoaders();
				file.LoadFile(path+"/"+*dir);
				file.Prepare();
				loadFile(file);
				loadedFiles.push_back(&file);
			}
		}
	}

	void loadAll(const std::string &path)
	{
		loadRecursive(path);
	}

	template<class T_>
	void resolvefor() {
		for(auto it=T_::list.begin();it!=T_::list.end();++it) {
			it->second->animation=NULL;
			if(it->second->ID!="") {
				for(auto it2=AnimationProvider::list.begin();it2!=AnimationProvider::list.end();++it2) {
					if(it->second->ID==it2->second->ID)
						it->second->animation=it2->second;
				}

			}
		}
	}

	void resolve() {
		resolvefor<Obstacle>();
		resolvefor<TownBuilding>();
		resolvefor<MilitaryBuilding>();
		resolvefor<Den>();
		resolvefor<Wildling>();
		resolvefor<Item>();

		assets::AnimationProvider::RecolorAll();
	}

	void loadMap(const std::string &path) {
		loadAll(path);

		//gge::utils::CheckAndDelete(mapFile); //!serious issue
		mapFile=new gge::resource::File;
		mapFile->AddGameLoaders();
		mapFile->LoadFile(path+"/map.gor");
		mapFile->Prepare();

		gge::utils::CheckAndDelete(mapProvider);
		mapProvider=new assets::Map;
		mapProvider->load(mapFile->Root());
		createMap(*mapProvider);
	}

}
