using System;
using System.Collections.Generic;
using System.Windows.Media;
using System.Xml;
using Machinations.FromFlash.graph;

namespace Machinations.FromFlash.machinations.model
{
    /// <summary>
    /// node of machinations framework, can delay incoming resources and send then next turn-turns
    /// </summary>
    public class Delay : MachinationsNode
    {
        private List<Resource> m_resources;
        private ResourceConnection m_output;


        public double InputStateValue;
        private string m_delayType;

        public const string TypeQeue = "queue";
        public const string TypeNormal = "normal";

        public  Delay()
        {
            Size = 12;
            m_resources = new List<Resource>();
            m_delayType = TypeNormal;
        }


        public override NodeClass NodeClass => NodeClass.Delay;

        public string DelayType
        {
            get { return m_delayType; }
            set
            {
                if (m_delayType != value)
                {
                    m_delayType = value;
                    OnChanged("DelayType changed");
                }
            }
        }

        public List<Resource> Resources
        {
            get { return m_resources; }
            set { m_resources = value; }
        }

        public override XmlElement GenerateXml(XmlDocument document, XmlElement element = null)
		{
			element = base.GenerateXml(document);
			element.SetAttribute("delayType", DelayType);
			return element;
		}

        public override void AutoFire()
		{
			base.AutoFire();
			if ((m_graph as MachinationsGraph).TimeMode == TimeMode.TurnBased) AdvanceTime(1);
		}
		
		public override void ReadXml(XmlElement element) 
		{
			base.ReadXml(element);
		    DelayType = element.GetAttribute("delayType");
		}		
		
		public override void Prepare(bool doEvents) 
		{
			base.Prepare(doEvents);
			m_resources.Clear();
			m_output = null;
            m_outputs.ForEach(output =>
            {
                if (output is ResourceConnection)
                {
                    m_output = output as ResourceConnection;
                }
            });
			InputStateValue = 0;
		}
		
		public override void Stop() 
		{
			base.Stop();
			m_resources.Clear();
			if (m_doEvents) OnChanged(GraphEvent.ElementChange);
		}
		
		public override void Fire() 
		{
			base.Fire();
            Pull();
		}
		
		public override void ReceiveResource(Color color, ResourceConnection flow) 
		{
			base.ReceiveResource(color, flow);
			Resource resource = null;
			if ((m_graph as MachinationsGraph).ColorCoding)
			{
			    ResourceConnection outputRc;
			    for (int index = 0; index < m_outputs.Count; index++)
			    {
			        var output = m_outputs[index];
			        outputRc = output as ResourceConnection;
			        if (outputRc != null && outputRc.Color == color && !outputRc.Inhibited)
			        {
			            outputRc.Label.GenerateNewValue();
			            double d = outputRc.Label.Value + InputStateValue;
			            resource = new Resource(color, d) {Connection = outputRc};
			            break;
			        }
			    }

			    if (resource == null)
			    {
			        foreach (var output in m_outputs)
			        {
			            outputRc = output as ResourceConnection;
			            if (outputRc != null && outputRc.Color == Color && !outputRc.Inhibited)
			            {
			                outputRc.Label.GenerateNewValue();
			                double d = outputRc.Label.Value + InputStateValue;
			                resource = new Resource(color, d) {Connection = outputRc};
			                break;
			            }
			        }
			    }
			} else if (m_output != null && !m_output.Inhibited)
            {
				m_output.Label.GenerateNewValue();
				double d = m_output.Label.Value + InputStateValue;
				resource = new Resource(color, d);
                resource.Connection = m_output;
			}
			if (resource != null)
            {
				m_resources.Add(resource);
                ChangeState(resource.Color, 1);
			}
			//if (m_doEvents) OnChanged(GraphEvent.ElementChange);
		}
		
		public override void Update(double time) 
		{
			base.Update(time);
			if ((m_graph as MachinationsGraph).TimeMode != TimeMode.TurnBased)
            {
                AdvanceTime(time);
			}
		}
		
		private void AdvanceTime(double time)
        {
			int resourcesCount = m_resources.Count;
			if (DelayType == TypeQeue) resourcesCount = Math.Min(resourcesCount, 1); //queue
			for (int i = resourcesCount - 1; i >= 0; i--) {
				m_resources[i].Position -= time;
				if (m_resources[i].Position <= 0) {
					if (m_output != null && !m_output.Inhibited)
                    {
                        ChangeState(m_resources[i].Color, -1);
                        m_resources[i].Position = 0;
						m_resources[i].Connection.Resources.Add(m_resources[i]);
						m_resources[i].Connection.RequestQueue.Add(1);
						m_resources.RemoveAt(i);
                        Trigger();
						if (m_doEvents) OnChanged(GraphEvent.ElementChange);
					}
				}
			}
		}

        private void Trigger()
        {
            m_outputs.ForEach(output =>
            {
                StateConnection outConnection = output as StateConnection;
                if (outConnection != null && outConnection.Label.Type ==  LabelType.Trigger) outConnection.Fire();
            });
        }

        public bool GetDelayed()
        {
            return m_resources.Count > 0;
        }
		
		public void Modify(double delta)
        {
			InputStateValue += delta;
		}
		
		public void ChangeState(Color resourceColor, int delta)
        {
            m_outputs.ForEach(output =>
            {
                StateConnection stateConnection = output as StateConnection;
                if (stateConnection != null && (stateConnection.Color == Color || resourceColor == ColorsUtils.TransparentColor || stateConnection.Color == resourceColor ||! (m_graph as MachinationsGraph).ColorCoding ) )
                {
                    stateConnection.ChangeState(delta);
                }
            });
			if (delta != 0) {

                CheckInhibition();
			}
			
		}
    }
}
