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

namespace Algorithms.Nw
{
    public class LinkPenalty : PathGenerationAlgorithm
    {
        private int pathLimit;
        private ShortestPathAlgorithm spa;
        private double penalty; // if 0.05 means that fftt of 100 will be 105
        private int iterationPerOdLimit;

        public LinkPenalty(int pathLimit, double penalty, int iterationPerOdLimit, ShortestPathAlgorithm shortestPathAlgorithm, bool keepExistingPaths)
            : base(keepExistingPaths)
        {
            this.pathLimit = pathLimit;
            this.iterationPerOdLimit = iterationPerOdLimit;
            this.spa = shortestPathAlgorithm;
            this.penalty = penalty;
        }

        public override void generate(Graph graph, bool keepTime, bool performPathAttributeCalculations)
        {
            /*
            if (pathLimit < 1) { return; }
            if (keepTime) { base.startTimer(); }
            OdPair[] odArray = graph.getOds().getArray();
            int V = graph.getNbVertices();
            SubGraph subGraph = new SubGraph(V);
            foreach (OdPair od in odArray)
            {
                bool cs = true;
                Graph g = graph.clone();
                List<List<int>> pathsAsVertices = new List<List<int>>();
                List<string> pathsStrings = new List<string>();
                if (base.doKeepExistingPaths())
                {
                    pathsAsVertices = g.getOdPathsList(od, Path.RepresentationType.VertexIndices);
                    pathsStrings = g.getOdPathStringList(od, Path.RepresentationType.VertexIndices);
                    foreach (List<int> vertexIndices in pathsAsVertices) { penalizeLinks(g, vertexIndices); }
                }
                int s = od.getOriginIndex();
                int t = od.getDestIndex();
                g.updateAdditiveEdgeCosts();
                this.spa.calculate(g, subGraph, s, t, false);
                List<int> spAsVertices0 = this.spa.getShortestPathAsVertexIndices(s, t);
                if (spAsVertices0 == null) { cs = false; }
                else
                {
                    pathsAsVertices.Add(spAsVertices0);
                    pathsStrings.Add(Path.toString(spAsVertices0));
                    penalizeLinks(g, spAsVertices0);
                }
                int iterationCounter = 0;
                while (iterationCounter < iterationPerOdLimit && pathsAsVertices.Count < pathLimit && cs)
                {
                    iterationCounter += 1;
                    this.spa.calculate(g, subGraph, s, t, false);
                    List<int> spAsVertices = this.spa.getShortestPathAsVertexIndices(s, t);
                    if (spAsVertices == null) { iterationCounter = iterationPerOdLimit + 1; }
                    else
                    {
                        penalizeLinks(g, spAsVertices);
                        string pathStr = Path.toString(spAsVertices);
                        if (!pathsStrings.Contains(pathStr))
                        {
                            pathsStrings.Add(pathStr);
                            pathsAsVertices.Add(spAsVertices);
                        }
                    }
                }
                updatePaths(graph, od, pathsAsVertices);
                g.clear();
            }
            if (keepTime) { base.stopTimer(); }
            if (performPathAttributeCalculations) { graph.performPathAttributeCalculations(); }//*/
        }


        private void penalizeLinks(Graph g, List<int> vertexIndices)
        {
            /*
            for (int i = 1; i < vertexIndices.Count; i++)
            {
                int ori = vertexIndices[i - 1];
                int des = vertexIndices[i];
                Edge edge = g.getEdge(ori, des);
                edge.setFreeFlowTravelTime(edge.getFreeFlowTravelTime() * (1 + this.penalty));
            }
            g.updateAdditiveEdgeCosts();//*/
        }


        private void updatePaths(Graph graph, OdPair od, List<List<int>> pathsAsVertices)
        {
            /*
            Path[] pathArray = new Path[pathsAsVertices.Count];
            Vertices vertices = graph.getVertices();
            for (int p = 0; p < pathsAsVertices.Count; p++)
            {
                List<int> vertexIndices = pathsAsVertices[p];
                int originIndex = vertexIndices[0];
                int destIndex = vertexIndices[vertexIndices.Count - 1];
                int[] edgeIndices = new int[vertexIndices.Count - 1];
                for (int i = 1; i < vertexIndices.Count; i++)
                {
                    int ori = vertexIndices[i - 1];
                    int des = vertexIndices[i];
                    int edgeIndex = graph.getEdge(ori, des).getIndex();
                    edgeIndices[i - 1] = edgeIndex;
                }
                pathArray[p] = new Path(edgeIndices, originIndex, destIndex);
            }
            od.setPaths(new Paths(pathArray));//*/
        }
    }
}
