using System;
using System.Globalization;
using System.Windows.Media;
using System.Xml;
using Machinations.FromFlash.graph;
using Machinations.UserComponents;

namespace Machinations.FromFlash.machinations.model
{
    /// <summary>
    /// base class of resource and state connnections, have common thoings connected with machinations framework...so no connection things,those are in graphconnection
    /// </summary>
    public abstract class MachinationsConnection : GraphConnection, IPreparable
    {
        protected bool m_communicateInhibition = true;

        public Color Color;
        private int m_thickness;
        public Label Label;
        public bool DoEvents;
        public double  Firing;
        public double Blocked;

        public Action VisualChanged;

        protected MachinationsConnection()
        {
            m_thickness = 2;
            Color = ColorsUtils.InitColor;
            Label = new Label(this, 0.5, "");
        }

        public int Thickness
        {
            get { return m_thickness; }
            set
            {
                if (m_thickness != value)
                {
                    m_thickness = value;
                    VisualChanged?.Invoke();
                }
            }
        }

        public void ConnectToElement(GraphElement element, bool connectingStart)
        {
            if (connectingStart)
            {
                Start = element;
                element.AddOutput(this);
            }
            else
            {
                End = element;
                element.AddInput(this);
            }
        }

        public void DisconnectElement(bool connectingStart)
        {
            if (connectingStart)
            {
                Start?.RemoveOutput(this);
                Start = null;
            }
            else
            {
                End?.RemoveInput(this);
                End = null;
            }
        }

        public override void Dispose()
        {
            if (m_start != null)
            {
                m_start.RemoveOutput(this);
                m_start = null;
            }
            if (m_end != null)
            {
                m_end.RemoveInput(this);
                m_end = null;
            }
            base.Dispose();
            //m_points.Clear();
        }

        //      protected override void CalculateTotalLength()
        //{
        //	base.CalculateTotalLength();
        //          CalculateModifierPosition();
        //      }

        //      public void CalculateModifierPosition(double x = -1, double y = -1)
        //      {
        //	double targetLength = Label.Position * TotalLength;
        //          int i = 1;
        //	Label.CalculatedNormal = new MyVector(1, 0);
        //          Label.CalculatedPosition = Points[0].Clone();
        //	while (i <  Points.Count)
        //          {
        //		MyVector difference = Points[i].Subtract(Points[i - 1]);
        //              double differenceLength = difference.Normalize();
        //		if (differenceLength < targetLength) {
        //			targetLength -= differenceLength;
        //		} else {
        //			Label.CalculatedNormal = difference;
        //			Label.CalculatedPosition = Points[i - 1].Clone();
        //                  Label.CalculatedPosition.X += difference.X* targetLength;
        //                  Label.CalculatedPosition.Y += difference.Y* targetLength;

        //			if (x > -1) {
        //				MyVector difference2 = Label.CalculatedPosition.Clone();
        //				difference2.X -= x;
        //				difference2.Y -= y;
        //				double temp = difference2.X;
        //			    difference2.X = -difference2.Y;
        //                      difference2.Y = temp;
        //                      double dot = difference2.DotProduct(difference);
        //				if (dot > 0) Label.Side = 1;
        //				else Label.Side = -1;
        //			}

        //			double s = 10 * Label.Side;
        //			if (difference.X>0.94 || difference.X<-0.94) {
        //				Label.Align = PhantomFont.AlignCenter;
        //			} else if (difference.Y * Label.Side < 0) {
        //                      Label.Align = PhantomFont.AlignLeft;
        //                  } else {
        //				Label.Align = PhantomFont.AlignRight;
        //			}
        //			Label.CalculatedPosition.X -= difference.Y * s;
        //                  Label.CalculatedPosition.Y += difference.Y * s;
        //			break;
        //		}
        //		i++;
        //	}
        //          Inputs.ForEach(input =>
        //          {
        //              if (input != this)
        //              {
        //                  input.CalculateEndPosition();
        //              }
        //          });

        //          Outputs.ForEach(output =>
        //          {
        //              if (output != this)
        //              {
        //                  output.CalculateStartPosition();
        //              }
        //          });
        //}

        //public override Point Position 
        //{
        //	get { return Label.CalculatedPosition.Clone(); }
        //      }

        //public override MyVector GetConnection(MyVector towards) 
        //{
        //	Point difference = Label.CalculatedPosition.Clone();
        //	switch (Label.Align) {
        //		case PhantomFont.AlignLeft:
        //			difference.X += Label.Size.X * 0.5;
        //			break;
        //		case PhantomFont.AlignRight:
        //			difference.X -= Label.Size.X * 0.5;
        //			break;
        //	}
        //	MyVector u = towards.Subtract(difference);
        //	u.Normalize();
        //	MyVector p = MathUtil.GetRectangleOutlinePoint(u, 0.5 * Label.Size.X + 3, 0.5 * Label.Size.Y + 3);
        //          IncrementBy(ref difference, p);
        //	//difference.x -= width * 0.5;
        //	//difference.y -= height * 0.5;
        //	return difference;
        //      }	

        public override XmlElement GenerateXml(XmlDocument document, XmlElement element = null) 
		{
			element = base.GenerateXml(document, element);
		    element.SetAttribute("label", Label.Text);
		    element.SetAttribute("position", Math.Round(Label.Position, 2) * Label.Side+ "");
		    element.SetAttribute("color", Color.ToNiceString());
		    element.SetAttribute("thickness", Thickness + "");
            if (Label.Min > -Label.Limit) element.SetAttribute("min", Math.Round(Label.Min, 2) + "");
			if (Label.Max < Label.Limit) element.SetAttribute("max", Math.Round(Label.Max, 2) + "") ;
			return element;
		}	
		
		public override void ReadXml(XmlElement element) 
		{
			base.ReadXml(element);
			Label.Text = element.GetAttribute("label");
			Label.Position = double.Parse(element.GetAttribute("position"), CultureInfo.InvariantCulture);
            if (Label.Position < 0)
            {
				Label.Position *= -1;
				Label.Side = -1;
			} else
            {
				Label.Side = 1;
			}
		    Color = ColorsUtils.GetColorFromString(element.GetAttribute("color"));
		    
			if (element.HasAttribute("min")) Label.Min = double.Parse(element.GetAttribute("min"), CultureInfo.InvariantCulture); 
			if (element.HasAttribute("max")) Label.Max = double.Parse(element.GetAttribute("max"), CultureInfo.InvariantCulture);
		    Thickness = Convert.ToInt32(double.Parse(element.GetAttribute("thickness"), CultureInfo.InvariantCulture));
        }
		
		public virtual void Prepare(bool doEvents)
        {
            DoEvents = doEvents;
            Firing = 0;
            Blocked = 0;
            Label.Prepare();
            m_inhibited = false;
            var node = Start as MachinationsNode;
            if (node != null)
            {
                m_inhibited = node.Inhibited;
                node.CheckInhibition();
            }
        }

        public virtual void Stop()
        {
			Firing = 0;
			Blocked = 0;
			Label.Stop();
			m_inhibited = false;

            OnChanged(GraphEvent.ElementChange);
		}
		
		public virtual void Update(double time)
		{
			if (Firing > 0) {
				Firing -= time;
				if (Firing <= 0) {
					Firing = 0;
					if (DoEvents) OnChanged(GraphEvent.ElementChange);
				}
			}			
			if (Blocked > 0) {
				Blocked -= time;
				if (Blocked <= 0) {
					Blocked = 0;
				}
				if (DoEvents) OnChanged(GraphEvent.ElementChange);
			}			
		}

        protected override void InhibitedChangeForReal()
        {
            if (m_inhibited != m_inhibitedNewState)
            {
                base.InhibitedChangeForReal();
                if (m_communicateInhibition)
                {
                    (End as MachinationsNode)?.CheckInhibition();
                    (End as ResourceConnection)?.CheckInhibition();
                }

                if (DoEvents) OnChanged(GraphEvent.ElementChange);
            }
        }
    }
}
