#pragma once

#include <string>
#include <map>
#include <memory>
#include <vector>
#include "glm/glm.hpp"
#include "Shader.hpp"

namespace ftgl
{
	struct texture_atlas_t;
	struct texture_font_t;
};

struct FontDescription
{
	std::string Filename;
	float Size;

	bool operator<(const FontDescription& val) const
	{
		if(Size != val.Size)
			return Size < val.Size;
		return Filename < val.Filename;
	}
};

class Text;


/// manages all existing Text-Objects and renders them in an efficient way
/// NewText returns a handle to the text object, the object itself is managed by TextManager, so the handle can be discarded
class TextManager
{
public:
	TextManager(glm::uvec2 screenSize, glm::uvec2 atlasSize=glm::uvec2(256, 256));
	TextManager(TextManager&) = delete;
	TextManager& operator=(TextManager&) = delete;
	~TextManager();

	void SetScreenSize(glm::vec2 new_size);

	void AddFont(std::string Filename, float Size);
	Text* NewText(std::string text, glm::vec2 Position=glm::vec2(), float Size = 0, std::string FontFile = "");
	void RemoveText(Text* text);

	void RenderAll();
	static std::string GetUtf8StdStringFromWChar(wchar_t* text);
private:
	glm::uvec2 m_ScreenSize;
	ftgl::texture_atlas_t* m_Atlas;
	std::map<FontDescription, ftgl::texture_font_t*> m_Fonts;
	std::vector<std::unique_ptr<Text>> m_Texts;
	Shader m_Shader;
};

/// object to manage a single text. The text is an UTF8-String, so Unicode is supported
class Text
{
public:
	/// should only be used by TextManager::NewText()
	Text(std::string text, glm::vec2 Position, ftgl::texture_font_t* Font);
	Text(Text&) = delete;
	Text& operator=(Text&) = delete;
	~Text();

	void SetText(std::string Text);
	void AddText(std::string Text);
	std::string GetText();

	/// should only be used by TextManager::RenderAll()
	void DrawCall();
	glm::vec2 GetScreenPosition() { return m_ScreenPosition; }
	void SetScreenPosition(glm::vec2 p) { m_ScreenPosition = p; }

	glm::vec2 GetSize()  { return m_DrawSize; } // returns the size of the current text in pixel

	void SetColor(glm::vec3 Color) {m_Color=Color;}
	glm::vec3 GetColor() { return m_Color; }

	void SetVisible(bool visible);
	bool GetVisible();
private:
	glm::vec2 m_ScreenPosition;
	glm::vec3 m_Color=glm::vec3(1, 1, 1);
	bool m_Visible;

	std::string m_CurrentText;
	ftgl::texture_font_t* m_Font;

	std::vector<glm::vec2> m_Positions;
	std::vector<glm::vec2> m_UVs;

	unsigned int m_PositionBuffer;
	unsigned int m_UVBuffer;
	unsigned int m_VAO;

	glm::vec2 m_DrawSize;
};


