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

namespace U.SUE
{
    public class Link : U.Graph.Arc
    {
        private LinkCost linkCost;
        private double costAdd;
        private double costMul;


        // CONSTRUCTORS
        public Link(string fromLabel, string toLabel, double freeFlowTravelTime, double B, double capacity, double power, double toll, double tollFactor, double length, double distanceFactor, double exponentialCoefficient) : base(fromLabel, toLabel) { setLinkCost(freeFlowTravelTime, B, capacity, power, toll, tollFactor, length, distanceFactor, exponentialCoefficient); }
        public Link(List<string> args) : base(args)
        {
            double fftt = Str.toDouble(args[6]);
            double b = Str.toDouble(args[7]);
            double capacity = Str.toDouble(args[8]);
            double power = Str.toDouble(args[9]);
            double toll = Str.toDouble(args[10]);
            double tollFac = Str.toDouble(args[11]);
            double length = Str.toDouble(args[12]);
            double distFac = Str.toDouble(args[13]);
            double expCoef = Str.toDouble(args[14]);
            this.linkCost = new LinkCost(fftt, b, capacity, power, toll, tollFac, length, distFac, expCoef);
            this.costAdd = Str.toDouble(args[15]);
            this.costMul = Str.toDouble(args[16]);
        }

        // to delete
        public Link(string strLink) : base(strLink)
        {
            StrFunc sf = new StrFunc(strLink);
            if (sf.getNbArgs() != 11) { throw new InvalidLinkException(strLink); }
            if (!Str.isNumeric(sf.getArgs())) { throw new InvalidLinkException(strLink); }
            List<double> lst = Str.toDouble(sf.getArgs());
            setLinkCost(lst[2], lst[3], lst[4], lst[5], lst[6], lst[7], lst[8], lst[9], lst[10]);

            this.costAdd = this.linkCost.getBPRCost(base.getFlow());
            this.costMul = this.linkCost.getBPRCostExponential(base.getFlow());
        }



        // SETTERS
        public void setLinkCost(LinkCost linkCost) { this.linkCost = linkCost; }
        public void setFreeFlowTravelTime(double freeFlowTravelTime) { this.linkCost.setFreeFlowTravelTime(freeFlowTravelTime); }

        // GETTERS
        public double getLength() { return this.linkCost.getLength(); }
        public double getCostAdd() { return this.costAdd; }
        public double getCostMul() { return this.costMul; }
        public LinkCost getLinkCost() { return this.linkCost; }




        // CALCULATORS
        public void calcCostAdd() { this.costAdd = this.linkCost.getBPRCost(base.getFlow()); }
        public void calcCostMul() { this.costMul = this.linkCost.getBPRCostExponential(base.getFlow()); }



        // COMMON
        public override string ToString()
        {
            List<string> args = new List<string>()
            {
                getFlow().ToString(), getCost().ToString(),
                linkCost.getFreeFlowTravelTime().ToString(), linkCost.getB().ToString(),
                linkCost.getCapacity().ToString(), linkCost.getPower().ToString(),
                linkCost.getToll().ToString(), linkCost.getTollFactor().ToString(),
                linkCost.getLength().ToString(), linkCost.getDistanceFactor().ToString(),
                linkCost.getExponentialCoefficient().ToString()
            };
            //List<string> args = new List<string>() { base.getFlow().ToString(), base.getCost().ToString(), this.linkCost.ToString() };
            return StrFunc.getFuncString(getLabel(), args);
        }
        public bool Equals(Link link) { return base.getLabel() == link.getLabel(); }
        


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



        // Private Constructor
        private void setLinkCost(double freeFlowTravelTime, double B, double capacity, double power, double toll, double tollFactor, double length, double distanceFactor, double exponentialCoefficient)
        {
            this.linkCost = new LinkCost(freeFlowTravelTime, B, capacity, power, toll, tollFactor, length, distanceFactor, exponentialCoefficient);
        }
    }
}
