using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UIFun.Definition;
using UIFun.Interface;
using UIFun.Messagesv2;
using VRageMath;
using BlendTypeEnum = VRageRender.MyBillboard.BlendTypeEnum;

/*
//+-------------------------+
//| margin                  |
//|  +-------------------+  |
//|  | border            |  |
//|  |  +-------------+  |  |
//|  |  | padding     |  |  |
//|  |  |  +-------+  |  |  |
//|  |  |  |content|  |  |  |
//|  |  |  +-------+  |  |  |
//|  |  | padding     |  |  |
//|  |  +-------------+  |  |
//|  | border            |  |
//|  +-------------------+  |
//| margin                  |
//+-------------------------+

*/

namespace Draygo.TextHUDAPI.BoxUI
{
	public class BoxUIRoot : iTextHUDAPI
	{
		internal UIDefinition UIDef;
		internal UIBehaviourDefinition UIBehaviourDef = new UIBehaviourDefinition();
		internal ModBillboardHUDMessage top, left, right, bottom, top_left, top_right, bottom_left, bottom_right, fill;
		internal int contentheight = 0;
		internal int contentwidth = 0;
		internal int width = 0;
		internal int height = 0;
		internal int posx = 0;
		internal int posy = 0;
		internal bool hideHud = true;
		internal Color m_BackgroundColor = Color.White;
		internal BoxUIRoot m_Parent;
		internal static BoxUIRoot RootObject;
		internal ModMessageBase Content;

		internal bool m_float = true;
		internal List<BoxUIRoot> children = new List<BoxUIRoot>();

		public bool visible = true;

		private enum BoxUIBaseMembers : int
		{
			Origin = 0,
			BackgroundColor,
			Width,
			Height,
			Definition,
			Behaviour,
			Visible,
			Parent,
			HideHud
		}

		public virtual void SetMember(int MemberEnum, object Value)
		{
			switch((BoxUIBaseMembers)MemberEnum)
			{
				case BoxUIBaseMembers.Origin:
					var origin = (Vector2I)Value;
					SetPosition(origin.X, origin.Y);
					return;
				case BoxUIBaseMembers.Height:
					UpdateHW((int)Value, width);
					return;
				case BoxUIBaseMembers.Width:
					UpdateHW(height, (int)Value);
                    return;
				case BoxUIBaseMembers.Definition:
					SetDefinition((UIDefinition)Value);
					return;
				case BoxUIBaseMembers.Behaviour:
					SetBehaviour((UIBehaviourDefinition)Value);
					return;
				case BoxUIBaseMembers.BackgroundColor:
					m_BackgroundColor = (Color)Value;
					SetColor();
					return;
				case BoxUIBaseMembers.Visible:
					visible = (bool)Value;
					return;
				case BoxUIBaseMembers.Parent:
					var newparent = (BoxUIRoot)Value;
					newparent.AddChild(this);
					return;
				case BoxUIBaseMembers.HideHud:
					hideHud = (bool)Value;
					return;
			}
		}



		public virtual object GetMember(int MemberEnum)
		{
			switch ((BoxUIBaseMembers)MemberEnum)
			{
				case BoxUIBaseMembers.Origin:
					return new Vector2I(posx, posy);
				case BoxUIBaseMembers.Height:
					return height;
				case BoxUIBaseMembers.Width:
					return width;
				case BoxUIBaseMembers.Definition:
					return UIDef;
				case BoxUIBaseMembers.Behaviour:
					return UIBehaviourDef;
				case BoxUIBaseMembers.BackgroundColor:
					return m_BackgroundColor;
				case BoxUIBaseMembers.Visible:
					return visible;
				case BoxUIBaseMembers.HideHud:
					return hideHud;
				default:
					return null;
			}
		}

		public BoxUIRoot()
		{
			if(m_Parent == null)
			{
				if(RootObject != this && RootObject != null)
				{
					RootObject.AddChild(this);
				}
			}
		}
		private void SetColor()
		{
			if (bottom != null)
				bottom.BillBoardColor = m_BackgroundColor;
			if (top != null)
				top.BillBoardColor = m_BackgroundColor;
			if (left != null)
				left.BillBoardColor = m_BackgroundColor;
			if (right != null)
				right.BillBoardColor = m_BackgroundColor;
			if (fill != null)
				fill.BillBoardColor = m_BackgroundColor;
			if (top_left != null)
				top_left.BillBoardColor = m_BackgroundColor;
			if (top_right != null)
				top_right.BillBoardColor = m_BackgroundColor;
			if (bottom_left != null)
				bottom_left.BillBoardColor = m_BackgroundColor;
			if (bottom_right != null)
				bottom_right.BillBoardColor = m_BackgroundColor;
		}
		public void SetDefinition(UIDefinition def)
		{
			UIDef = def;
			
			if (UIDef.bottom.HasValue)
			{
				bottom = CreateBillboardFactoryDefaults();
				bottom.Material = UIDef.bottom.material;
				bottom.TextureSize = UIDef.bottom.materialSize;
				bottom.uvOffset = new Vector2(UIDef.bottom.ux, UIDef.bottom.uy);
				bottom.uvSize = new Vector2(UIDef.bottom.usizex, UIDef.bottom.usizey);
			}
			if (UIDef.top.HasValue)
			{
				top = CreateBillboardFactoryDefaults();
				top.Material = UIDef.top.material;
				top.TextureSize = UIDef.top.materialSize;
				top.uvOffset = new Vector2(UIDef.top.ux, UIDef.top.uy);
				top.uvSize = new Vector2(UIDef.top.usizex, UIDef.top.usizey);
			}
			if (UIDef.left.HasValue)
			{
				left = CreateBillboardFactoryDefaults();
				left.Material = UIDef.left.material;
				left.TextureSize = UIDef.left.materialSize;
				left.uvOffset = new Vector2(UIDef.left.ux, UIDef.left.uy);
				left.uvSize = new Vector2(UIDef.left.usizex, UIDef.left.usizey);
			}
			if (UIDef.right.HasValue)
			{
				right = CreateBillboardFactoryDefaults();
				right.Material = UIDef.right.material;
				right.TextureSize = UIDef.right.materialSize;
				right.uvOffset = new Vector2(UIDef.right.ux, UIDef.right.uy);
				right.uvSize = new Vector2(UIDef.right.usizex, UIDef.right.usizey);
			}
			if (UIDef.fill.HasValue)
			{
				fill = CreateBillboardFactoryDefaults();
				fill.Material = UIDef.right.material;
				fill.TextureSize = UIDef.right.materialSize;
				fill.uvOffset = new Vector2(UIDef.fill.ux, UIDef.fill.uy);
				fill.uvSize = new Vector2(UIDef.fill.usizex, UIDef.fill.usizey);
			}
			if (UIDef.top_left.HasValue)
			{
				top_left = CreateBillboardFactoryDefaults();
				top_left.Material = UIDef.top_left.material;
				top_left.TextureSize = UIDef.top_left.materialSize;
				top_left.uvOffset = new Vector2(UIDef.top_left.ux, UIDef.top_left.uy);
				top_left.uvSize = new Vector2(UIDef.top_left.usizex, UIDef.top_left.usizey);
			}
			if (UIDef.top_right.HasValue)
			{
				top_right = CreateBillboardFactoryDefaults();
				top_right.Material = UIDef.top_right.material;
				top_right.TextureSize = UIDef.top_right.materialSize;
				top_right.uvOffset = new Vector2(UIDef.top_right.ux, UIDef.top_right.uy);
				top_right.uvSize = new Vector2(UIDef.top_right.usizex, UIDef.top_right.usizey);
			}
			if (UIDef.bottom_left.HasValue)
			{
				bottom_left = CreateBillboardFactoryDefaults();
				bottom_left.Material = UIDef.top_left.material;
				bottom_left.TextureSize = UIDef.top_left.materialSize;
				bottom_left.uvOffset = new Vector2(UIDef.bottom_left.ux, UIDef.bottom_left.uy);
				bottom_left.uvSize = new Vector2(UIDef.bottom_left.usizex, UIDef.bottom_left.usizey);
			}
			if (UIDef.bottom_right.HasValue)
			{
				bottom_right = CreateBillboardFactoryDefaults();
				bottom_right.Material = UIDef.bottom_right.material;
				bottom_right.TextureSize = UIDef.bottom_right.materialSize;
				bottom_right.uvOffset = new Vector2(UIDef.bottom_right.ux, UIDef.bottom_right.uy);
				bottom_right.uvSize = new Vector2(UIDef.bottom_right.usizex, UIDef.bottom_right.usizey);
			}
			Update();
		}

		public void SetBehaviour( UIBehaviourDefinition UIBehaviourDef)
		{
			this.UIBehaviourDef = UIBehaviourDef;
			Update();
		}

		public void SetPosition(int x, int y)
		{
			bool changed = false;
			if(posx != x)
			{
				posx = x;
				changed = true;
            }
			if (posy != y)
			{
				posy = y;
				changed = true;
			}
			if (changed)
				Update();			

		}

		public void UpdateHW(int height, int width)
		{
			bool changed = false;
			if(this.height != height )
			{
				this.height = height;
				contentheight = height - (UIDef?.MinX ?? 0);
				changed = true;
			}
			if(this.width != width)
			{
				this.width = width;
				contentwidth = width - (UIDef?.MinY ?? 0);
				changed = true;
			}
			if (changed)
				Update();
        }
		public void Update()
		{
			Vector2D Adj = Vector2D.Zero;
			if(m_Parent != null)
			{
				var adjust = m_Parent.ContentTopLeftCorner();
                Adj = new Vector2D(adjust.X, adjust.Y);
            }
			if (UIDef == null)
				return;
			Adj.X += UIDef.left.margin;
			Adj.Y += UIDef.top.margin;
            if (UIDef.bottom.HasValue)
			{
				bottom.Width = contentwidth;
				bottom.Height = UIDef.bottom.usizey;

				bottom.Origin = new Vector2D(posx, posy) + Adj;
				bottom.uvSize = new Vector2(Math.Min(UIDef.bottom.usizex, contentwidth), UIDef.bottom.usizey);
				bottom.Offset = new Vector2D(UIDef.left.usizex, height - UIDef.bottom.usizey - UIDef.bottom.padding);
			}
			if (UIDef.top.HasValue)
			{
				top.Width = contentwidth;
				top.Height = UIDef.top.usizey;

				top.Origin = new Vector2D(posx, posy) + Adj;
				top.uvSize = new Vector2(Math.Min(UIDef.top.usizex, contentwidth), UIDef.top.usizey);
				top.Offset = new Vector2D(UIDef.left.usizex, 0);
			}
			if (UIDef.left.HasValue)
			{
				left.Width = UIDef.left.usizex;
				left.Height = contentheight; 

				left.Origin = new Vector2D(posx, posy) + Adj;
				left.uvSize = new Vector2(UIDef.left.usizex, Math.Min(UIDef.left.usizey, contentheight));
				left.Offset = new Vector2D(0, UIDef.top.usizey);
			}
			if (UIDef.right.HasValue)
			{
				right.Width = UIDef.right.usizex;
				right.Height = contentheight;

				right.Origin = new Vector2D(posx, posy) + Adj;
				right.uvSize = new Vector2(UIDef.right.usizex, Math.Min(UIDef.right.usizey, contentheight));
				right.Offset = new Vector2D(width - UIDef.right.usizex - UIDef.right.padding, UIDef.top.usizey);
			}
			if (UIDef.fill.HasValue)
			{
				fill.Width = contentwidth;//contentwidth;
                fill.Height = contentheight;// contentheight;

				fill.Origin = new Vector2D(posx, posy) + Adj;
				fill.Offset = new Vector2D(UIDef.left.usizex, UIDef.top.usizey);

			}
			if(UIDef.top_left.HasValue)
			{
				top_left.Width = UIDef.top_left.usizex;
				top_left.Height = UIDef.top_left.usizey;

				top_left.Origin = new Vector2D(posx, posy) + Adj;
				top_left.Offset = Vector2D.Zero;
			}
			if (UIDef.bottom_left.HasValue)
			{
				bottom_left.Width = UIDef.bottom_left.usizex;
				bottom_left.Height = UIDef.bottom_left.usizey;

				bottom_left.Origin = new Vector2D(posx, posy) + Adj;
				bottom_left.Offset = new Vector2D(0, height - UIDef.bottom_left.usizey - UIDef.bottom.padding);
			}
			if (UIDef.top_right.HasValue)
			{
				top_right.Width = UIDef.top_right.usizex;
				top_right.Height = UIDef.top_right.usizey;

				top_right.Origin = new Vector2D(posx, posy) + Adj;
				top_right.Offset = new Vector2D(width - UIDef.bottom_right.usizex - UIDef.right.padding, 0);
			}
			if (UIDef.bottom_right.HasValue)
			{
				bottom_right.Width = UIDef.bottom_right.usizex;
				bottom_right.Height = UIDef.bottom_right.usizey;

				bottom_right.Origin = new Vector2D(posx, posy) + Adj;
				bottom_right.Offset = new Vector2D(width - UIDef.bottom_right.usizex -UIDef.right.padding, height - UIDef.bottom_left.usizey - UIDef.bottom.padding);
			}
		}
		public Vector2I ContentTopLeftCorner()
		{
			if(UIDef == null)
			{
				return (m_Parent?.ContentTopLeftCorner() ?? new Vector2I(0, 0)) + new Vector2I(posx, posy);
            }
			return (m_Parent?.ContentTopLeftCorner() ?? new Vector2I(0, 0)) + new Vector2I(posx + UIDef.left.margin + UIDef.left.usizex + UIDef.left.padding, posy + UIDef.top.margin + UIDef.top.usizey + UIDef.top.padding);
		}
		public Vector2I InnerSize()
		{
			return new Vector2I(contentwidth, contentheight);
		}
		public Vector2I OuterSize()
		{
			return new Vector2I(width, height);
		}

		public virtual void Draw(bool hudhidden)
		{
			if (hideHud && hudhidden)
				return;
			if (UIDef == null || !visible)
				return;
			if (UIDef.fill.HasValue)
			{
				fill.Draw();
			}
			if (UIDef.bottom.HasValue)
			{
				bottom.Draw();
			}
			if(UIDef.top.HasValue)
			{
				top.Draw();
			}
			if(UIDef.left.HasValue)
			{
				left.Draw();
			}
			if(UIDef.right.HasValue)
			{
				right.Draw();
			}
			if(UIDef.top_left.HasValue)
			{
				top_left.Draw();
			}
			if (UIDef.top_right.HasValue)
			{
				top_right.Draw();
			}
			if (UIDef.bottom_left.HasValue)
			{
				bottom_left.Draw();
			}
			if (UIDef.bottom_right.HasValue)
			{
				bottom_right.Draw();
			}
			if (Content != null)
			{
				Content.Draw();
			}
			foreach (var child in children)
			{
				if(child.visible)
					child.Draw(hudhidden);
			}
		}

		public void AddChild(BoxUIRoot box)
		{
			if(box.m_Parent != null)
			{
				box.m_Parent.RemoveChild(box, false);
			}
			children.Add(box);

			box.m_Parent = this;
			box.Update();
		}

		public void RemoveChild(BoxUIRoot box, bool addroot = true)
		{
			children.Remove(box);
			if(addroot)
			{
				box.m_Parent = RootObject;
				box.Update();
			}

		}

		public static ModBillboardHUDMessage CreateBillboardFactoryDefaults()
		{
			var billboard = new ModBillboardHUDMessage();
			billboard.UseUv = true;
			billboard.Visible = false;
			billboard.Scale = 1;
			billboard.Blend = BlendTypeEnum.PostPP;
			billboard.Options |= Options.Pixel;
			return billboard;

		}


	}
}
