using System;
using System.Collections.Generic;
using System.Globalization;
using System.Net;
using System.Xml;
using Machinations.FromFlash.graph;

namespace Machinations.FromFlash.machinations.model
{
    /// <summary>
    /// node of a graph, can be set up to do simple scripts based on if then rules and by that,affect others interactive elements
    /// </summary>
    public class ArtificialPlayer : MachinationsNode
    {
        private ActivationMode m_initialMode;
        private double m_autoFire;
        private double m_timer;

        public string Script;
        public List<APInstruction> Instructions;
        public double ActionsPerTurn;
        public int ActionsExecuted;
        public int ActionsPerStep;
        public List<double> PregeneratedRandom;

        public ArtificialPlayer()
        {
            Script = "";
            ActionsPerTurn = 1;
            m_activationMode = ActivationMode.Automatic;
            Actions = 0;
            PregeneratedRandom = new List<double>();
            for (int i = 0; i < 10; i++) PregeneratedRandom.Add(0);
        }

        public override NodeClass NodeClass => NodeClass.ArtificialPlayer;

        public override XmlElement GenerateXml(XmlDocument document, XmlElement element = null) 
		{
			element = base.GenerateXml(document);
            if (!string.IsNullOrEmpty(Script))
            {
                element.InnerText = Script;
            }
            element.SetAttribute("actionsPerTurn", ActionsPerTurn + "");
            return element;
		}

        public override void ReadXml(XmlElement element) 
		{
			base.ReadXml(element);
            Script = WebUtility.HtmlDecode(element.InnerXml);
			ActionsPerTurn = double.Parse(element.GetAttribute("actionsPerTurn"), CultureInfo.InvariantCulture);
		}

        public void ReadInstructions() 
		{
			Instructions = new List<APInstruction>();
			string s = Script;
			int endLineIndex = s.IndexOf("\r");
			if ( endLineIndex < 0) endLineIndex = s.IndexOf("\n");
			while (endLineIndex > 0) {
				string i = (s.Substring(0, endLineIndex)).Trim();
				if (i.Length > 0) Instructions.Add(new APInstruction(this, s));
				s = s.Substring(endLineIndex + 1);
				endLineIndex = s.IndexOf("\r");
				if (endLineIndex < 0) endLineIndex = s.IndexOf("\n");
			}
			var rest = s.Trim();
			if (rest.Length > 0) Instructions.Add(new APInstruction(this, s));
		}	
		
		public override void Prepare(bool doEvents) 
		{
			base.Prepare(doEvents);
			m_timer = 0;
			m_autoFire = 0;
			ActionsExecuted = 0;
			ActionsPerStep = 0;
			Actions = 0;
			m_initialMode = m_activationMode;
            for (int i = 0; i < PregeneratedRandom.Count; i++) {
				PregeneratedRandom[i] = RandomUtils.NextDouble();
			}
            ReadInstructions();
		}
		
		public override void Stop() 
		{
			m_activationMode = m_initialMode;
			base.Stop();
		}
		
		public override void AutoFire() 
		{
			ActionsPerStep = 0;
			if ((m_graph as MachinationsGraph)?.TimeMode == TimeMode.TurnBased)
            {
				if (ActionsPerTurn >= 1 && m_activationMode == ActivationMode.Automatic)
                {
					if (!Inhibited) Fire();
                        m_autoFire += Math.Floor(ActionsPerTurn-1);
				}			
			}
            else {
			    base.AutoFire();
		    }
		}
		
		public override void Update(double time) 
		{
			if (Firing > 0)
            {
                Firing -= time;
                if (Firing <= 0)
                {
                    Firing = 0;
                    if (m_doEvents) OnChanged(GraphEvent.ElementChange);
                }
            }
			if (m_autoFire > 0)
            {
                if ((m_autoFire % 1) - time * 0.8 <= 0 && (m_autoFire % 1) > 0)
                {
                    if (!Inhibited) Fire();
                }
                m_autoFire -= time * 0.8;
            }
			if ((m_graph as MachinationsGraph).Ended || (m_graph as MachinationsGraph).ActionsPerTurn > 0) return;
            m_timer += time;
		    if (m_timer >= ActionsPerTurn)
            {
                m_timer -= ActionsPerTurn;
                if (ActivationMode == ActivationMode.Automatic && !Inhibited) Fire();
            }
        }

        public override void Fire()
		{
			if (m_caption == "F") {
				throw new NotImplementedException("how did I get here");
			}
			//TODO: color-coding new style
			ActionsExecuted++;
			ActionsPerStep++;

            SetFiring();
			Instructions.ForEach(instruction => instruction.Activate());
            LogSelf();
		}	
		
		public void Activate()
        {
			if (m_activationMode == ActivationMode.Passive)
            {
				ActivationMode = ActivationMode.Automatic;
				if (m_doEvents) OnChanged(GraphEvent.ElementChange);
			}
		}
		
		public void Deactivate()
        {
			if (m_activationMode == ActivationMode.Automatic)
            {
				ActivationMode = ActivationMode.Passive;
				if (m_doEvents) OnChanged(GraphEvent.ElementChange); 
			}
			
		}
    }
}
