using Sandbox.ModAPI;
using System;
using System.Collections.Generic;
using System.Linq;
using VRage.Utils;
using VRageMath;
using UIFun.StringProcessor;
using UIFun.Definition;

namespace UIFun.Messagesv2
{

	public enum TextOrientation : byte
	{
		ltr = 1,
		center = 2,
		rtl = 3
	}
    public class ModSpaceMessage : ModMessageBase
	{

		private enum EntityMembers : int
		{
			WorldPosition = 10,
			Up,
			Left,
			TxtOrientation,
			Font

		}
		public Vector3D WorldPosition = Vector3D.Zero;
		public Vector3D Up = MatrixD.Identity.Up;
		public Vector3D Left = MatrixD.Identity.Left;
		public TextOrientation TxtOrientation = TextOrientation.ltr;
		FontDefinition Font;
		const string FONTNAME = "white";
		MyStringId m_font = MyStringId.GetOrCompute( FONTNAME );
		public bool m_HasCache = false;
		uint hash = 0;
		Vector2I m_Size = Vector2I.Zero;
		private List<TextProcessor.Cache> Cache = new List<TextProcessor.Cache>();

		public override object GetMember(int MemberEnum)
		{
			switch ((EntityMembers)MemberEnum)
			{
				case EntityMembers.WorldPosition:
					return WorldPosition;
				case EntityMembers.Up:
					return Up;
				case EntityMembers.Left:
					return Left;
				case EntityMembers.TxtOrientation:
					return (byte)TxtOrientation;
				case EntityMembers.Font:
					return m_font.String;
				default:
					return base.GetMember(MemberEnum);
			}
		}
		public override void SetMember(int MemberEnum, object Value)
		{
			switch ((EntityMembers)MemberEnum)
			{
				case EntityMembers.WorldPosition:
					WorldPosition = (Vector3D)Value;
					return;
				case EntityMembers.Up:
					Up = (Vector3D)Value;
					return;
				case EntityMembers.Left:
					Left = (Vector3D)Value;
					return;
				case EntityMembers.TxtOrientation:
					TxtOrientation = (TextOrientation)(byte)Value;
					return;
				case EntityMembers.Font:
					m_font = MyStringId.GetOrCompute((string)Value);
					Font = FontTexture.GetFont(m_font);
					Flush();
					return;
				default:
					base.SetMember(MemberEnum, Value);
					return;
			}

		}
		public override Vector2D GetLength()
		{
			Process();
			Vector2D Length = Vector2D.Zero;
			if (Font == null)
			{
				Font = FontTexture.GetFont(m_font);
				if (Font == null)
					return Length;
			}
			Length = new Vector2D( m_Size.X, m_Size.Y ) / 37d;
			return Length;
		}
		public override void Draw()
		{

			if (Vector3D.DistanceSquared(MyAPIGateway.Session.Camera.WorldMatrix.Translation, WorldPosition) > Math.Pow(200d * (Scale < 1.0d ? 1.0d : Scale), 2))
				return;
			if (Font == null)
			{
				Font = FontTexture.GetFont(m_font);
				if (Font == null)
					return;
			}
			Process();
			DrawCache();
			return;
		}

		private void DrawCache()
		{
			Vector2I offset = Vector2I.Zero;
			if (TxtOrientation == TextOrientation.rtl)
			{
				offset.X = -m_Size.X;
			}
			if (TxtOrientation == TextOrientation.center)
			{
				offset.X = -m_Size.X / 2;
			}
			for (int i = 0; i < Cache.Count && Cache[i].Letter != '\0'; i++)
			{
				//TextProcessor.Cache cache = Cache[i];
				//WriteLetter(cache.Position + offset, cache.Letter, cache.TextColor);
				WriteLetter(Cache[i], offset);
			}

		}

		public void Process()
		{
			Vector2I Size = Vector2I.Zero;
			int CacheSize = 0;
			bool updated = false;
            var newhash = TextProcessor.ProcessStringBuilder(this, this.Message, Cache, Color.White.ToVector4(), hash, Font, m_HasCache, out Size, out CacheSize, out updated);
			if(updated)
			{
				m_HasCache = true;
				m_Size = Size;
				hash = newhash;
			}
		}

		public override void Flush()
		{
			base.Flush();
			m_HasCache = false;
		}
		private void WriteLetter(Vector2I OffsetI, char letter, Vector4 fontcolor)
		{
			FontDefinition.FontCharacterDefinition value;
			if (Font.Characters.TryGetValue(letter, out value))
			{
				if (letter != ' ')
				{
					Vector3D textpos = this.WorldPosition;
					textpos += this.Left * (((-OffsetI.X - value.aw / 2d )/ 37d) * Scale + -this.Offset.X);
					textpos += this.Up * ((OffsetI.Y / 37d) * this.Scale + this.Offset.Y);
					
					VersionHelper.AddBillboardOriented(value, fontcolor, textpos , Up, Left, (float)Scale, Blend);
				}
			}
		}
		private void WriteLetter(TextProcessor.Cache Cache, Vector2I OffsetI)
		{
			OffsetI += Cache.Position;
			FontDefinition.FontCharacterDefinition value;
			if (Font.Characters.TryGetValue(Cache.Letter, out value))
			{
				if (Cache.Letter != ' ')
				{
					Vector3D textpos = this.WorldPosition;
					textpos += this.Left * (((-OffsetI.X - value.aw / 2d) / 37d) * Scale + -this.Offset.X);
					textpos += this.Up * ((OffsetI.Y / 37d) * this.Scale + this.Offset.Y);

					VersionHelper.AddBillboardOriented(value, Cache.TextColor, textpos, Up, Left, (float)Scale, Blend);
				}
			}
		}
	}
}
