#include <psemek/fonts/font.hpp>
#include <psemek/fonts/monospace_font.hpp>
#include <psemek/fonts/kerned_font.hpp>

#include <psemek/gfx/resource/font_9x12_png.hpp>
#include <psemek/gfx/resource/font_10x12_bold_png.hpp>
#include <psemek/fonts/resources/font_9x12_glyphs_txt.hpp>
#include <psemek/fonts/resources/font_10x12_bold_glyphs_txt.hpp>

#include <psemek/gfx/pixmap.hpp>

#include <psemek/io/memory_stream.hpp>

#include <sstream>

namespace psemek::fonts::inline v1
{

	std::unique_ptr<font> make_default_monospace_9x12_font()
	{
		character_range range{32, 128};
		std::string_view name = "default_monospace_9x12";
		math::vector<int, 2> size{9, 12};

		gfx::texture_2d atlas = gfx::texture_2d::from_pixmap(gfx::read_image<std::uint8_t>(io::memory_istream{gfx::resource::font_9x12_png.data}));
		atlas.nearest_filter();
		atlas.clamp();
		gl::TexParameteri(atlas.target, gl::TEXTURE_SWIZZLE_G, gl::RED);
		gl::TexParameteri(atlas.target, gl::TEXTURE_SWIZZLE_B, gl::RED);
		gl::TexParameteri(atlas.target, gl::TEXTURE_SWIZZLE_A, gl::RED);

		std::vector<math::box<float, 2>> texcoords(range.end - range.begin);

		for (char32_t c = range.begin; c < range.end; ++c)
		{
			int const row = 16;
			int x = (c - range.begin) % row;
			int y = (c - range.begin) / row;

			math::box<float, 2> b;
			b[0].min = x * 11 + 1;
			b[0].max = b[0].min + 9;
			b[1].min = y * 14 + 1;
			b[1].max = b[1].min + 12;
			texcoords[c - range.begin] = b;
		}

		return std::make_unique<monospace_font>(range, name, size, std::move(atlas), std::move(texcoords));
	}

	static std::unique_ptr<font> make_default_font(std::string_view name, math::vector<int, 2> const & size, rs::resource const & atlas_resource, rs::resource const & glyphs_resource)
	{
		gfx::texture_2d atlas = gfx::texture_2d::from_pixmap(gfx::read_image<std::uint8_t>(io::memory_istream{atlas_resource.data}));
		atlas.nearest_filter();
		atlas.clamp();
		gl::TexParameteri(atlas.target, gl::TEXTURE_SWIZZLE_G, gl::RED);
		gl::TexParameteri(atlas.target, gl::TEXTURE_SWIZZLE_B, gl::RED);
		gl::TexParameteri(atlas.target, gl::TEXTURE_SWIZZLE_A, gl::RED);

		bmfont_data data;
		data.name = name;
		data.size = size;
		data.baseline = 2;

		{
			std::istringstream is{std::string(glyphs_resource.data)};

			std::string line;
			while (std::getline(is, line))
			{
				if (auto pos = line.find('#'); pos != std::string::npos)
					line = line.substr(0, pos);

				if (line.empty()) continue;

				std::istringstream is{std::move(line)};

				int c;
				is >> c;
				auto & glyph = data.glyphs[c];

				is >> glyph.start_x >> glyph.start_y >> glyph.size_x >> glyph.size_y >> glyph.offset_x >> glyph.offset_y >> glyph.advance;
			}
		}

		return std::make_unique<kerned_font>(std::move(data), std::move(atlas));
	}

	std::unique_ptr<font> make_default_9x12_font()
	{
		return make_default_font("default_9x12", {9, 12}, gfx::resource::font_9x12_png, resources::font_9x12_glyphs_txt);
	}

	std::unique_ptr<font> make_default_10x12_bold_font()
	{
		return make_default_font("default_10x12_bold", {10, 12}, gfx::resource::font_10x12_bold_png, resources::font_10x12_bold_glyphs_txt);
	}

}
