/*
 * 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 "Host/SystemFontResolver.hpp"
#include "Base/Utils.hpp"
#include <Windows.h>
#include <filesystem>

#define QFR_DESCRIPTION 1

namespace OpenVulkano
{
	const std::string& SystemFontResolver::GetSystemFontPath(const std::string& fontName)
	{
		// font name -> filename
		static std::map<std::string, std::string> fontFileMapping = ReadSystemFonts();
		auto it = fontFileMapping.find(Utils::ToLower(fontName));
		return it == fontFileMapping.end() ? "" : it->second;
	}

	std::map<std::string, std::string> SystemFontResolver::ReadSystemFonts()
	{
		std::map<std::string, std::string> fontFileMapping;
		// thank you Microsoft for function that is not even documented, but exists and it's the only function that
		// can return real font name from font filename (e.g. font filename is times.ttf that corresponds to Times New Roman)
		int(WINAPI* GetFontResourceInfoW)(wchar_t*, unsigned long*, void*, unsigned long);
		*(FARPROC*) &GetFontResourceInfoW = GetProcAddress(GetModuleHandleA("gdi32"), "GetFontResourceInfoW");

		std::wstring winDir;
		winDir.resize(MAX_PATH);
		UINT len = GetWindowsDirectoryW(winDir.data(), MAX_PATH);
		winDir.resize(len);
		std::filesystem::path fontsDir = std::filesystem::path(winDir) / "Fonts";
		for (const auto& fontFilename : std::filesystem::directory_iterator(fontsDir))
		{
			unsigned long size = 0;
			std::wstring ws = fontFilename.path().wstring();
			if (!GetFontResourceInfoW(ws.data(), &size, NULL, QFR_DESCRIPTION))
			{
				continue;
			}
			std::wstring fontName;
			fontName.resize(size);
			if (GetFontResourceInfoW(ws.data(), &size, fontName.data(), QFR_DESCRIPTION))
			{
				// remove null-terminated characters since size is always bigger than needed
				std::string fontNameCropped(fontName.begin(), fontName.end());
				size_t realSize = 0;
				for (; realSize < fontNameCropped.size(); realSize++)
				{
					if (fontNameCropped[realSize] == '\0')
					{
						break;
					}
				}
				fontNameCropped.resize(realSize);
				Utils::ToLower(fontNameCropped);
				fontFileMapping[std::move(fontNameCropped)] = fontFilename.path().string();
			}
		}
		return fontFileMapping;
	}

}
