#include "utility/resourcemanager.h"
#include "utility/component.h"
#include "graphics/sprite.h"
#include "utility/script.h"
#include "graphics/shader.h"
#include "graphics/animation.h"
#include "gameplay/weapons/weapons.h"

SpriteAtlas* ResourceManager::loadSpriteAtlas(const std::string& path, float frameSize, bool isDirectional)
{
	auto iterator = sprites.find(path);
	if (iterator != sprites.end())
		return static_cast<SpriteAtlas*>(iterator->second.get());
	auto sprite = std::make_unique<SpriteAtlas>(path.c_str(), frameSize, isDirectional);
	sprites[path] = std::move(sprite);
	SpriteAtlas& l = static_cast<SpriteAtlas&>(*sprites[path].get());
	return static_cast<SpriteAtlas*>(sprites[path].get());
}

Sprite* ResourceManager::loadSpriteStatic(const std::string& path)
{
	auto iterator = sprites.find(path);
	if (iterator != sprites.end())
		return iterator->second.get();
	auto sprite = std::make_unique<SpriteStatic>(path.c_str());
	if (!sprite->loaded())
		return nullptr;
	sprites[path] = std::move(sprite);
	return sprites[path].get();
}

std::shared_ptr<AIScript> ResourceManager::loadAIScript(const std::string& path)
{
	return std::make_shared<AIScript>(path.c_str());
}

std::shared_ptr<WeaponScript> ResourceManager::loadWeaponScript(const std::string& path)
{
	return std::make_shared<WeaponScript>(path.c_str());
}

std::shared_ptr<TileSetData> ResourceManager::loadTileSet(const std::string& name)
{
	return xmlLoader->getTileSetData(name);
}

const unsigned ResourceManager::loadShader(const std::string& name, const std::string& vertexPath, const std::string& fragPath)
{
	auto iterator = shaders.find(name);
	if (iterator != shaders.end())
		return iterator->second->ID;
	auto shader = std::make_unique<Shader>(vertexPath.c_str(), fragPath.c_str());
	unsigned id = shader->ID;
	shaderIDs[shader->ID] = shader.get();
	shaders[name] = std::move(shader);
	return id;
}

Shader* ResourceManager::getShaderByID(unsigned int ID)
{
	auto iterator = shaderIDs.find(ID);
	return (iterator != shaderIDs.end() ? iterator->second : nullptr);
}

// We attach our script after we create our weapon because we are passing a reference to the weapon into the script and we don't want to pass an
// incomplete reference to our script.
std::shared_ptr<Weapon> ResourceManager::loadWeapon(const std::string& name, const unsigned weaponShaderID, const unsigned bulletShaderID)
{
	std::shared_ptr<WeaponData> data = xmlLoader->getWeaponData(name);
	auto weapon = std::make_shared<Weapon>(data, weaponShaderID, bulletShaderID, this);
	if (!data->script.empty())
		weapon->attachScript(loadWeaponScript(data->script));
	return weapon;
}

std::shared_ptr<SceneData> ResourceManager::loadScene(const std::string& id)
{
	return xmlLoader->getSceneData(id);
}

std::shared_ptr<AnimationSet> ResourceManager::loadAnimationSet(const std::string& name, int entityid)
{
	auto animSetData = xmlLoader->getAnimationSet(name);

	return std::make_shared<AnimationSet>(entityid, this, animSetData);
}

// this will need some work, but for now where there is only one weapon type we can work with it
// TODO: Allow different weapon types!
/*
template <typename T>
std::shared_ptr<T> ResourceManager::loadWeapon(const std::string& name, std::shared_ptr<Shader> shader, std::shared_ptr<SpriteComponent> spriteComponent)
{
	auto iterator = weapons.find(name);
	if (iterator != weapons.end())
		return iterator->second;
	auto weapon = std::make_shared<T>(T(shader, spriteComponent));
	weapons[name] = weapon;
	return weapon;
}
*/
void ResourceManager::clearResources()
{
	sprites.clear();
	shaders.clear();
	shaderIDs.clear();
	weapons.clear();
	tileSets.clear();
}

ResourceManager::~ResourceManager()
{
	clearResources();
	xmlLoader.reset();
}
