/*
 * 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/.
 */

#pragma once

#if __has_include("msdfgen.h")

#include "Scene/AtlasData.hpp"
#include "IFontAtlasGenerator.hpp"
#include "Scene/Texture.hpp"
#include <msdfgen.h>
#include <msdf-atlas-gen/msdf-atlas-gen.h>
#include <string>
#include <optional>
#include <map>
#include <variant>
#define MSDFGEN_AVAILABLE 1

namespace OpenVulkano::Scene
{

	struct FontAtlasGeneratorConfig
	{
		static FontAtlasGeneratorConfig sdfDefaultConfig;
		static FontAtlasGeneratorConfig msdfDefaultConfig;
		int glyphSize;
		double miterLimit;
		msdfgen::Range pixelRange;
	};

	template<int Channels>
	class FontAtlasGenerator : public IFontAtlasGenerator
	{
	private:
		using SdfGenerator = msdf_atlas::ImmediateAtlasGenerator<float, 1, msdf_atlas::sdfGenerator,
		                                                         msdf_atlas::BitmapAtlasStorage<msdfgen::byte, 1>>;
		using MsdfGenerator = msdf_atlas::ImmediateAtlasGenerator<float, 3, msdf_atlas::msdfGenerator,
		                                                          msdf_atlas::BitmapAtlasStorage<msdfgen::byte, 3>>;
	public:
		using Generator = std::conditional<Channels == 1, SdfGenerator, MsdfGenerator>::type;
		using Config = FontAtlasGeneratorConfig;
		static constexpr int channelsCount = (Channels == 1 ? 1 : 4);
		static msdf_atlas::Charset LoadAllGlyphs(const std::variant<std::string, Array<char>>& data);
		FontAtlasGenerator();
		void GenerateAtlas(const std::string& fontFile, const std::set<uint32_t>& charset,
		                   const std::optional<std::string>& pngOutput = std::nullopt) override;
		void GenerateAtlas(const Array<char>& fontData, int length, const std::set<uint32_t>& charset,
		                   const std::optional<std::string>& pngOutput = std::nullopt) override;
		void GenerateAtlas(const std::string& fontFile, const msdf_atlas::Charset& charset = msdf_atlas::Charset::ASCII,
		                   const std::optional<std::string>& pngOutput = std::nullopt);
		void GenerateAtlas(const msdfgen::byte* fontData, int length,
		                   const msdf_atlas::Charset& charset = msdf_atlas::Charset::ASCII,
		                   const std::optional<std::string>& pngOutput = std::nullopt);
		void SaveAtlasMetadataInfo(const std::string& outputFile, bool packIntoSingleFile = true) const override;
		void SetGeneratorConfig(const Config& config) { m_config = config; }
		std::shared_ptr<AtlasData> GetAtlasData() const { return m_atlasData; }
		Config& GetGeneratorConfig() { return m_config; }
	private:
		void InitFreetypeFromFile(msdfgen::FreetypeHandle*& ft, msdfgen::FontHandle*& font, const std::string& file);
		void InitFreetypeFromBuffer(msdfgen::FreetypeHandle*& ft, msdfgen::FontHandle*& font,
		                            const msdfgen::byte* fontData, int length);
		void Generate(msdfgen::FreetypeHandle* ft, msdfgen::FontHandle* font, const msdf_atlas::Charset& chset,
		              const std::optional<std::string>& pngOutput);
		void SavePng(const std::string& output) const;

	private:
		Config m_config;
		std::shared_ptr<AtlasData> m_atlasData;
	};
	using SdfFontAtlasGenerator = FontAtlasGenerator<1>;
	using MsdfFontAtlasGenerator = FontAtlasGenerator<3>;
}
#endif
