using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using U.ListOperations;
using U.StringOperations;
using U.SUE.Algorithms.MSAClasses;
using U.SUE.Helpers;

namespace U.SUE
{
    public class Graph : U.Graph.Graph
    {
        OdPair[] odPairs;

        #region CONSTRUCTORS
        public Graph(Node[] nodes, Link[] links, Path[] paths, OdPair[] odPairs)
            : base(nodes, links, paths)
        {
            this.odPairs = odPairs;
            GraphValidity.check(this);
            GraphInitialization.initialize(this);
            base.setPathLabels();
        }
        public Graph(string sueFilepath)
        {
            List<string> args = GraphString.getArgsFromSueFile(sueFilepath);
            base.setNodes(GraphString.getNodes(args[0]));
            base.setArcs(GraphString.getLinks(args[1]));
            base.setPaths(GraphString.getPaths(args[2]));
            this.odPairs = GraphString.getOdPairs(args[3]);
            base.createIncidenceMatrix();
            base.setPathLabels();
        }
        public Graph(List<string> args)
        {
            //base.setIncidenceMatrix(GraphString.getIncidenceMatrix(args[0]));
            base.setNodes(GraphString.getNodes(args[0]));
            base.setArcs(GraphString.getLinks(args[1]));
            base.setPaths(GraphString.getPaths(args[2]));
            this.odPairs = GraphString.getOdPairs(args[3]);
            base.createIncidenceMatrix();
            base.setPathLabels();
        } 
        #endregion

        // SETTERS
        public void insertPaths(List<List<List<int>>> odLstNodeIndices) { PathInsertion.add(this, odLstNodeIndices); }
        //public void insertPaths(List<List<int>> lstNodeIndices, bool checkExistence) { PathInsertion.add(this, lstNodeIndices, checkExistence); }
        public void clearPaths() { PathDeletion.clearAll(this); }


        // GETTERS
        public new Node[] getNodes() { return (Node[])base.getNodes(); }
        public new Node getNode(int index) { return getNodes()[index]; }
        public Link[] getLinks() { return (Link[])base.getArcs(); }
        public Link getLink(int index) { return getLinks()[index]; }
        public new Path[] getPaths() { return (Path[])base.getPaths(); }
        public new Path getPath(int index) { return getPaths()[index]; }
        public OdPair[] getOdPairs() { return this.odPairs; }
        public OdPair getOdPair(int index) { return getOdPairs()[index]; }
        public int getOdPairIndexByLabel(string label) { for (int i = 0; i < this.odPairs.Length; i++) { if (this.odPairs[i].getLabel() == label) { return i; } } return -1; }
        public int getNbOdPairs() { return this.odPairs.Length; }


        // OVERRIDE
        public override string ToString()
        {
            return UGrToStr.graphToString(this);
            /*
            List<string> lst = new List<string>();
            lst.Add(Str.inParenthesis(UList.toList(getNodes()), Str.ParenthesisTypes.Square, Str.Delimiter.Semicolon));
            lst.Add(Str.inParenthesis(UList.toList(getLinks()), Str.ParenthesisTypes.Square, Str.Delimiter.Semicolon));
            lst.Add(Str.inParenthesis(UList.toList(getPaths()), Str.ParenthesisTypes.Square, Str.Delimiter.Semicolon));
            lst.Add(Str.inParenthesis(UList.toList(getOdPairs()), Str.ParenthesisTypes.Square, Str.Delimiter.Semicolon));
            return Str.inParenthesis(lst, Str.ParenthesisTypes.Regular, Str.Delimiter.Comma);//*/
        }
        public override List<string> toArgs() { return GraphString.toArgs(this); }
        public override string toString() { return GraphString.toString(this); }


        // INTERNAL
        internal void setPaths(Path[] paths) { base.setPaths(paths); }


        // MSA
        public void initializeForMsa() { BoundsForMDM.set(this); foreach (Link link in getLinks()) { link.setFlow(0.0); } foreach (Path path in getPaths()) { path.setFlow(0.0); path.setProb(0.0); path.setFlow(0.0); } }
        public void calcLinkCostsAdd() { foreach (Link link in getLinks()) { link.calcCostAdd(); } }
        public void calcLinkCostsMul() { foreach (Link link in getLinks()) { link.calcCostMul(); } }
        public void calcPathCosts() { foreach (OdPair od in getOdPairs()) { od.calcPathCosts(getPaths(), getLinks()); } }
        public void performTrafficAssignment()
        {
            foreach (OdPair od in odPairs) { od.calcProbsFlows(getPaths()); }
            foreach (Link link in getLinks()) { link.setFlow(0.0); }
            foreach (Path path in getPaths()) { foreach (int a in path.getArcIndices()) { getLink(a).setFlow(getLink(a).getFlow() + path.getFlow()); } }
        }
        public double[] getLinkFlowArray()
        {
            double[] F = new double[getLinks().Length];
            for (int a = 0; a < getLinks().Length; a++) { F[a] = getLink(a).getFlow(); }
            return F;
        }
        public void setLinkFlows(double[] F) { for (int a = 0; a < F.Length; a++) { getLink(a).setFlow(F[a]); } }


    }
}
