#pragma once
#ifndef __FONT_GLYPHS_TEXTURE_H__
#define __FONT_GLYPHS_TEXTURE_H__

// I need GeometryText::Justify.
// There is a bug somewhere, when I include this file as the last included file, it fails to compile
#include "geometrytext.h"

#include <memory>
#include <vector>
#include <wx/font.h>
#include "3dmath.h"

namespace VRUT
{

	/// This class represents a texture with glyphs of individual letters of font,
	/// plus extra information about them like glyph origin or width.
	///
	/// Information is often given in a "single glyph's texture space". Single glyph
	/// texture is a rectangular subtexture of whole texture in which a single
	/// glyph resides, and its space is defined as having (0,0) in lower left corner
	/// of this subtexture (not the whole texture) and (1,1) in upper right corner
	/// of the subtexture.
	class VRUT_CORE_API FontGlyphsTexture
	{
	public:
		/// Additional information about each individual glyph
		struct GlyphMetrics
		{
			Vector2 pen_origin;		/// Position (in single glyph's texture space) of glyph's left side at bottom line
			float x_width;			/// Width of glyph (in single glyph's texture space)
		};

	protected:
		/// Number of characters, usually 256
		size_t charCount;
		/// Additional information about each glyph
		std::vector<GlyphMetrics> metrics;

		/// Maximal total height of glyphs (in single glyph's texture space)
		float glyphsHeight;
		/// Maximal descent of glyphs (in single glyph's texture space).
		///		- Descent is the space between the bottom of the glyph and a baseline.
		float glyphsDescent;

		/// Size of each character texture
		size_t texSize;
		/// Scale of the texture quad with respect to the glyph quad
		float texScale;
		/// Data of all rendered glyphs
		std::unique_ptr<float []> texData;

		/// Releases all internal data of this texture
		void releaseTex();

	public:
		FontGlyphsTexture();
		FontGlyphsTexture(const wxFont &font, size_t char_count, size_t tex_size, float tex_scale, size_t supersampling);
		FontGlyphsTexture(const wxFont &font, size_t char_count, size_t tex_size);
		~FontGlyphsTexture();

		/// Returns the number of rendered character glyphs
		inline size_t GetCharCount() const			{	return charCount;		}
		
		/// Returns data about each character
		inline const std::vector<GlyphMetrics> &GetMetrics() const		{	return metrics;		}
		
		/// Returns maximal height of glyphs (in single glyph's texture space)
		inline float GetGlyphsHeight() const		{	return glyphsHeight;	}
		
		/// Returns maximal descent of glyphs (in single glyph's texture space).
		/// Descent is the space between the bottom of the glyph and a baseline.
		inline float GetGlyphsDescent() const		{	return glyphsDescent;	}

		/// Returns the scale of the texture, which describes the size of a textured quad in which the glyph size is one
		inline float GetTexScale() const			{	return texScale;		}
		
		/// Returns size of each character texture
		inline size_t GetTexSize() const			{	return texSize;			}
		
		/// Returns the texture of a specific glyph. Each pixel has a single float value, which
		/// defines the intensity of the pixel.
		inline const float *GetTexData(int glyph) const		{	return &texData[texSize*texSize * glyph];		}

		/// Creates textures of given font
		/// \param[in] font Font to be rendered
		/// \param[in] char_count Number of characters to be rendered
		/// \param[in] tex_size Resolution of one glyph texture
		/// \param[in] tex_scale Scale of the texture quad
		/// \param[in] supersampling Size of the rectangle (in pixels) that is evaluated per each final texture pixel.
		/// \return Returns \c false if failed
		bool Create(const wxFont &font, size_t char_count, size_t tex_size, float tex_scale, size_t supersampling);

		/// The same as previous \c Create, uses default values for \c tex_scale and \c supersampling
		bool Create(const wxFont &font, size_t char_count, size_t tex_size);
	};

	/// Position of letters "compiled" from text. May be used as a source for creating geometry or for instancing.
	class VRUT_CORE_API TextLettersData
	{
	public:
		struct LetterDesc
		{
			Vector2 position;		///< Position of the lower left corner of a rectangle on which subtexture is rendered
			int glyph;				///< Index of used glyph
		};

		/// Memory pool for UpdateText method
		struct UpdateTextMemPool
		{
			std::vector<std::vector<LetterDesc> > lines;
			std::vector<float> widths;

			/// Resets the mem pool lines (it does not release the memory)
			void Reset();
			/// Pushes finished line into the list of lines and prepares a new line
			void PushLine(float line_width);
			/// Returns a number of finished (pushed) lines
			inline size_t GetNumberOfFinishedLines()			{	return widths.size();			}
			/// Returns the data of the line that is currently being prepared
			inline std::vector<LetterDesc> &GetCurrentLine()	{	return lines[widths.size()];	}
		};

	protected:
		/// Position of all letters of given text
		std::vector<LetterDesc> letters;

		/// Texture and metrics of font glyphs
		std::shared_ptr<FontGlyphsTexture> fontGlyphs;
		/// Size of the font in object units.
		/// Actual height of glyphs depends on \c fontSize the same as it depends on font point size when measured in pixels.
		float fontSize;
		/// Spacing between lines of the text. This spacing does not affect the space between individual letters.
		float spacing;
		/// X and Y justification of the text
		GeometryText::Justify xJustify, yJustify;

	public:
		TextLettersData(std::shared_ptr<FontGlyphsTexture> font_glyphs, float font_size, float spacing,
			GeometryText::Justify x_justify, GeometryText::Justify y_justify);
		TextLettersData(const wxString &text, std::shared_ptr<FontGlyphsTexture> font_glyphs, float font_size, float spacing,
			GeometryText::Justify x_justify, GeometryText::Justify y_justify);

		/// Updates parameters of the font.
		/// This function also clears descriptors of all letters
		void UpdateFont(std::shared_ptr<FontGlyphsTexture> font_glyphs, float font_size, float spacing,
			GeometryText::Justify x_justify, GeometryText::Justify y_justify);

		/// Updates descriptors of letters to given text.
		/// The font must be already updated.
		void UpdateText(const wxString &text);
		void UpdateText(const wxString &text, UpdateTextMemPool &mem_pool);

		/// Returns descriptors of all letters
		const std::vector<LetterDesc> &GetLetterDesc() const			{	return letters;		}

		/// Returns current font glyphs texture data
		/// Do not allow to change the returned object. To change it, use \c UpdateFont method.
		std::shared_ptr<const FontGlyphsTexture> GetFontGlyphs() const	{	return fontGlyphs;	}

		/// Returns size of every rectangle with glyphs of the text
		float GetRectSize() const		{	return fontSize * fontGlyphs->GetTexScale();		}
	};

}

#endif	// __FONT_GLYPHS_TEXTURE_H__
