using System;
using System.Collections.Generic;
using System.Threading;
using System.Windows;
using System.Windows.Media;
using System.Xml;
using Machinations;
using Machinations.FromFlash.graph;
using Machinations.FromFlash.machinations.model;
using Machinations.UserComponents;
using NUnit.Framework;

namespace MachinationsTests
{
    public class TestGate
    {
        [Test]
        public void Test1Output()
        {
            MachinationsGraph graph = new MachinationsGraph();
            graph.AddElement(new Source());
            Pool pool1 = new Pool();
            graph.AddElement(pool1);
            Gate gate = new Gate();
            graph.AddElement(gate);
            graph.CreateResourceConnection(graph.Elements[0], gate, ColorsUtils.InitColor);
            graph.CreateResourceConnection(gate, pool1, ColorsUtils.InitColor);
            graph.Running = true;
            graph.OneTurnWithoutUserActions();
            Assert.That(pool1.Resources.Count == 1);
            graph.Running = false;
            Assert.That(pool1.Resources.Count == 0);           
        }

        [Test]
        [TestCase(2, 2)]
        [TestCase(1, 3)]
        [TestCase(3, 1)]
        [TestCase(1, 5)]
        [TestCase(5, 1)]
        [TestCase(0, 1)]
        [TestCase(1, 0)]
        public void Test2DetermenisticOutputs(int pool1Count, int pool2Count)
        {
            GateTestingGraphDecorator graph = new GateTestingGraphDecorator();
            graph.Gate.GateType = GateMode.Deterministic;
            graph.Connection1.Label.Text = pool1Count.ToString();
            graph.Connection2.Label.Text = pool2Count.ToString();
            graph.Graph.Running = true;
            graph.Graph.MoreTurns(pool1Count + pool2Count);
            Assert.That(graph.Pool1.Resources.Count == pool1Count && graph.Pool2.Resources.Count == pool2Count);
        }

        [Test]
        [TestCase(2, 2, 2)]
        [TestCase(1, 3, 0)]
        [TestCase(1, 10, 1)]
        public void Test3DeterministicOutputs(int pool1Count, int pool2Count, int pool3Count)
        {
            GateTestingGraphDecorator graph = new GateTestingGraphDecorator();
            Pool pool3 = new Pool();
            graph.Graph.AddElement(pool3);
            var connection3 = graph.CreateResourceConnection(graph.Gate, pool3, ColorsUtils.InitColor);
            graph.Connection1.Label.Text = pool1Count.ToString();
            graph.Connection2.Label.Text = pool2Count.ToString();
            connection3.Label.Text = pool3Count.ToString();
            graph.Graph.Running = true;
            graph.Graph.MoreTurns(pool1Count + pool2Count + pool3Count);
            Assert.That(graph.Pool1.Resources.Count == pool1Count && graph.Pool2.Resources.Count == pool2Count &&
                        pool3.Resources.Count == pool3Count);
        }

        [Test]
        [TestCase(50,50)]
        [TestCase(10, 20)]
        [TestCase(20, 80)]
        public void Test2RandomOutputs(int prob1, int prob2)
        {
            GateTestingGraphDecorator graph = new GateTestingGraphDecorator();
            graph.Gate.GateType = GateMode.Dice;
            graph.Connection1.Label.Text = prob1 + "%";
            graph.Connection2.Label.Text = prob2 + "%";
            graph.Graph.Running = true;
            for (int i = 0; i < 1000; i++)
            {
                graph.Graph.OneTurnWithoutUserActions();
                //Thread.Sleep(1);
            }
            int error = 50;
            Assert.That(graph.Pool1.Resources.Count > prob1 * 10 - error && graph.Pool1.Resources.Count < prob1 * 10 + error);
            Assert.That(graph.Pool2.Resources.Count > prob2 * 10 - error && graph.Pool2.Resources.Count < prob2 * 10 + error);
            Assert.That(graph.Pool1.Resources.Count != prob1 * 10 || graph.Pool2.Resources.Count != prob2 * 10);
        }




        private class GateTestingGraphDecorator : IGraph
        {
            private readonly MachinationsGraph m_graph;
            public GateTestingGraphDecorator()
            {
                m_graph = new MachinationsGraph();
                m_graph.AddElement(new Source());                                             
                m_graph.AddElement(new Pool());                                               //1
                Gate gate = new Gate();         
                m_graph.AddElement(gate);                                                     //2
                m_graph.CreateResourceConnection(m_graph.Elements[0], gate, ColorsUtils.InitColor);
                m_graph.CreateResourceConnection(gate, m_graph.Elements[1], ColorsUtils.InitColor);        //4
                m_graph.AddElement(new Pool());                                               //5
                m_graph.CreateResourceConnection(gate, m_graph.Elements[5], ColorsUtils.InitColor);        //6
            }


            public ResourceConnection Connection1 => (ResourceConnection) m_graph.Elements[4];

            public ResourceConnection Connection2 => (ResourceConnection) m_graph.Elements[6];

            public Pool Pool1 => (Pool) m_graph.Elements[1];

            public Pool Pool2 => (Pool)m_graph.Elements[5];

            public Gate Gate => (Gate)m_graph.Elements[2];

            public MachinationsGraph Graph => m_graph;
            public List<GraphElement> Elements { get; set; }
            public List<IUserComponentSchema> UserComponents { get; set; }

            public void AddElement(GraphElement element)
            {
                
            }

            public void RemoveElement(GraphElement element)
            {
                throw new NotImplementedException();
            }

            public XmlDocument GenerateXml()
            {
                throw new NotImplementedException();
            }

            public void FillXmlElement(XmlElement filled)
            {
                throw new NotImplementedException();
            }

            public void Clear()
            {
                throw new NotImplementedException();
            }

            public void OnChanged(string reason, string message = null)
            {
                throw new NotImplementedException();
            }

            public ResourceConnection CreateResourceConnection(GraphElement startElement, GraphElement endElement, Color color, string label = null)
            {
                return m_graph.CreateResourceConnection(startElement, endElement, color);
            }

            public StateConnection CreateStateConnection(GraphElement startElement, GraphElement endElement, Color color, string label = null)
            {
                return m_graph.CreateStateConnection(startElement, endElement, color);
            }

            public Point GetCenter()
            {
                throw new NotImplementedException();
            }
        }
    }
}
