#include "PluginManager.h"
#include <filesystem>
#include <windows.h> 
#include <iostream> 
//#include "misc/logger.h"
#include "logging.h"
#include "nlohmann/json.hpp"

using json = nlohmann::json;

void PluginManager::Init()
{
	char const* tmp = getenv("CENOS_CONFIG");

	logging::log("Plugin Manager init()\n");
	logging::log("CENOS_CONFIG=[" + std::string(tmp) + "]\n");

	const std::string pluginDir(std::string(tmp) + "\\plugins");

	if (std::filesystem::exists(pluginDir))
	{
		//loop all subfolders in plugins folder
		for (auto& p : std::filesystem::directory_iterator(pluginDir))
		{
			std::string pluginName = p.path().filename().string();
			const std::string pluginPath(pluginDir + "\\" + pluginName + "\\" + pluginName + std::string(".dll"));

			if (std::filesystem::exists(pluginPath))
			{
				Plugin* pl = new Plugin();
				//logging::log("in plugin" + pluginName);

				//this part is not cross-platform! 
				HINSTANCE hinstLib = LoadLibraryA(pluginPath.c_str());
				if (hinstLib != NULL)
				{
					pl->info_call = (PluginInfoCall)GetProcAddress(hinstLib, "info");
					pl->setup_call = (PluginSetupCall)GetProcAddress(hinstLib, "getSetup");

					if (NULL != pl->info_call && NULL != pl->setup_call)
					{
						json plugin_info;
						pl->info_call(&plugin_info);
						pluginMap.insert(std::make_pair(plugin_info.at("name").get<std::string>(), pl));
						logging::log("Plugin Loaded Successfuly [" + pluginName + "]\n");
					}
					else
					{
						//auro !!!
					}
				}
			}
		}
	}
	else 
	{
		//no plugins Found.
		logging::log("No plugins Found.\n");

	}

}

Setup* PluginManager::GetSetup(std::string pluginName)
{
	Plugin* p = nullptr;
	auto found = pluginMap.find(pluginName);
	if (found != pluginMap.end())
	{
		p = found->second;
		return (Setup*)p->setup_call();
	}
}

bool PluginManager::HasPlugin(std::string pluginName)
{
	Plugin* p = nullptr;
	auto found = pluginMap.find(pluginName);
	if (found != pluginMap.end())
	{
		return true;
	}
	return false;
}