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

namespace Algorithms.Nw
{
    public class DialsMethod : PathGenerationAlgorithm
    {
        public enum Condition { NoCondition, SingleCondition, DoubleCondition };

        private Condition condition;
        private int edgeLimit;
        private int pathLimit;
        private ShortestPathAllPairsAlgorithm apspa;

        public DialsMethod(Condition condition, int edgeLimit, int pathLimit, ShortestPathAllPairsAlgorithm allPairsSpAlgorithm, bool keepExistingPaths)
            : base(keepExistingPaths)
        {
            this.condition = condition;
            this.edgeLimit = edgeLimit;
            this.pathLimit = pathLimit;
            this.apspa = allPairsSpAlgorithm;
        }


        public override void generate(Graph graph, bool keepTime, bool performPathAttributeCalculations)
        {
            /*
            if (keepTime) { base.startTimer(); }
            apspa.calculate(graph, false);
            double[,] D = apspa.getDistanceMatrix();
            int[,] P = apspa.getPredecessorMatrix();
            OdPair[] odArray = graph.getOdPairs();
            foreach (OdPair od in odArray)
            {
                List<Path> pathList = new List<Path>();
                int o = od.getOriIndex();
                int d = od.getDesIndex();
                List<int> edgeIndices = new List<int>();
                int[] visitedNodes = UArray.sameValues<int>(0, graph.getNbNodes());
                visitedNodes[o] = 1;
                switch (condition)
                {
                    case Condition.NoCondition: mainStepNoCondition(graph, pathList, o, d, o, edgeIndices, visitedNodes); break;
                    case Condition.SingleCondition: mainStepSingleCondition(graph, pathList, o, d, o, edgeIndices, visitedNodes, D); break;
                    case Condition.DoubleCondition: mainStepDoubleCondition(graph, pathList, o, d, o, edgeIndices, visitedNodes, D); break;
                }
                if (pathList.Count == 0)
                {
                    List<int> spEdges = ShortestPathAllPairsAlgorithm.getShortestPathAsEdgeIndices(graph, o, d, P);
                    if (spEdges.Count == 0) { int uur = 12; }
                    else { pathList.Add(new Path(UArray.toArray(spEdges), o, d)); }
                }
                od.setPaths(new Paths(pathList.ToArray()));
            }
            if (keepTime) { base.stopTimer(); }
            if (performPathAttributeCalculations) { graph.performPathAttributeCalculations(); }
            //*/
        }
        // Main Step - Double Condition
        private void mainStepDoubleCondition(Graph graph, List<Path> pathList, int o, int d, int i, List<int> edgeIndices, int[] visitedNodes, double[,] D)
        {
            /*
            if (edgeIndices.Count == edgeLimit) { return; }
            if (pathList.Count == pathLimit) { return; }
            Vertex current = graph.getVertex(i);
            foreach (int edgeIndex in current.getOutEdgeIndices())
            {
                Edge edge = graph.getEdge(edgeIndex);
                int j = edge.getToIndex();
                //if (visitedNodes[j] == 1) { return; } // Cycle observed
                if (D[o, i] < D[o, j])
                {
                    if (D[i, d] > D[j, d])
                    {
                        edgeIndices.Add(edge.getIndex()); // Forward
                        visitedNodes[j] = 1; // Forward
                        if (j == d) { pathList.Add(new Path(UArray.toArray(edgeIndices), o, d)); }
                        else { mainStepDoubleCondition(graph, pathList, o, d, j, edgeIndices, visitedNodes, D); }
                        edgeIndices.RemoveAt(edgeIndices.Count - 1); // Backward
                        visitedNodes[j] = 0; // Backward
                    }
                }
            }//*/
        }
        // Main Step - Single Condition
        private void mainStepSingleCondition(Graph graph, List<Path> pathList, int o, int d, int i, List<int> edgeIndices, int[] visitedNodes, double[,] D)
        {
            /*
            if (edgeIndices.Count == edgeLimit) { return; }
            if (pathList.Count == pathLimit) { return; }
            Vertex current = graph.getVertex(i);
            foreach (int edgeIndex in current.getOutEdgeIndices())
            {
                Edge edge = graph.getEdge(edgeIndex);
                int j = edge.getToIndex();
                //if (visitedNodes[j] == 1) { return; } // Cycle observed
                if (D[o, i] < D[o, j])
                {
                    edgeIndices.Add(edge.getIndex()); // Forward
                    visitedNodes[j] = 1; // Forward
                    if (j == d) { pathList.Add(new Path(UArray.toArray(edgeIndices), o, d)); }
                    else { mainStepSingleCondition(graph, pathList, o, d, j, edgeIndices, visitedNodes, D); }
                    edgeIndices.RemoveAt(edgeIndices.Count - 1); // Backward
                    visitedNodes[j] = 0; // Backward
                }
            }//*/
        }
        // Main Step - No Condition
        private void mainStepNoCondition(Graph graph, List<Path> pathList, int o, int d, int i, List<int> edgeIndices, int[] visitedNodes)
        {
            /*
            if (edgeIndices.Count == edgeLimit) { return; }
            if (pathList.Count == pathLimit) { return; }
            Vertex current = graph.getVertex(i);
            foreach (int edgeIndex in current.getOutEdgeIndices())
            {
                Edge edge = graph.getEdge(edgeIndex);
                int j = edge.getToIndex();
                //if (visitedNodes[j] == 1) { return; } // Cycle observed
                edgeIndices.Add(edge.getIndex()); // Forward
                visitedNodes[j] = 1; // Forward
                if (j == d) { pathList.Add(new Path(UArray.toArray(edgeIndices), o, d)); }
                else { mainStepNoCondition(graph, pathList, o, d, j, edgeIndices, visitedNodes); }
                edgeIndices.RemoveAt(edgeIndices.Count - 1); // Backward
                visitedNodes[j] = 0; // Backward
            }//*/
        }
    }
}
