/*
 * 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 "PlatformProducer.hpp"
#include "Base/Logger.hpp"
#include <stdexcept>
#include <map>

namespace OpenVulkano
{
	namespace
	{
		struct PlatformRegistry
		{
			static PlatformRegistry& GetInstance()
			{
				static PlatformRegistry instance;
				return instance;
			}

			std::map<RenderAPI, std::function<IPlatform*()>> platformMap;
			std::map<RenderAPI, std::function<IRenderer*()>> rendererMap;

			void RegisterPlatform(RenderAPI renderApi, std::function<IPlatform*()> createMethod)
			{
				platformMap[renderApi] = createMethod;
			}

			void RegisterRenderer(RenderAPI renderApi, std::function<IRenderer*()> createMethod)
			{
				rendererMap[renderApi] = createMethod;
			}
		};
	}

	void PlatformProducer::RegisterPlatformProducer(RenderAPI renderApi, std::function<IPlatform*()> createMethod)
	{
		PlatformRegistry::GetInstance().RegisterPlatform(renderApi, createMethod);
	}

	void PlatformProducer::RegisterRendererProducer(RenderAPI renderApi, std::function<IRenderer*()> createMethod)
	{
		PlatformRegistry::GetInstance().RegisterRenderer(renderApi, createMethod);
	}

	IRenderer* PlatformProducer::CreateRenderManager(RenderAPI renderApi)
	{
		auto& rMap = PlatformRegistry::GetInstance().rendererMap;
		auto renderProducer = rMap.find(renderApi);
		if (renderProducer == rMap.end())
		{
			Logger::RENDER->error("Unsupported render api requested! Requested {}", renderApi.ToString());
			throw std::runtime_error("Unsupported render api requested!");
		}
		return renderProducer->second();
	}

	IPlatform* PlatformProducer::CreatePlatform(RenderAPI renderApi)
	{
		auto& pMap = PlatformRegistry::GetInstance().platformMap;
		auto platformProducer = pMap.find(renderApi);
		if (platformProducer == pMap.end())
		{
			Logger::MANAGER->error("No platform for render api {}!", renderApi.ToString());
			return nullptr;
		}
		return platformProducer->second();
	}
}
