using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UIFun.Definition;
using UIFun.Messagesv2;
using VRageMath;

namespace UIFun.StringProcessor
{
	public static class TextProcessor
	{
		static char[] Buffer = new char[1048576];//1MB
		static char[] HashCheck = new char[100];

		public struct Cache
		{
			internal char Letter;
			internal Vector2I Position;
			internal Vector4 TextColor;
			internal bool Italics;
		}
		public readonly static Cache EOL = new Cache() { Letter = '\0', TextColor = Color.White, Position = Vector2I.Zero, Italics = false };
		public static uint ProcessStringBuilder(ModMessageBase callingClass, StringBuilder Data, List<Cache> CacheValues, Vector4 InitialColor, uint PreviousHash, FontDefinition Font, bool FlushCache, out Vector2I Size, out int CacheSize, out bool Updated, bool wordwrap = false, Vector2I? WordWrapMax = null)
		{

			//Environment.CurrentManagedThreadId
			Updated = false;
			Size = Vector2I.Zero;
			CacheSize = 0;
			uint hash = 1;

			int cap = MathHelper.Clamp(Data.Length, 0, 100);
			if (cap == 0)
			{
				CacheValues.EnsureCapacity(1);
				if (CacheValues.Count < 1)
				{
					CacheValues.Add(EOL);

				}
				else
				{
					CacheValues[0] = EOL;
                }
				//CacheValues[0] = EOL;
				return hash;
				
            }
			Data.CopyTo(0, HashCheck, 0, cap);
			for (int l = 0; l < cap; l++)
			{
				hash += HashCheck[l];
			}
			hash += (uint)Data.Length;//account for length
            if (hash == PreviousHash && !FlushCache )
				return PreviousHash;
						
			FontDefinition.FontCharacterDefinition Value;
			
			if (Font == null)
				return 0;

			

			Updated = true;
			int lineheight = -Font.Lineheight;
			Size.Y = lineheight;

			if (Data.Length == 0)
			{
				CacheValues.EnsureCapacity(1);
				if (CacheValues.Count < 1)
				{
					CacheValues.Add(EOL);

				}
				else
				{
					CacheValues[0] = EOL;
				}
				return 0;
			}
			InitialColor = callingClass.ToLinearRGB(InitialColor);
			Data.CopyTo(0, Buffer, 0, MathHelper.Clamp(Data.Length, 0, 1048575));
			var initposition = Vector2I.Zero;
			var currentposition = initposition;
			var color = InitialColor;
			short italics = 0;
			//ensure capacity
			CacheValues.EnsureCapacity(Data.Length);
			bool wordwraploop = false;
			int lastword = 0;
			int lastwordpi = 0;
			int i = 0, pi = 0;
            for (; i < Data.Length; i++)
			{

                if (Buffer[i] == '<')
				{
					Vector4 ColorOut;
					int indexincrease;
					if(ColorReader.TryReadTag(Buffer, i, Data.Length, out indexincrease, out ColorOut))
					{
						i += indexincrease;
						color = callingClass.ToLinearRGB(ColorOut);
						continue;//skip!
					}
					short italicsinc;
					if(MarkupProcessor.TryReadTag(Buffer, i, Data.Length, out indexincrease, out italicsinc))
					{
						i += indexincrease;
						italics += italicsinc;
						continue;
					}

					if(ResetProcessor.TryReadTag(Buffer, i, Data.Length, out indexincrease))
					{
						i += indexincrease;
						color = InitialColor;
						italics = 0;
						continue;
					}
				}
				if(Buffer[i] == '\n')
				{
                    currentposition.X = initposition.X;
					currentposition.Y += lineheight;
					Size.Y += lineheight;
					lastword = i;
					lastwordpi = pi;
					wordwraploop = false;
                    continue;
				}
				else if(Buffer[i] == '\r')
				{
					continue;
				}
				else if (!Font.Characters.TryGetValue(Buffer[i], out Value))
				{
					continue;
				}
				if(wordwrap)
				{
					if (Buffer[i] == ' ' || Buffer[i] == '.' || Buffer[i] == '!' || Buffer[i] == '?' || Buffer[i] == '-')
					{
						lastword = i;
						lastwordpi = pi;
						wordwraploop = false;
                    }
					else
					{
						if(!wordwraploop && currentposition.X + Value.aw > WordWrapMax.Value.X)
						{
							i = lastword; //look back. 
							pi = lastwordpi;
							currentposition.Y += lineheight;
							Size.Y += lineheight;
                            currentposition.X = initposition.X;
							wordwraploop = true;
							continue;
                        }
                    }
                
				}
				currentposition.X += Value.lsb;
				if (CacheValues.Count > pi)
				{
					var Item = CacheValues.ElementAt(pi);
					Item.Letter = Buffer[i];
					Item.TextColor = color;
					Item.Position = currentposition;
					Item.Italics = italics > 0;
					CacheValues[pi] = Item;
				}
				else
				{
					Cache Item = new Cache() { Letter = Buffer[i], TextColor = color, Position = currentposition , Italics = italics > 0};
					CacheValues.Add(Item);
                }
				currentposition.X += Value.aw - Value.lsb;
				if (currentposition.X > Size.X)
					Size.X = currentposition.X;
				pi++;
				
			}

			if (CacheValues.Count > pi)
				CacheValues[pi] = EOL;
			else
				CacheValues.Add(EOL);
			CacheSize = pi;
            return hash;
		}

	}
}
