using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Windows.Controls;

using miew.Mesh;
using miew.Array;

namespace agree.Wpf.Util
{
	public partial class DagLayoutPanel : Panel
	{

		internal class RailSet : List<Rail>
		{
			internal RailSet(LayoutDag _dag)
			{
				this.AddRange(_dag.GroupBy(n => n.Level)
								.OrderBy(g => g.Key)
								.Select((grp, ix) =>
								{
									Rail r = new Rail(this, ix);
									foreach (var node in grp)
									{
										node.railpos = r.AppendNew(new HvdConst(node.DesiredSize.Width), node);
									}
									return r;
								}));

				var h = RailsLoaded;
				if (h != null)
					h(this, new EventArgs());
			}

			public double MaxWidth { get { return this.Max(r => r.RailWidth); } }

			public event EventHandler RailsLoaded;

			public void SetRailCount(int c)
			{
				while (this.Count > c)
					this.RemoveAt(this.Count - 1);
				while (this.Count < c)
					this.Add(new Rail(this, this.Count));
			}
		};

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		internal partial class Rail
		{
			//double NodeHorizontalPadding = 10.0;
			public HvdStatic bvHorzPad = new HvdStatic(10);
			List<PosBase> rg = new List<PosBase>();
			RailSet rs;
			int index;
			HvdStatic left_start;

			public Rail(RailSet rs, int index)
			{
				this.rs = rs;
				this.index = index;
				this.left_start = new HvdStatic(0);
			}

			public RailSet RailSet { get { return rs; } }

			public int RailIndex { get { return index; } }

			//public void OnDagLoaded()
			//{
			//    foreach (PosBase pos in rg)
			//        pos.OnDagLoaded();
			//}

			public IHvDouble GetRailStart(int iPos)
			{
				return iPos == 0 ? left_start : rg[iPos - 1].RailCalcs(index).RightPadded;
			}

			public int Count { get { return rg.Count; } }

			public SingleNodePos AppendNew(IHvDouble bvWidth, LayoutDag.Node node)
			{
				return InsertNew(rg.Count, bvWidth, node);
			}


			public SingleNodePos InsertNew(int iPos, IHvDouble bvWidth, LayoutDag.Node node)
			{
				if (iPos > rg.Count)
					throw new Exception();

				return new SingleNodePos(this, bvWidth, new HvdConst(node.DesiredSize.Height), iPos, node);
			}

			//public Pos RemoveAt(int iPos)
			//{
			//    Pos pOld = GetItem(iPos);
			//    if (pOld == null)
			//        throw new Exception();
			//    pOld.Remove();
			//    return pOld;
			//}

			public double MaxHeight { get { return rg.Max(p => p.RailCalcs(index).Height.Value); } }

			public PosBase GetItem(int iPos)
			{
				return iPos < 0 || iPos >= rg.Count ? null : rg[iPos];
			}

			public int FindIndex(PosBase item)
			{
				return rg.IndexOf(item);
			}

			public int FindIndex(Double xPos)
			{
				int ix = rg.BinarySearch(xPos, p => p.RailCalcs(index).Center.Value);
				if (ix < 0)
					ix = ~ix;
				return ix;
			}

			public RailCalcSet FirstItemCalcs { get { return rg[0].RailCalcs(index); } }

			public RailCalcSet LastItemCalcs { get { return rg[rg.Count - 1].RailCalcs(index); } }

			public Double RailWidth { get { return LastItemCalcs.Right.Value - FirstItemCalcs.Left.Value; } }

		};
	};
}