/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

#include "ResourceLoader.hpp"
#include "Base/Logger.hpp"
#include <vector>

namespace OpenVulkano
{
	class AggregatingResourceLoader final : public ResourceLoader
	{
		std::vector<std::unique_ptr<ResourceLoader>> m_loaders;

	public:
		Array<char> GetResource(const std::string& resourceName) override
		{
			for(auto& loader : m_loaders)
			{
				try
				{
					auto res = loader->GetResource(resourceName);
					if (!res.Empty()) return res;
				}
				catch (const std::exception& e)
				{
					Logger::FILESYS->error("Error trying to get resource for '{}'! Error: {}", resourceName, e.what());
				}
				catch (...)
				{
					Logger::FILESYS->error("Unknown error trying to get resource for '{}'!", resourceName);
				}
			}
			return {};
		}

		void* Register(std::unique_ptr<ResourceLoader> loader)
		{
			m_loaders.push_back(std::move(loader));
			return m_loaders.back().get();
		}

		bool Unregister(void* loaderHandle)
		{
			for(auto iter = m_loaders.begin(); iter != m_loaders.end(); iter++)
			{
				if (iter->get() == loaderHandle)
				{
					m_loaders.erase(iter);
					return true;
				}
			}
			return false;
		}

		std::string GetResourcePath(const std::string& resourceName) override
		{
			try
			{
				for (auto& loader: m_loaders)
				{
					auto res = loader->GetResourcePath(resourceName);
					if (!res.empty())
					{
						return res;
					}
				}
			}
			catch (const std::exception& e)
			{
				Logger::FILESYS->error("Error trying to get resource path for '{}'! Error: {}", resourceName, e.what());
			}
			catch (...)
			{
				Logger::FILESYS->error("Unknown error trying to get resource path for '{}'!", resourceName);
			}
			return "";
		}
	};

	ResourceLoader& ResourceLoader::GetInstance()
	{
		static AggregatingResourceLoader resourceLoader;
		return resourceLoader;
	}

	void* ResourceLoader::RegisterResourceLoader(std::unique_ptr<ResourceLoader> loader)
	{
		AggregatingResourceLoader* aggregator = static_cast<AggregatingResourceLoader*>(&GetInstance());
		return aggregator->Register(std::move(loader));
	}

	bool ResourceLoader::UnregisterResourceLoader(void* loaderHandle)
	{
		AggregatingResourceLoader* aggregator = static_cast<AggregatingResourceLoader*>(&GetInstance());
		return aggregator->Unregister(loaderHandle);
	}
}