using Algorithms.Nw.ShortestPathAllPairs;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using U.Graph;
using U.ListOperations;
using U.StringOperations;

namespace Algorithms.Nw.PathGeneration
{
    public class Dials : PathGenerationAlgorithm
    {
        public enum Criteria { NoCriteria, SingleCriterion, DoubleCriteria };

        private Criteria criteria;
        private double[,] D;
        private int maxNbArcs;

        public Dials(Criteria condition, double[,] shortestPathMatrix, int maxNbArcsForUnconditioned)
        {
            this.criteria = condition;
            this.D = shortestPathMatrix;
            this.maxNbArcs = maxNbArcsForUnconditioned;
        }


        public override void run(Graph graph, int oriIndex, int desIndex, int nbExistingPaths, int maxNbPaths, bool keepTime)
        {
            if (keepTime) { startTimer(); }
            base.lstNodeIndices = new List<List<int>>();
            if (nbExistingPaths >= maxNbPaths) { return; }

            List<int> path = new List<int>() { oriIndex };
            int pathCount = 0;
            switch (criteria)
            {
                case Criteria.NoCriteria: noCondition(graph, maxNbPaths - nbExistingPaths, base.lstNodeIndices, path, ref pathCount, oriIndex, desIndex, oriIndex, 0); break;
                case Criteria.SingleCriterion: singleCondition(graph, maxNbPaths - nbExistingPaths, base.lstNodeIndices, path, ref pathCount, oriIndex, desIndex, oriIndex); break;
                case Criteria.DoubleCriteria: doubleCondition(graph, maxNbPaths - nbExistingPaths, base.lstNodeIndices, path, ref pathCount, oriIndex, desIndex, oriIndex); break;
            }
            if (keepTime) { stopTimer(); }
        }

        #region DOUBLE CRITERIA
        private void doubleCondition(Graph graph, int nbPathsToGenerate, List<List<int>> lst, List<int> path, ref int pathCount, int s, int t, int i)
        {
            Node node = graph.getNode(i);
            foreach (int a in node.getOutArcIndices())
            {
                if (pathCount >= nbPathsToGenerate) { return; }
                U.Graph.Arc arc = graph.getArc(a);
                int j = arc.getToIndex();
                if (D[s, i] < D[s, j])
                {
                    if (D[i, t] > D[j, t])
                    {
                        path.Add(j);
                        if (j == t)
                        {
                            string str = Str.combine(path, Str.Delimiter.Dash);
                            if (!existingPathLabels.Contains(str)) { lst.Add(UList.clone(path)); addToExisting(str); pathCount += 1; }
                        }
                        else { doubleCondition(graph, nbPathsToGenerate, lst, path, ref pathCount, s, t, j); }
                        path.RemoveAt(path.Count - 1);
                    }
                }
            }
        } 
        #endregion

        #region SINGLE CRITERION
        private void singleCondition(Graph graph, int nbPathsToGenerate, List<List<int>> lst, List<int> path, ref int pathCount, int s, int t, int i)
        {
            Node node = graph.getNode(i);
            foreach (int a in node.getOutArcIndices())
            {
                if (pathCount >= nbPathsToGenerate) { return; }
                U.Graph.Arc arc = graph.getArc(a);
                int j = arc.getToIndex();
                if (D[s, i] < D[s, j])
                {
                    //if (sp.D[i, t] > sp.D[j, t])
                    {
                        path.Add(j);
                        if (j == t)
                        {
                            string str = Str.combine(path, Str.Delimiter.Dash);
                            if (!existingPathLabels.Contains(str)) { lst.Add(UList.clone(path)); addToExisting(str); pathCount += 1; }
                        }
                        else { singleCondition(graph, nbPathsToGenerate, lst, path, ref pathCount, s, t, j); }
                        path.RemoveAt(path.Count - 1);
                    }
                }
            }
        } 
        #endregion

        #region NO CRITERIA
        private void noCondition(Graph graph, int nbPathsToGenerate, List<List<int>> lst, List<int> path, ref int pathCount, int s, int t, int i, int itr)
        {
            Node node = graph.getNode(i);
            foreach (int a in node.getOutArcIndices())
            {
                int uur = 12;
                if (itr == 50) { uur = 12; }
                if (itr == 100) { uur = 12; }
                if (itr == 150) { uur = 12; }
                if (itr == 200) { uur = 12; }
                if (pathCount >= nbPathsToGenerate) { return; }
                if (path.Count >= maxNbArcs) { return; }
                U.Graph.Arc arc = graph.getArc(a);
                int j = arc.getToIndex();
                if (!path.Contains(j))
                //if (sp.D[s, i] < sp.D[s, j])
                {
                    //if (sp.D[i, t] > sp.D[j, t])
                    {
                        path.Add(j);
                        if (j == t)
                        {
                            string str = Str.combine(path, Str.Delimiter.Dash);
                            if (!existingPathLabels.Contains(str)) { lst.Add(UList.clone(path)); addToExisting(str); pathCount += 1; }
                        }
                        else { noCondition(graph, nbPathsToGenerate, lst, path, ref pathCount, s, t, j, itr + 1); }
                        path.RemoveAt(path.Count - 1);
                    }
                }
            }
        } 
        #endregion



    }
}
