using System.Linq;
using System.Windows;
using System.Xml;
using Machinations;
using Machinations.FromFlash.graph;
using Machinations.FromFlash.machinations.model;
using Machinations.GUI;
using NUnit.Framework;

namespace MachinationsTests
{
    /// <summary>
    /// nefunkcni,potrebuji UI thread
    /// </summary>
    class ViewsTests
    {
        ////[Test]
        public void TestSourceToPool()
        {
            var graph = CreateSourcePoolGraphByViews();
            Pool pool = (Pool)graph.Elements[1];
            Assert.That(pool.ResourceCount == 0);
            StartGraph(graph);
            graph.OneTurnWithoutUserActions();
            Assert.That(pool.ResourceCount == 1);
        }

        //[Test]
        public void TestStateConnectionIncrement()
        {
            var graph = CreateSourcePoolGraphByViews();
            Pool pool = (Pool)graph.Elements[1];
            var stateConection = new StateConnection(pool, graph.Elements[2]);
            graph.AddElement(stateConection);
            //stateConection.Label.Text = "+1";
            StartGraph(graph);
            graph.OneTurnWithoutUserActions();
            Assert.That(pool.ResourceCount == 1);
            graph.OneTurnWithoutUserActions();
            Assert.That(pool.ResourceCount == 3);
            graph.OneTurnWithoutUserActions();
            Assert.That(pool.ResourceCount == 7);
        }

        //[Test]
        public void TestConnectionInhibition()
        {
            var graph = CreateSourcePoolGraphByViews();
            Pool pool = (Pool)graph.Elements[1];
            var stateConection = new StateConnection(pool, graph.Elements[2]);
            stateConection.Label.Text = "==0";
            graph.AddElement(stateConection);
            StartGraph(graph);
            graph.OneTurnWithoutUserActions();
            Assert.That(pool.ResourceCount == 1);
            graph.OneTurnWithoutUserActions();
            Assert.That(pool.ResourceCount == 1);
        }

        //[Test]
        public void OverrideGraphTest()
        {
            var graph = CreateSourcePoolGraphByViews();
            int elementsCount = graph.Elements.Count;
            var document = graph.GenerateXml();
            graph.ReadXml(document);
            Assert.That(graph.Elements.Count == elementsCount);
        }

        //[Test]
        public void AddGraphTest()
        {
            var graph = CreateSourcePoolGraphByViews();
            int elementsCount = graph.Elements.Count;
            var document = graph.GenerateXml();
            graph.AddXml(document.DocumentElement);
            Assert.That(graph.Elements.Count == 2 * elementsCount);
        }

        //[Test]
        public void TestAllComponents()
        {
            MachinationsGraph graph = new MachinationsGraph();
            graph.AddElement(new Pool());
            graph.AddElement(new Gate());
            graph.AddElement(new Source());
            graph.AddElement(new Drain());
            graph.AddElement(new ResourceConnection(graph.Elements[2], graph.Elements[3]));
            graph.AddElement(new StateConnection(graph.Elements[0], graph.Elements[4]));
            graph.AddElement(new Converter());
            graph.AddElement(new Trader());
            graph.AddElement(new Delay());
            graph.AddElement(new EndCondition());

            var document = graph.GenerateXml();
            MachinationsGraph graph2 = LoadGraph(document);
            Assert.That(graph2.Elements.Count == 10);
            Assert.That(graph2.Elements[0] is Pool);
            Assert.That(graph2.Elements[1] is Gate);
            Assert.That(graph2.Elements[2] is Source);
            Assert.That(graph2.Elements[3] is Drain);
            Assert.That(graph2.Elements[4] is ResourceConnection);
            Assert.That(graph2.Elements[5] is StateConnection);
            Assert.That(graph2.Elements[6] is Converter);
            Assert.That(graph2.Elements[7] is Trader);
            Assert.That(graph2.Elements[8] is Delay);
            Assert.That(graph2.Elements[9] is EndCondition);
            Assert.That(graph2.Elements[0].Outputs.Count() == 1);
            Assert.That(graph2.Elements[2].Outputs.Count() == 1);
            Assert.That(graph2.Elements[3].Inputs.Count() == 1);
            Assert.That(graph2.Elements[4].Inputs.Count() == 1);
            ResourceConnection resourceConnection = (ResourceConnection)graph2.Elements[4];
            Assert.That(resourceConnection.Start == graph2.Elements[2]);
            Assert.That(resourceConnection.End == graph2.Elements[3]);
            var stateConnection = (StateConnection)graph2.Elements[5];
            Assert.That(stateConnection.Start == graph2.Elements[0]);
            Assert.That(stateConnection.End == graph2.Elements[4]);
        }
        

        private static void StartGraph(MachinationsGraph graph)
        {
            graph.Running = true;
            graph.Prepare();
        }


        private MachinationsGraph CreateSourcePoolGraphByViews()
        {
            MachinationsGraph graph = new MachinationsGraph();
            INodeView<MachinationsNode> sourceView = CreateNodeView(new Source(), graph);
            INodeView<MachinationsNode> poolView = CreateNodeView(new Pool(), graph);
            IConnectionView connectionView =
                CreateConnectionView(new ResourceConnection(), graph);
            sourceView.AddConnection(connectionView, true);
            poolView.AddConnection(connectionView, false);
            return graph;
        }

        private IConnectionView CreateConnectionView(MachinationsConnection connection, MachinationsGraph graph)
        {
            var view = GraphConnectionType.CreateView(connection);
            graph.AddElement(connection);
            return view;
        }

        private INodeView<MachinationsNode> CreateNodeView(dynamic node, MachinationsGraph graph)
        {
            var view = GraphSymbol.CreateView(node);
            graph.AddElement(node);
            return view;
        } 

        private bool XMLCompare(XmlElement primary, XmlElement secondary)
        {
            if (primary.HasAttributes)
            {
                if (primary.Attributes.Count != secondary.Attributes.Count)
                    return false;
                foreach (XmlAttribute attr in primary.Attributes)
                {
                    if (secondary.Attributes[attr.Name] == null)
                        return false;
                    if (attr.Value.ToLower() != secondary.Attributes[attr.Name].Value.ToLower())
                        return false;
                }
            }
            if (primary.HasChildNodes)
            {
                if (primary.ChildNodes.Count != secondary.ChildNodes.Count)
                    return false;
                for (int i = 0; i <= primary.ChildNodes.Count - 1; i++)
                {
                    if (XMLCompare((XmlElement)primary.ChildNodes[i], (XmlElement)secondary.ChildNodes[i]) == false)
                        return false;
                }
            }
            return true;
        }

        private MachinationsGraph LoadGraph(XmlDocument document)
        {
            MachinationsGraph graph = new MachinationsGraph();
            graph.ReadXml(document);
            graph.Elements.ForEach(e =>
            {
                var connection = e as MachinationsConnection;
                if (connection != null)
                {
                    ProgramControlUtils.ConnectConnections(connection, 0, graph);
                }
            });
            return graph;
        }
    }
}
