using Algorithms.Nw.PathGeneration;
using Algorithms.Nw.ShortestPath;
using Algorithms.Nw.ShortestPathAllPairs;
using SeSue.Forms.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using U.SUE;

namespace SeSue.Forms.PathGeneration
{
    class PgaInitializer
    {
        internal static double runTime;

        #region DIALS
        public static PGA getDialsPga(Graph graph, int w, int h, int top, int left)
        {
            PGA pga = new PGA();
            pga.Text = "Path Generation by Dial's Algorithm";
            if (Program.sueForm.WindowState != FormWindowState.Maximized) { pga.Width = w; pga.Height = h; pga.Top = top; pga.Left = left; }
            pga.lblOd.Text = "The algorithm generates 'efficient' paths with respect to the criteria proposed by Dial, R.B. (1971).";
            List<string> condItems = new List<string>() { "Double Criteria", "Single Criterion", "No Criteria" };
            List<string> condLabels = new List<string>()
            {
                "Each arc in the path takes the traveler further away from the O and closer to the D",
                "Each arc in the path takes the traveler further away from the O.",
                "No criteria on the paths (enumeration of acyclic paths)."
            };
            CbAndLabel conditions = new CbAndLabel("conditions", condItems, 0, condLabels);
            pga.splitContainer2.Panel1.Controls.Add(conditions);

            List<string> spapaItems = new List<string>() { "Floyd-Warshall Algorithm (Floyd, R. W. (1962), Warshall, S. (1962))", "Dijkstra's Algorithm for all node pairs (Dijkstra, E. W. (1959))" };
            List<string> spapaLabels = new List<string>()
            {
                "Selected algorithm will be used to calculate shortest distances between all node pairs for evaluating Dial's criteria.",
                "Selected algorithm will be used to calculate shortest distances between all node pairs for evaluating Dial's criteria.",
            };
            CbAndLabel spapas = new CbAndLabel("spapas", spapaItems, 0, spapaLabels);
            pga.splitContainer3.Panel1.Controls.Add(spapas);

            TbAndLabel arcLim = new TbAndLabel("arcLim", "Maximum number of arcs per path (used only for 'no criteria' option).", "100", System.Windows.Forms.HorizontalAlignment.Right, typeof(int), TbAndLabel.NumberCondition.Positive);
            pga.splitContainer4.Panel1.Controls.Add(arcLim);

            commonControls(pga);
            pga.btnRun.Click += new EventHandler(runDials);
            return pga;
        }
        private static void runDials(object sender, EventArgs e)
        {
            Button btn = (Button)sender;
            PGA pga = (PGA)btn.FindForm();

            bool keepPaths = pga.chbKeepExisting.Checked;
            if (!keepPaths) { SueForm.sue.graph.clearPaths(); }

            Dials.Criteria crit = Dials.Criteria.DoubleCriteria;
            CbAndLabel conditions = (CbAndLabel)pga.splitContainer2.Panel1.Controls["conditions"];
            if (conditions.selectedIndex() == 1) { crit = Dials.Criteria.SingleCriterion; }
            else if (conditions.selectedIndex() == 2) { crit = Dials.Criteria.NoCriteria; }

            ShortestPathAllPairsAlgorithm spapa = new FloydWarshall();
            CbAndLabel spapas = (CbAndLabel)pga.splitContainer3.Panel1.Controls["spapas"];
            if (spapas.selectedIndex() == 1) { spapa = new DijkstraAllPairs(); }

            TbAndLabel pathLimTb = (TbAndLabel)pga.splitContainer7.Panel2.Controls["pathLim"];
            int pathLim = Convert.ToInt16(pathLimTb.getText());

            TbAndLabel arcLimTb = (TbAndLabel)pga.splitContainer4.Panel1.Controls["arcLim"];
            int arcLim = Convert.ToInt16(arcLimTb.getText());


            double[] arcCosts = new double[SueForm.sue.graph.getNbArcs()];
            for (int a = 0; a < SueForm.sue.graph.getNbArcs(); a++) { arcCosts[a] = SueForm.sue.graph.getArc(a).getCost(); }
            for (int a = 0; a < SueForm.sue.graph.getNbArcs(); a++) { SueForm.sue.graph.getArc(a).setCost(SueForm.sue.graph.getLink(a).getLinkCost().getFreeFlowTravelTime()); }

            List<object> args0 = new List<object>() { spapa, SueForm.sue.graph };
            string algText = "Floyd - Warshall algorithm is running.";
            if (spapas.selectedIndex() == 1) { algText = "Dijkstra (all pairs) algorithm is running."; }
            pga.bgwAllPairsSp.RunWorkerAsync(args0); Progress.setText(algText); Progress.show(pga);
            
            //spapa.run(SueForm.sue.graph, false);
            double[,] D = spapa.getDistanceMatrix();
            PathGenerationAlgorithm alg = new Dials(crit, D, arcLim);

            List<object> args = new List<object>() { alg, pathLim };
            pga.bgwPga.RunWorkerAsync(args); Progress.setText("Initializing."); Progress.show(pga);

            for (int a = 0; a < SueForm.sue.graph.getNbArcs(); a++) { SueForm.sue.graph.getArc(a).setCost(arcCosts[a]); }
            afterAfterRun();
            string afterRunMsg = "Running time of (all pairs) shortest path algorithm is " + spapa.getMiliseconds().ToString("#,###,##0") + " miliseconds.";
            afterRunMsg = afterRunMsg + Environment.NewLine + "Running time is " + runTime.ToString("#,###,##0") + " miliseconds.";
            Msg.show("Dial's Algorithm.", afterRunMsg, pga);
        } 
        #endregion

        #region YENS
        public static PGA getYensPga(Graph graph, int w, int h, int top, int left)
        {
            PGA pga = new PGA();
            pga.Text = "Path Generation by Yen's Algorithm";
            if (Program.sueForm.WindowState != FormWindowState.Maximized) { pga.Width = w; pga.Height = h; pga.Top = top; pga.Left = left; }
            pga.lblOd.Text = "The algorithm proposed by Yen, J.Y. (1971) generates K shortest paths with respect to the free flow travel times.";
            List<string> spaItems = new List<string>() { "Dijkstra's Algorithm (Dijkstra, E. W. (1959))" };
            List<string> spaLabels = new List<string>()
            {
                "Selected shortest path algorithm will be used at each iteration of Yen's K-shortest path algorithm.",
            };
            CbAndLabel spas = new CbAndLabel("spas", spaItems, 0, spaLabels);
            pga.splitContainer2.Panel1.Controls.Add(spas);

            commonControls(pga);
            pga.btnRun.Click += new EventHandler(runYens);
            return pga;
        }
        private static void runYens(object sender, EventArgs e)
        {
            Button btn = (Button)sender;
            PGA pga = (PGA)btn.FindForm();

            bool keepPaths = pga.chbKeepExisting.Checked;
            if (!keepPaths) { SueForm.sue.graph.clearPaths(); }

            ShortestPathAlgorithm spa = new Dijkstra(); // update here if new SP algorithms are added

            TbAndLabel pathLimTb = (TbAndLabel)pga.splitContainer7.Panel2.Controls["pathLim"];
            int pathLim = Convert.ToInt16(pathLimTb.getText());

            PathGenerationAlgorithm alg = new Yens(spa);

            List<object> args = new List<object>() { alg, pathLim };
            pga.bgwPga.RunWorkerAsync(args);
            Progress.show(pga);

            afterAfterRun();
            Msg.show("Yen's Algorithm.", "Running time is " + runTime.ToString("#,###,##0") + " miliseconds.", pga);
        } 
        #endregion

        #region LINK ELIMINATION
        public static PGA getLinkEliminationPga(Graph graph, int w, int h, int top, int left)
        {
            PGA pga = new PGA();
            pga.Text = "Path Generation by Link Elimination Algorithm";
            if (Program.sueForm.WindowState != FormWindowState.Maximized) { pga.Width = w; pga.Height = h; pga.Top = top; pga.Left = left; }
            pga.lblOd.Text = "The algorithm proposed by Azevedo, J.A. et al. (1993) generates paths by successively eliminating shortest path links.";
            List<string> spaItems = new List<string>() { "Dijkstra's Algorithm (Dijkstra, E. W. (1959))" };
            List<string> spaLabels = new List<string>()
            {
                "Selected shortest path algorithm will be used at each iteration of the link elimination algorithm.",
            };
            CbAndLabel spa = new CbAndLabel("spas", spaItems, 0, spaLabels);
            pga.splitContainer2.Panel1.Controls.Add(spa);
            pga.btnRun.Click += new EventHandler(runLE);
            commonControls(pga);
            return pga;
        }
        private static void runLE(object sender, EventArgs e)
        {
            Button btn = (Button)sender;
            PGA pga = (PGA)btn.FindForm();

            bool keepPaths = pga.chbKeepExisting.Checked;
            if (!keepPaths) { SueForm.sue.graph.clearPaths(); }

            ShortestPathAlgorithm spa = new Dijkstra(); // update here if new SP algorithms are added

            TbAndLabel pathLimTb = (TbAndLabel)pga.splitContainer7.Panel2.Controls["pathLim"];
            int pathLim = Convert.ToInt16(pathLimTb.getText());

            PathGenerationAlgorithm alg = new LinkElimination(spa);

            List<object> args = new List<object>() { alg, pathLim };
            pga.bgwPga.RunWorkerAsync(args);
            Progress.show(pga);

            afterAfterRun();
            Msg.show("Link Elimination Algorithm.", "Running time is " + runTime.ToString("#,###,##0") + " miliseconds.", pga);
        } 
        #endregion

        #region LINK PENALTY
        public static PGA getLinkPenaltyPga(Graph graph, int w, int h, int top, int left)
        {
            PGA pga = new PGA();
            pga.Text = "Path Generation by Link Penalty Algorithm";
            if (Program.sueForm.WindowState != FormWindowState.Maximized) { pga.Width = w; pga.Height = h; pga.Top = top; pga.Left = left; }
            pga.lblOd.Text = "The algorithm proposed by De La Barra, T. et al. (1993) generates paths by successively penalizing shortest path links.";
            List<string> spaItems = new List<string>() { "Dijkstra's Algorithm (Dijkstra, E. W. (1959))" };
            List<string> spaLabels = new List<string>()
            {
                "Selected shortest path algorithm will be used at each iteration of the link penalty algorithm.",
            };
            CbAndLabel spa = new CbAndLabel("spas", spaItems, 0, spaLabels);
            pga.splitContainer2.Panel1.Controls.Add(spa);

            TbAndLabel penalty = new TbAndLabel("penalty", "Penalty (link cost of 100 becomes 105 with a penalty of 0.05)", "0.05", System.Windows.Forms.HorizontalAlignment.Right, typeof(double), TbAndLabel.NumberCondition.Positive);
            pga.splitContainer3.Panel1.Controls.Add(penalty);

            TbAndLabel iterLim = new TbAndLabel("iterLim", "Maximum number of iterations per OD pair.", "1000", System.Windows.Forms.HorizontalAlignment.Right, typeof(int), TbAndLabel.NumberCondition.Positive);
            pga.splitContainer4.Panel1.Controls.Add(iterLim);
            pga.btnRun.Click += new EventHandler(runLP);
            commonControls(pga);
            return pga;
        }
        private static void runLP(object sender, EventArgs e)
        {
            Button btn = (Button)sender;
            PGA pga = (PGA)btn.FindForm();

            bool keepPaths = pga.chbKeepExisting.Checked;
            if (!keepPaths) { SueForm.sue.graph.clearPaths(); }

            ShortestPathAlgorithm spa = new Dijkstra(); // update here if new SP algorithms are added

            TbAndLabel penaltyTb = (TbAndLabel)pga.splitContainer3.Panel1.Controls["penalty"];
            double penalty = Convert.ToDouble(penaltyTb.getText());

            TbAndLabel iterLimTb = (TbAndLabel)pga.splitContainer4.Panel1.Controls["iterLim"];
            long iterLim = Convert.ToInt64(iterLimTb.getText());

            TbAndLabel pathLimTb = (TbAndLabel)pga.splitContainer7.Panel2.Controls["pathLim"];
            int pathLim = Convert.ToInt16(pathLimTb.getText());

            PathGenerationAlgorithm alg = new LinkPenalty(spa, penalty, iterLim);

            List<object> args = new List<object>() { alg, pathLim };
            pga.bgwPga.RunWorkerAsync(args);
            Progress.show(pga);

            afterAfterRun();
            Msg.show("Link Penalty Algorithm.", "Running time is " + runTime.ToString("#,###,##0") + " miliseconds.", pga);
        } 
        #endregion

        #region LINK PENALTY >> LINK ELIMINATION
        public static PGA getLinkPenElimPga(Graph graph, int w, int h, int top, int left)
        {
            PGA pga = new PGA();
            pga.Text = "Path Generation by Link Penalty Algorithm followed by Link Elimination Algorithm";
            if (Program.sueForm.WindowState != FormWindowState.Maximized) { pga.Width = w; pga.Height = h; pga.Top = top; pga.Left = left; }
            pga.lblOd.Text = "The algorithm sequentially runs link penalty (De La Barra, T. et al. (1993)) and link elimination (Azevedo, J.A. et al. (1993)) algorithms.";
            List<string> spaItems = new List<string>() { "Dijkstra's Algorithm (Dijkstra, E. W. (1959))" };
            List<string> spaLabels = new List<string>()
            {
                "Selected shortest path algorithm will be used at each iteration of link penalty and link elimination algorithms.",
            };
            CbAndLabel spa = new CbAndLabel("spas", spaItems, 0, spaLabels);
            pga.splitContainer2.Panel1.Controls.Add(spa);

            TbAndLabel penalty = new TbAndLabel("penalty", "Penalty (link cost of 100 becomes 105 with a penalty of 0.05)", "0.05", System.Windows.Forms.HorizontalAlignment.Right, typeof(double), TbAndLabel.NumberCondition.Positive);
            pga.splitContainer3.Panel1.Controls.Add(penalty);

            TbAndLabel iterLim = new TbAndLabel("iterLim", "Maximum number of iterations per OD pair for link penalty algorithm.", "1000", System.Windows.Forms.HorizontalAlignment.Right, typeof(int), TbAndLabel.NumberCondition.Positive);
            pga.splitContainer4.Panel1.Controls.Add(iterLim);

            TbAndLabel perc = new TbAndLabel("perc", "Limit on the fraction of the paths that will be generated by link penalty algorithm", "0.5", System.Windows.Forms.HorizontalAlignment.Right, typeof(double), TbAndLabel.NumberCondition.Positive);
            pga.splitContainer5.Panel1.Controls.Add(perc);
            pga.btnRun.Click += new EventHandler(runLPLE);
            commonControls(pga);
            return pga;
        }
        private static void runLPLE(object sender, EventArgs e)
        {
            Button btn = (Button)sender;
            PGA pga = (PGA)btn.FindForm();

            bool keepPaths = pga.chbKeepExisting.Checked;
            if (!keepPaths) { SueForm.sue.graph.clearPaths(); }

            ShortestPathAlgorithm spa = new Dijkstra(); // update here if new SP algorithms are added

            TbAndLabel penaltyTb = (TbAndLabel)pga.splitContainer3.Panel1.Controls["penalty"];
            double penalty = Convert.ToDouble(penaltyTb.getText());

            TbAndLabel iterLimTb = (TbAndLabel)pga.splitContainer4.Panel1.Controls["iterLim"];
            long iterLim = Convert.ToInt64(iterLimTb.getText());

            TbAndLabel percTb = (TbAndLabel)pga.splitContainer5.Panel1.Controls["perc"];
            double perc = Convert.ToDouble(percTb.getText());

            TbAndLabel pathLimTb = (TbAndLabel)pga.splitContainer7.Panel2.Controls["pathLim"];
            int pathLim = Convert.ToInt16(pathLimTb.getText());

            PathGenerationAlgorithm alg = new LinkPenaltyThenElimination(spa, penalty, iterLim, perc);

            List<object> args = new List<object>() { alg, pathLim };
            pga.bgwPga.RunWorkerAsync(args);
            Progress.show(pga);

            afterAfterRun();
            Msg.show("Link Penalty >> Link Elimination Algorithm.", "Running time is " + runTime.ToString("#,###,##0") + " miliseconds.", pga);
        } 
        #endregion

        #region LINK ELIMINATION >> LINK PENALTY
        public static PGA getLinkElimPenPga(Graph graph, int w, int h, int top, int left)
        {
            PGA pga = new PGA();
            pga.Text = "Path Generation by Link Elimination Algorithm followed by Link Penalty Algorithm";
            if (Program.sueForm.WindowState != FormWindowState.Maximized) { pga.Width = w; pga.Height = h; pga.Top = top; pga.Left = left; }
            pga.lblOd.Text = "The algorithm sequentially runs link elimination (Azevedo, J.A. et al. (1993)) and link penalty (De La Barra, T. et al. (1993)) algorithms.";
            List<string> spaItems = new List<string>() { "Dijkstra's Algorithm (Dijkstra, E. W. (1959))" };
            List<string> spaLabels = new List<string>()
            {
                "Selected shortest path algorithm will be used at each iteration of link elimination and link penalty algorithms.",
            };
            CbAndLabel spa = new CbAndLabel("spas", spaItems, 0, spaLabels);
            pga.splitContainer2.Panel1.Controls.Add(spa);

            TbAndLabel penalty = new TbAndLabel("penalty", "Penalty (link cost of 100 becomes 105 with a penalty of 0.05)", "0.05", System.Windows.Forms.HorizontalAlignment.Right, typeof(double), TbAndLabel.NumberCondition.Positive);
            pga.splitContainer3.Panel1.Controls.Add(penalty);

            TbAndLabel iterLim = new TbAndLabel("iterLim", "Maximum number of iterations per OD pair for link penalty algorithm.", "1000", System.Windows.Forms.HorizontalAlignment.Right, typeof(int), TbAndLabel.NumberCondition.Positive);
            pga.splitContainer4.Panel1.Controls.Add(iterLim);

            TbAndLabel perc = new TbAndLabel("perc", "Limit on the fraction of the paths that will be generated by link elimination algorithm", "0.5", System.Windows.Forms.HorizontalAlignment.Right, typeof(double), TbAndLabel.NumberCondition.Positive);
            pga.splitContainer5.Panel1.Controls.Add(perc);
            pga.btnRun.Click += new EventHandler(runLELP);
            commonControls(pga);
            return pga;
        }
        private static void runLELP(object sender, EventArgs e)
        {
            Button btn = (Button)sender;
            PGA pga = (PGA)btn.FindForm();

            bool keepPaths = pga.chbKeepExisting.Checked;
            if (!keepPaths) { SueForm.sue.graph.clearPaths(); }

            ShortestPathAlgorithm spa = new Dijkstra(); // update here if new SP algorithms are added

            TbAndLabel penaltyTb = (TbAndLabel)pga.splitContainer3.Panel1.Controls["penalty"];
            double penalty = Convert.ToDouble(penaltyTb.getText());

            TbAndLabel iterLimTb = (TbAndLabel)pga.splitContainer4.Panel1.Controls["iterLim"];
            long iterLim = Convert.ToInt64(iterLimTb.getText());

            TbAndLabel percTb = (TbAndLabel)pga.splitContainer5.Panel1.Controls["perc"];
            double perc = Convert.ToDouble(percTb.getText());

            TbAndLabel pathLimTb = (TbAndLabel)pga.splitContainer7.Panel2.Controls["pathLim"];
            int pathLim = Convert.ToInt16(pathLimTb.getText());

            PathGenerationAlgorithm alg = new LinkEliminationThenPenalty(spa, penalty, iterLim, perc);

            List<object> args = new List<object>() { alg, pathLim };
            pga.bgwPga.RunWorkerAsync(args);
            Progress.show(pga);

            afterAfterRun();
            Msg.show("Link Elimination >> Link Penalty Algorithm.", "Running time is " + runTime.ToString("#,###,##0") + " miliseconds.", pga);
        } 
        #endregion


        #region HELPERS
        private static void commonControls(PGA pga)
        {
            TbAndLabel pathLim = new TbAndLabel("pathLim", "Maximum nb of paths per OD pair", "0", System.Windows.Forms.HorizontalAlignment.Right, typeof(int), TbAndLabel.NumberCondition.Nonnegative);
            pga.splitContainer7.Panel2.Controls.Add(pathLim);
        }
        private static void afterAfterRun()
        {
            SueForm.statDgv.dgv.setDataTable(SueForm.statDt);
            SueForm.nodesDgv.dgv.setDataTable(SueForm.nodesDt);
            SueForm.odDgv.dgv.setDataTable(SueForm.odDt);
            SueForm.pathDgv.dgv.setDataTable(SueForm.pathDt);
        }
        #endregion
        

    }
}
