using ProtoBuf;
using Sandbox.ModAPI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UIFun.Interface;
using VRage;
using VRage.Utils;
using VRageMath;

namespace UIFun.Definition
{
	public class FontDefinition : iTextHUDAPI
	{


		enum FontDefinitionMembers : int
		{
			AddCharacter = 0,
			DefineFont,
			AddKerning,
			ReadOnly
		}

		[ProtoContract]
		public struct FontCharacterDefinitionData
		{
			[ProtoMember(1)]
			public char character;
			[ProtoMember(2)]
			public int texturesize;
			[ProtoMember(3)]
			public string charactercode;
			[ProtoMember(4)]
			public int uv1x;
			[ProtoMember(5)]
			public int uv1y;
			[ProtoMember(6)]
			public int sizex;
			[ProtoMember(7)]
			public int sizey;
			[ProtoMember(8)]
			public int aw;
			[ProtoMember(9)]
			public int lsb;
			[ProtoMember(10)]
			public bool forcewhite;
			[ProtoMember(11)]
			public MyStringId MaterialId;
		}

		public class FontCharacterDefinition 
		{
			public char character;
			public int texturesize;
			public string charactercode;
			public int uv1x;
			public int uv1y;
			public int sizex;
			public int sizey;
			public int aw;
			public int lsb;
			public bool forcewhite;
			public MyStringId MaterialId;
			public bool hasKerning;
			public Dictionary<char, int> Kerning;
			public Vector2 v0, v1, v2, v3;


		}
		private Dictionary<char, FontCharacterDefinition> m_characters = new Dictionary<char, FontCharacterDefinition>();
		private int m_fontbase = 30;
		private int m_lineheight = 30;
		private int m_fontsize = 23;
		private bool m_ReadOnly = false;
		private bool m_valid = false;
		public MyStringId fontname;

		public bool Valid
		{
			get
			{
				return m_valid;
			}
		}

		public void SetMember(int MemberEnum, object Value)
		{
			switch((FontDefinitionMembers)MemberEnum)
			{
				case FontDefinitionMembers.ReadOnly:
					ReadOnly = (bool)Value;
					break;
				case FontDefinitionMembers.DefineFont:
					var data = (MyTuple<int, int, int>)Value;
					Fontbase = data.Item1;
					Lineheight = data.Item2;
					Fontsize = data.Item3;
					break;
				case FontDefinitionMembers.AddCharacter:
					var characterData = MyAPIGateway.Utilities.SerializeFromBinary<FontCharacterDefinitionData>((byte[])Value);
					TryAddCharacter(characterData.character, characterData.MaterialId, characterData.texturesize, characterData.charactercode, characterData.uv1x, characterData.uv1y, characterData.sizex, characterData.sizey, characterData.aw, characterData.lsb, characterData.forcewhite);
					break;
				case FontDefinitionMembers.AddKerning:
					var kerningdata = (MyTuple<int, char, char>)Value;
					TryAddKerningPair(kerningdata.Item1, kerningdata.Item2, kerningdata.Item3);
                    break;
			}
		}

		public object GetMember(int MemberEnum)
		{
			switch ((FontDefinitionMembers)MemberEnum)
			{
				case FontDefinitionMembers.ReadOnly:
					return ReadOnly;
				default:
					return null;
			}
		}

		public Dictionary<char, FontCharacterDefinition> Characters
		{
			get
			{
				return m_characters;
			}

			set
			{
				m_characters = value;
			}
		}
		public bool TryAddKerningPair(int kerning, char right, char left)
		{
			FontCharacterDefinition characterdef;
            if (Characters.TryGetValue(right, out characterdef))
			{
				if(characterdef.Kerning == null)
				{
					characterdef.Kerning = new Dictionary<char, int>();
                    characterdef.hasKerning = true;
				}
				if(!characterdef.Kerning.ContainsKey(left))
				{
					characterdef.Kerning.Add(left, kerning);
					return true;
				}
			}
			return false;
		}
		public bool TryAddCharacter(char character, MyStringId material, int texturesize, string charactercode, int uv1x, int uv1y, int sizex, int sizey, int aw, int lsb, bool forcewhite = false)
		{
			if (Characters.ContainsKey(character))
			{
				if (ReadOnly)
					return false;
				Characters.Remove(character);
			}
			m_valid = true;
			var chara = new FontCharacterDefinition();
			chara.character = character;
			chara.texturesize = texturesize;
			chara.charactercode = charactercode;
			chara.uv1x = uv1x;
			chara.uv1y = uv1y + 6;
			chara.sizex = sizex;
			chara.sizey = sizey - 6;
			chara.aw = aw;
			chara.lsb = lsb;
			chara.forcewhite = forcewhite;
			chara.v0 = new Vector2(chara.uv1x, chara.uv1y) / chara.texturesize; //precalculate. 
			chara.v1 = new Vector2(chara.uv1x + chara.sizex, chara.uv1y) / chara.texturesize;
			chara.v2 = new Vector2(chara.uv1x, chara.uv1y + chara.sizey) / chara.texturesize;
			chara.v3 = new Vector2(chara.uv1x + chara.sizex, chara.uv1y + chara.sizey) / chara.texturesize;
			chara.MaterialId = material;
			chara.hasKerning = false;
			Characters.Add(character, chara);
			return true;
		}


		public int Fontbase
		{
			get
			{
				return m_fontbase;
			}

			set
			{
				if (!m_ReadOnly)
					m_fontbase = value;
			}
		}

		public int Lineheight
		{
			get
			{
				return m_lineheight;
			}

			set
			{
				if (!m_ReadOnly)
					m_lineheight = value;
			}
		}

		public int Fontsize
		{
			get
			{
				return m_fontsize;
			}

			set
			{
				if (!m_ReadOnly)
					m_fontsize = value;
			}
		}
		public bool ReadOnly
		{
			get
			{
				return m_ReadOnly;
			}
			set
			{
				if(!m_ReadOnly)
					m_ReadOnly = value;
			}
		}
		public override string ToString()
		{
			return fontname.String ?? base.ToString();
		}



	}
}
