/*
 * 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 "EmbeddedResourceLoaderWindows.hpp"
#include "Base/Logger.hpp"
#include "Data/Containers/String.hpp"
#include "../resources/resource.h"
#include <windows.h>
#include <iostream>

namespace OpenVulkano
{
	namespace
	{
		void* HANDLE = ResourceLoader::RegisterResourceLoader(std::make_unique<EmbeddedResourceLoaderWindows>());
	}

	std::string EmbeddedResourceLoaderWindows::GetResourcePath(const std::string& resourceName)
	{
		return "";
	}

	Array<char> EmbeddedResourceLoaderWindows::GetResource(const std::string& resourceName)
	{
		OpenVulkano::String s(resourceName);
		auto tokens = s.Split("_");
		if (tokens.empty() || tokens.size() == 1)
		{
			return {};
		}
		const std::string& resType = tokens.back();
		return GetResource(resourceName.c_str(), GetWinApiResourceType(resType));
	}

	LPSTR EmbeddedResourceLoaderWindows::GetWinApiResourceType(std::string resourceType)
	{
		std::transform(resourceType.begin(), resourceType.end(), resourceType.begin(),
		               [](char c) { return std::tolower(c); });
		if (resourceType == "icon")
		{
			return RT_GROUP_ICON;
		}
		else if (resourceType == "font")
		{
			return RT_FONT;
		}
		return RT_RCDATA;
	}

	std::string EmbeddedResourceLoaderWindows::GetResourceName(const char* resId) 
	{
		// check if resId was provided as interger or CString
		// https://stackoverflow.com/questions/3610565/why-does-makeintresource-work
		// first 64KB
		uintptr_t ptrT = reinterpret_cast<uintptr_t>(resId);
		// id that points to non-mappable memory
		if (ptrT <= 0xFFFF)
		{
			return std::to_string(static_cast<uint16_t>(0xFFFF & ptrT));
		}
		// C-string
		return std::string(resId);
	}

	Array<char> EmbeddedResourceLoaderWindows::GetResource(const char* resId, char* resourceType)
	{
		HMODULE exe = GetModuleHandleA(NULL);
		LPCSTR resourceName = resId;
		HRSRC hRes = FindResourceA(exe, resourceName, resourceType);

		if (!hRes)
		{
			Logger::DATA->debug("Could not find embedded resource {}. Error code = {}.", GetResourceName(resId),
			                  GetLastError());
			return {};
		}

		HGLOBAL hResData = LoadResource(exe, hRes);
		if (!hResData)
		{
			
			Logger::DATA->debug("Embedded resource {} found, but could not load. Error code = {}.", GetResourceName(resId),
			                  GetLastError());
			return {};
		}

		void* data = LockResource(hResData);
		DWORD size = SizeofResource(exe, hRes);
		Array<char> dst(size);
		std::memcpy(dst.Data(), data, size);
		return dst;
	}

	Array<char> EmbeddedResourceLoaderWindows::GetResource(uint16_t id, char* resourceType)
	{
		return GetResource(MAKEINTRESOURCE(id), resourceType);
	}

}