#include "FontAtlasBuilder.h"

#include <wincodec.h>
#include <wrl/client.h>
#include <windows.h>

namespace RenderCadenceCompositor
{
namespace
{
struct ComThreadGuard
{
	~ComThreadGuard()
	{
		if (initialized)
			CoUninitialize();
	}

	bool Initialize()
	{
		const HRESULT result = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
		initialized = SUCCEEDED(result);
		return SUCCEEDED(result) || result == RPC_E_CHANGED_MODE;
	}

	bool initialized = false;
};
}

bool FontAtlasBuilder::LoadAtlasImage(FontAtlasBuildOutput& output, std::string& error) const
{
	ComThreadGuard comGuard;
	if (!comGuard.Initialize())
	{
		error = "Could not initialize COM for font atlas PNG loading.";
		return false;
	}

	Microsoft::WRL::ComPtr<IWICImagingFactory> factory;
	HRESULT result = CoCreateInstance(
		CLSID_WICImagingFactory,
		nullptr,
		CLSCTX_INPROC_SERVER,
		IID_PPV_ARGS(factory.GetAddressOf()));
	if (FAILED(result))
	{
		error = "Could not create WIC imaging factory for font atlas PNG loading.";
		return false;
	}

	Microsoft::WRL::ComPtr<IWICBitmapDecoder> decoder;
	result = factory->CreateDecoderFromFilename(
		output.imagePath.wstring().c_str(),
		nullptr,
		GENERIC_READ,
		WICDecodeMetadataCacheOnLoad,
		decoder.GetAddressOf());
	if (FAILED(result))
	{
		error = "Could not decode font atlas PNG: " + output.imagePath.string();
		return false;
	}

	Microsoft::WRL::ComPtr<IWICBitmapFrameDecode> frame;
	result = decoder->GetFrame(0, frame.GetAddressOf());
	if (FAILED(result))
	{
		error = "Could not read font atlas PNG frame: " + output.imagePath.string();
		return false;
	}

	Microsoft::WRL::ComPtr<IWICFormatConverter> converter;
	result = factory->CreateFormatConverter(converter.GetAddressOf());
	if (FAILED(result))
	{
		error = "Could not create WIC format converter for font atlas PNG.";
		return false;
	}

	result = converter->Initialize(
		frame.Get(),
		GUID_WICPixelFormat32bppRGBA,
		WICBitmapDitherTypeNone,
		nullptr,
		0.0,
		WICBitmapPaletteTypeCustom);
	if (FAILED(result))
	{
		error = "Could not convert font atlas PNG to RGBA.";
		return false;
	}

	UINT width = 0;
	UINT height = 0;
	converter->GetSize(&width, &height);
	output.width = static_cast<unsigned>(width);
	output.height = static_cast<unsigned>(height);
	output.rgbaPixels.assign(static_cast<std::size_t>(output.width) * output.height * 4u, 0);

	const UINT stride = width * 4u;
	result = converter->CopyPixels(nullptr, stride, static_cast<UINT>(output.rgbaPixels.size()), output.rgbaPixels.data());
	if (FAILED(result))
	{
		error = "Could not copy font atlas PNG pixels.";
		return false;
	}

	error.clear();
	return true;
}
}
