#include "CShadersManager.hpp"

#include "CShaderFactory.hpp"
#include "../CKernel.hpp"

#include <boost/filesystem.hpp>

CShadersManager::CShadersManager(void) :m_shadersMap(), m_shaderList(nullptr) {

}

CShadersManager::~CShadersManager(void) {
	for (std::pair<const std::string, CShader*>& it : m_shadersMap)
	{
		delete it.second;
	}
	free(m_shaderList);
}

CShader* CShadersManager::get(std::string name) const {
	std::map<std::string, CShader*>::const_iterator it = m_shadersMap.find(name);
	if (it == m_shadersMap.end()) {
		return nullptr;
	}
	else {
		return it.operator*().second;
	}
}

void CShadersManager::create(void) {
	if (std::filesystem::is_directory(CEngineConfiguration::configuration->getGlobalShadersPath())) {
		for (std::filesystem::directory_iterator itr(CEngineConfiguration::configuration->getGlobalShadersPath()); itr != std::filesystem::directory_iterator(); ++itr) {
			if (std::filesystem::is_regular_file(itr->status())) {
				DEBUG_LOG(trace, "Kernel", "ShadersManager", "Shader : " + itr->path().string() + " found.")

				CFileManager jsonfm(itr->path().string());
				std::string json = jsonfm.read();
				try {
					nlohmann::json shaderJson = nlohmann::json::parse(json);
					std::string name = shaderJson["name"];
					std::string vert = shaderJson["vert"];
					std::string frag = shaderJson["frag"];

					CShader* newShader = CShaderFactory::createShader(CKernel::m_kernel ,name, CEngineConfiguration::configuration->getGlobalShadersPath().string() + std::string("/") + vert, CEngineConfiguration::configuration->getGlobalShadersPath().string() + std::string("/") + frag);

					m_shadersMap.insert(std::pair<std::string, CShader*>(name, newShader));
				}
				catch (std::exception& e) {
					throw CJsonException(std::string("Failed to parse and retrieve data from the json file ") + itr->path().string() + ": " + e.what());
				}

				DEBUG_LOG(trace, "Kernel", "ShadersManager", "Shader : " + itr->path().string() + " successfully retrieved.")
			}
		}

		m_shaderList = (CShader**)malloc(sizeof(CShader*) * m_shadersMap.size());

		if (m_shaderList == NULL) {
			throw CRuntimeException("unable to alloc shaders list");
		}

		unsigned int i = 0;

		for (std::pair<std::string, CShader*> it : m_shadersMap)
		{
			m_shaderList[i] = it.second;
			i++;
		}

	}
	else {
		throw CFileException(std::string("Failed to find the shaders folder : ") + CKernel::m_kernel->getEngineConfig()->getGlobalShadersPath().string());
	}
}

void CShadersManager::compile(void) {
	DEBUG_LOG(trace, "Kernel", "ShadersManager", "Starting compiling shaders files.");

	unsigned int nbShader = m_shadersMap.size();

	for (unsigned int i = 0; i < nbShader; i++)
	{
		m_shaderList[i]->init();
	}

	DEBUG_LOG(trace, "Kernel", "ShadersManager", "All shaders are ready to use.")
}