using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using U.Graph.HelperMethods;
using U.ListOperations;
using U.StringOperations;

namespace U.Graph
{
    public class Path
    {
        //private string[] nodeLabels;
        //private int[] nodeIndices;
        private int[] arcIndices;
        private double flow;
        private double cost;

        private string label;

        // CONSTRUCTORS
        public Path(List<string> args)
        {
            //this.nodeLabels = GraphString.getArrString(args[0], Str.Delimiter.Semicolon);
            //this.nodeIndices = GraphString.getArrInt(args[1], Str.Delimiter.Semicolon);
            this.arcIndices = GraphString.getArrInt(args[0], Str.Delimiter.Semicolon);
            this.flow = Convert.ToDouble(args[1]);
            this.cost = Convert.ToDouble(args[2]);
        }
        public Path(Graph graph, int[] nodeIndices, double flow, double cost)
        {
            //this.nodeIndices = nodeIndices;
            calcSetArcIndices(graph, nodeIndices);
            this.flow = flow;
            this.cost = cost;
        }

        private void calcSetArcIndices(Graph graph, int[] nodeIndices)
        {
            //this.nodeLabels = new string[nodeIndices.Length];
            this.arcIndices = new int[nodeIndices.Length - 1];
            //for (int n = 0; n < nodeIndices.Length; n++) { nodeLabels[n] = graph.getNode(nodeIndices[n]).getLabel(); }
            for (int n = 1; n < nodeIndices.Length; n++)
            {
                int from = nodeIndices[n - 1]; int to = nodeIndices[n];
                arcIndices[n - 1] = graph.getIncidenceMatrix()[from, to];
            }
        }
        internal void calcSetLabel(Graph graph)
        {
            this.label = graph.getNode(graph.getArc(arcIndices[0]).getFromIndex()).getLabel();
            for (int i = 0; i < arcIndices.Length; i++) { this.label = this.label + "-" + graph.getNode(graph.getArc(arcIndices[i]).getToIndex()).getLabel(); }
        }




        // to delete
        public Path(string strPath)
        {
            StrFunc sf = new StrFunc(strPath);
            List<string> lst = Str.split(sf.getFuncName(), Str.Delimiter.Dash);
            if (lst.Count < 2) { throw new InvalidPathException(strPath); }
            if (sf.getArgs().Count < 2) { throw new InvalidPathException(strPath); }
            //this.nodeLabels = UArray.toArray(lst);
            this.flow = sf.getArgDouble(0);
            this.cost = sf.getArgDouble(1);
        }


        // SETTERS
        public void setFlow(double flow) { this.flow = flow; }
        public void setCost(double cost) { this.cost = cost; }
        public void setArcIndices(int[] arcIndices) { this.arcIndices = arcIndices; }
        //public void setNodeIndices(int[] nodeIndices) { this.nodeIndices = nodeIndices; }

        // GETTERS
        //public string[] getNodeLabels() { return this.nodeLabels; }
        //public string getOriLabel() { return this.nodeLabels[0]; }
        //public string getDesLabel() { return this.nodeLabels[nodeLabels.Length - 1]; }
        public int[] getArcIndices() { return this.arcIndices; }
        public int getArcIndex(int index) { return this.arcIndices[index]; }
        public int[] getNodeIndices(Graph graph)
        {
            int[] nodeIndices = new int[this.arcIndices.Length - 1];
            nodeIndices[0] = graph.getArc(arcIndices[0]).getFromIndex();
            for (int i = 0; i < arcIndices.Length; i++) { nodeIndices[i + 1] = graph.getArc(arcIndices[i]).getToIndex(); }
            return nodeIndices;
        }
        //public int getOriIndex() { return this.nodeIndices[0]; }
        //public int getDesIndex() { return this.nodeIndices[this.nodeIndices.Length - 1]; }
        public double getCost() { return this.cost; }
        public double getFlow() { return this.flow; }

        // COMMON
        public string getLabel() { return this.label; }
        public override string ToString()
        {
            List<double> args = new List<double>() { this.flow, this.cost };
            return StrFunc.getFuncString(getLabel(), args);
        }
        public bool Equals(Path path) { return this.label == path.getLabel(); }
        public Path clone(Path path) { return null; }//TODO

        // EXCEPTIONS
        public class InvalidPathException : Exception { public InvalidPathException(string message) : base("Invalid path: " + message + ".") { } }

    }
}
