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
{
	using Math = System.Math;
	public partial class DagLayoutPanel : Panel
	{

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		[DebuggerDisplay("{ToString().Replace(\"\\r\\n\",\" \"),nq}")]
		internal partial class Rail
		{
			internal class RailCalcSet
			{
				readonly PosBase pb;
//				readonly Rail r;

				public RailCalcSet(Rail r, PosBase pb, IHvDouble width, IHvDouble height)
				{
	//				this.r = r;
					this.pb = pb;
					this.bv_width = new HvdDynamic(width);
					this.bv_height = new HvdDynamic(height);
					this.bv_my_parent_center = new HvdDynamic(HvdConst.NaN);
					this.bv_my_child_center = new HvdDynamic(HvdConst.NaN);

					this.bv_self_base = new SelfBaseCalc();
					this.bv_self_ctr = new SelfCenterCalc(
						pb, // temp
						bv_self_base, bv_width, bv_my_parent_center, bv_my_child_center);

					this.bv_left = new HvdSubHalf(bv_self_ctr, bv_width);
					this.bv_right = new HvdAddHalf(bv_self_ctr, bv_width);
					this.bv_right_padded = new HvdAddConst(20, bv_right);

					this.bv_parent_extracalc = new ExtraCalc(bv_my_parent_center, bv_self_ctr);
					this.bv_child_extracalc = new ExtraCalc(bv_my_child_center, bv_self_ctr);

					//this.RailPad = new HotValue.HvdMax(this.bv_left,this.
				}

				public PosBase PosBase { get { return pb; } }

				//HvIntervalAggregateSpan aspan = new HvIntervalAggregateSpan();

				readonly SelfBaseCalc bv_self_base;
				readonly SelfCenterCalc bv_self_ctr;
				readonly HvdDynamic bv_width;
				readonly HvdDynamic bv_height;

				readonly HvdDynamic bv_my_parent_center;
				readonly HvdDynamic bv_my_child_center;

				readonly IHvDouble bv_left;
				readonly IHvDouble bv_right;
				readonly IHvDouble bv_right_padded;
				readonly ExtraCalc bv_parent_extracalc;
				readonly ExtraCalc bv_child_extracalc;


				//class Bvi : BoundVar<Interval,Inter
				//private class BviWidth : BoundVar<Interval,Double>
				//{
				//    public BviWidth(Bvi
				//};

				private class SelfBaseCalc : HvdAdd
				{
					public SelfBaseCalc()
						: base(HvdConst.Zero, HvdConst.Zero)
					{
					}

					public IHvDouble RailBase
					{
						get { return (IHvDouble)Args[0]; }
						set
						{
							if (Args[0] != value)
							{
								StopListeningTo(Args[0]);
								Args[0] = value;
								ListenTo(Args[0]);
								Recalculate();
							}
						}
					}

					public IHvDouble RailPad
					{
						get { return (IHvDouble)Args[1]; }
						set
						{
							if (Args[1] != value)
							{
								StopListeningTo(Args[1]);
								Args[1] = value;
								ListenTo(Args[1]);
								Recalculate();
							}
						}
					}
				};

				private class SelfCenterCalc : HotValueCalc<Double>, IHvDouble
				{
					PosBase pb;
					public SelfCenterCalc(PosBase pb, SelfBaseCalc sbc, IHvDouble bv_width, IHvDouble bv_pp, IHvDouble bv_cp)
						: base(false, sbc, bv_width, bv_pp, bv_cp, HvdConst.Zero, HvdConst.Zero)
					{
						this.pb = pb;
					}

					Double dSelfBase { get { return Arg0; } }
					Double dWidth { get { return Arg1; } }
					Double dParentCtrProp { get { return Arg2; } }
					Double dChildCtrProp { get { return Arg3; } }
					Double dParentExtra { get { return Arg4; } }
					Double dChildExtra { get { return Arg5; } }

					//public Hvd ParentCenterProposal
					//{
					//    get { return (Hvd)Args[2]; }
					//    set
					//    {
					//        if (Args[2] != value)
					//        {
					//            Args[2] = value;
					//            ListenTo(Args[3]);
					//            Recalculate();
					//        }
					//    }
					//}

					//public Hvd ChildCenterProposal
					//{
					//    get { return (Hvd)Args[3]; }
					//    set
					//    {
					//        if (Args[3] != value)
					//        {
					//            Args[3] = value;
					//            ListenTo(Args[3]);
					//            Recalculate();
					//        }
					//    }
					//}

					public IHvDouble ParentExtraIn
					{
						get { return (IHvDouble)Args[4]; }
						set
						{
							if (Args[4] != value)
							{
								StopListeningTo(Args[4]);
								Args[4] = value;
								ListenTo(Args[4]);
								Recalculate();
							}
						}
					}

					public IHvDouble ChildExtraIn
					{
						get { return (IHvDouble)Args[5]; }
						set
						{
							if (Args[5] != value)
							{
								StopListeningTo(Args[5]);
								Args[5] = value;
								ListenTo(Args[5]);
								Recalculate();
							}
						}
					}

					protected override double Calculate()
					{
						Double half_width = dWidth / 2;

						//Double p_prop_l = dParentCtrProp - half_width;
						//Double c_prop_l = dChildCtrProp - half_width;

						//if (dParentCtrProp > 0.0 || dChildCtrProp > 0.0)
						//glue.Debugging.Nop.X();


						Double left = dSelfBase;
						if (!double.IsNaN(dParentCtrProp))
							left = Math.Max(left, (dParentCtrProp - half_width));
						if (!double.IsNaN(dChildCtrProp))
							left = Math.Max(left, (dChildCtrProp - half_width));

						left = Math.Max(dSelfBase, left);

						Double extra = Math.Max(dParentExtra, dChildExtra);
						//if (extra > 0.0)
						//    glue.Debugging.Nop.X();

						//if (((SingleNodePos)pb).node.fe.Name == "t3")
						//{
						//    extra += 200;
						//}

						Double final = extra + left + half_width;
						if (double.IsNaN(final))
							Debugger.Break();
						return final;
					}
				}

				private class ExtraCalc : HotValueCalc<Double>, IHvDouble
				{
					public ExtraCalc(IHvDouble bv0, IHvDouble bv1)
						: base(false, bv0, bv1)
					{
					}

					public IHvDouble Proposal
					{
						get { return (IHvDouble)Args[0]; }
						set
						{
							if (Args[0] != value)
							{
								StopListeningTo(Args[0]);
								Args[0] = value;
								ListenTo(Args[0]);
								Recalculate();
							}
						}
					}

					public IHvDouble Chosen
					{
						get { return (IHvDouble)Args[1]; }
						set
						{
							if (Args[1] != value)
							{
								StopListeningTo(Args[1]);
								Args[1] = value;
								ListenTo(Args[1]);
								Recalculate();
							}
						}
					}

					protected override double Calculate()
					{
						if (double.IsNaN(Proposal.Value))
							return 0.0;
						return Proposal.Value - Chosen.Value;
						//return 0.0;
					}
				};

				public IHvDouble RailBase
				{
					get { return bv_self_base.RailBase; }
					set { bv_self_base.RailBase = value; }
				}
				public IHvDouble RailPad
				{
					get { return bv_self_base.RailPad; }
					set { bv_self_base.RailPad = value; }
				}
				public IHvDouble SelfBase
				{
					get { return bv_self_base; }
				}
				public IHvDouble Width
				{
					get { return bv_width; }
					set { bv_width.Source = value; }
				}
				public IHvDouble Height
				{
					get { return bv_height; }
					set { bv_height.Source = value; }
				}
				/// <summary>
				/// Based on where my parent(s) currently are, this is the offset from my rail base that I would need to
				/// use to be centered under them.
				/// </summary>
				public IHvDouble MyParentCenter
				{
					get { return bv_my_parent_center; }
					set { bv_my_parent_center.Source = value; }
				}
				/// <summary>
				/// Based on where my child/children currently are, this is the offset that would place me over them
				/// </summary>
				public IHvDouble MyChildCenter
				{
					get { return bv_my_child_center; }
					set { bv_my_child_center.Source = value; }
				}
				/// <summary>
				/// This is the discrepancy between where I am currently positioned and where I should be positioned based
				/// on my parents.
				/// </summary>
				public IHvDouble ParentExtraOut
				{
					get { return bv_parent_extracalc; }
				}
				/// <summary>
				/// This is the discrepancy between where I am currently positioned and where I should be positioned based
				/// on my children.
				/// </summary>
				public IHvDouble ChildExtraOut
				{
					get { return bv_child_extracalc; }
				}
				public IHvDouble ParentExtraIn
				{
					get { return bv_self_ctr.ParentExtraIn; }
					set { bv_self_ctr.ParentExtraIn = value; }
				}
				public IHvDouble ChildExtraIn
				{
					get { return bv_self_ctr.ChildExtraIn; }
					set { bv_self_ctr.ChildExtraIn = value; }
				}
				public IHvDouble Center
				{
					get { return bv_self_ctr; }
				}
				public IHvDouble Left
				{
					get { return bv_left; }
				}
				public IHvDouble Right
				{
					get { return bv_right; }
				}
				public IHvDouble RightPadded
				{
					get { return bv_right_padded; }
				}

				public override string ToString()
				{
					return String.Format(@"
Width:                {0:0.0000} : {1}
Height:               {2:0.0000} : {3}
RailBase:             {4:0.0000} : {5}
RailPad:              {6:0.0000} : {7}
SelfBase:             {8:0.0000} : {9}
Left:                 {10:0.0000} : {11}
Center:               {12:0.0000} : {13}
Right:                {14:0.0000} : {15}
ParentCenterProposal: {16:0.0000} : {17}
ChildCenterProposal:  {18:0.0000} : {19}
ParentExtraOut:       {20:0.0000} : {21}
ChildExtraOut:        {22:0.0000} : {23}
ParentExtraIn:        {24:0.0000} : {25}
ChildExtraIn:         {26:0.0000} : {27}
",
				 Width.Value, Width.GetType().Name,
				 Height.Value, Height.GetType().Name,
				 RailBase.Value, RailBase.GetType().Name,
				 RailPad.Value, RailPad.GetType().Name,
				 SelfBase.Value, SelfBase.GetType().Name,
				 Left.Value, Left.GetType().Name,
				 Center.Value, Center.GetType().Name,
				 Right.Value, Right.GetType().Name,
				 MyParentCenter.Value, MyParentCenter.GetType().Name,
				 MyChildCenter.Value, MyChildCenter.GetType().Name,
				 ParentExtraOut.Value, Width.GetType().Name,
				 ChildExtraOut.Value, Width.GetType().Name,
				 ParentExtraIn.Value, ParentExtraIn.GetType().Name,
				 ChildExtraIn.Value, ChildExtraIn.GetType().Name
				 );
				}
			}
		};
	};
}