using SeSue.FormClasses.Dgv;
using SeSue.Forms;
using SeSue.Forms.Common;
using SeSue.Forms.Wizards;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using U.ListOperations;
using U.StringOperations;
using U.SUE;

namespace SeSue.DGVs.Wizard
{
    class ExponentialParamsDgv
    {
        private List<DgvColumn> dgvCols;
        public Dgv dgv;
        private List<double[]> CF;
        private List<double[]> PS;
        private List<double[]> locations;
        private List<double[]> rates;
        private List<int> selectedOdIndices;

        public ExponentialParamsDgv(Control container, List<int> selectedOdIndices, int scalingIndex, int correctionIndex)
        {
            this.dgvCols = new List<DgvColumn>()
            {
                //new DgvColumn("i", false, true, 0.00, typeof(int), String.Empty, true, DataGridViewContentAlignment.MiddleLeft, SueForm.labelColor, SueForm.regularFontColor),
                new DgvColumn("w", true, true, 0.05, typeof(int), String.Empty, true, DataGridViewContentAlignment.MiddleLeft, SueForm.editableColor, SueForm.labelColor),
                new DgvColumn("k", true, true, 0.05, typeof(int), String.Empty, true, DataGridViewContentAlignment.MiddleLeft, SueForm.editableColor, SueForm.labelColor),
                //new DgvColumn("OD", true, true, 0.05, typeof(string), String.Empty, true, DataGridViewContentAlignment.MiddleLeft, SueForm.labelColor, SueForm.regularFontColor),
                new DgvColumn("Path", true, true, 0.20, typeof(string), String.Empty, true, DataGridViewContentAlignment.MiddleLeft, SueForm.editableColor, SueForm.labelColor),
                new DgvColumn("CF", true, true, 0.175, typeof(double), "#,##0.0000", true, DataGridViewContentAlignment.MiddleRight, SueForm.editableColor, SueForm.labelColor),
                new DgvColumn("PS", true, true, 0.175, typeof(double), "#,##0.0000", true, DataGridViewContentAlignment.MiddleRight, SueForm.editableColor, SueForm.labelColor),
                new DgvColumn("A (location)", true, false, 0.175, typeof(double), "#,##0.0000", true, DataGridViewContentAlignment.MiddleRight, SueForm.editableColor, SueForm.regularFontColor),
                new DgvColumn("theta (rate)", true, false, 0.175, typeof(double), "#,##0.0000", true, DataGridViewContentAlignment.MiddleRight, SueForm.editableColor, SueForm.regularFontColor),
            };
            this.dgv = new Dgv(container, dgvCols, SueForm.editableColor, SueForm.gridColor, true, false, SueForm.rowHeight, SueForm.headerVertPadding, false, false, false, true, false, true, DataGridViewClipboardCopyMode.EnableAlwaysIncludeHeaderText, DataGridViewSelectionMode.CellSelect, ScrollBars.Vertical, DockStyle.Fill);
            container.Controls.Add(dgv);
            initialize(selectedOdIndices, scalingIndex, correctionIndex);
            this.dgv.getDataGridView().CellValidating += new DataGridViewCellValidatingEventHandler(validating);
            this.dgv.getDataGridView().CellValueChanged += new DataGridViewCellEventHandler(valueChanged);
        }
        private void initialize(List<int> selectedOdIndices, int scalingIndex, int correctionIndex)
        {
            this.selectedOdIndices = selectedOdIndices;
            this.locations = new List<double[]>();
            this.rates = new List<double[]>();
            this.CF = new List<double[]>();
            this.PS = new List<double[]>();

            for (int i = 0; i < selectedOdIndices.Count; i++)
            {
                int w = selectedOdIndices[i];
                OdPair od = SueForm.sue.graph.getOdPair(w);
                int K = od.getPathIndices().Length;
                double[] cf = UArray.sameValues(-1.0, od.getPathIndices().Length);
                double[] ps = UArray.sameValues(-1.0, od.getPathIndices().Length);
                double[] As = UArray.sameValues(-1.0, od.getPathIndices().Length);
                double[] thetas = UArray.sameValues(-1.0, od.getPathIndices().Length);

                // rates - thetas
                if (scalingIndex == 0)
                {
                    for (int p = 0; p < K; p++) { thetas[p] = SueForm.theta; }
                }
                else if (scalingIndex == 1)
                {
                    double spfftt = od.calcSpFFTT(SueForm.sue.graph);
                    for (int p = 0; p < K; p++) { thetas[p] = SueForm.theta * Math.PI / Math.Sqrt(6 * SueForm.eta * spfftt); }
                }
                else if (scalingIndex == 2)
                {
                    double spfftt = od.calcSpFFTT(SueForm.sue.graph);
                    for (int p = 0; p < K; p++) { thetas[p] = Math.PI / Math.Sqrt(6) / SueForm.nu / spfftt; }
                }
                else if (scalingIndex == 3)
                {
                    for (int p = 0; p < K; p++)
                    {
                        Path path = SueForm.sue.graph.getPath(od.getPathIndices()[p]);
                        thetas[p] = SueForm.theta * Math.PI / Math.Sqrt(6 * SueForm.eta * path.calcFFTT(SueForm.sue.graph));
                    }
                }
                else if (scalingIndex == 4)
                {
                    for (int p = 0; p < K; p++)
                    {
                        Path path = SueForm.sue.graph.getPath(od.getPathIndices()[p]);
                        thetas[p] = Math.PI / Math.Sqrt(6) / SueForm.nu / path.calcFFTT(SueForm.sue.graph);
                    }
                }

                // locations - As
                if (correctionIndex == 0) { for (int p = 0; p < cf.Length; p++) { As[p] = 0.0; } }
                if (correctionIndex == 1)
                {
                    cf = od.calcCommonalityFactors(SueForm.sue.graph, SueForm.beta0, SueForm.gamma);
                    for (int p = 0; p < cf.Length; p++) { As[p] = -cf[p]; }
                }
                if (correctionIndex == 2)
                {
                    ps = od.calcPathSize(SueForm.sue.graph);
                    for (int p = 0; p < cf.Length; p++) { As[p] = Math.Log(ps[p]) / thetas[p]; }
                }

                this.CF.Add(cf);
                this.PS.Add(ps);
                this.rates.Add(thetas);
                this.locations.Add(As);
            }
            filter(SueForm.sue.graph.getOdPair(selectedOdIndices[0]).getLabel(), String.Empty, String.Empty);
        }
        public void filter(string odLabel, string nodeLabels, string linkLabels)
        {
            DataTable dt = this.dgv.getEmptyDatatable();
            int w = getOdPairIndex(odLabel);
            int ind = selectedOdIndices.IndexOf(w);
            if (ind != -1)
            {
                List<string> nodes = new List<string>();
                List<string> links = new List<string>();
                if (nodeLabels != String.Empty) { nodes = Str.split(nodeLabels, Str.Delimiter.Comma); }
                if (linkLabels != String.Empty) { links = Str.split(linkLabels, Str.Delimiter.Comma); }
                OdPair od = SueForm.sue.graph.getOdPair(w);
                int K = od.getPathIndices().Length;
                for (int k = 0; k < K; k++)
                {
                    Path path = SueForm.sue.graph.getPath(od.getPathIndices()[k]);
                    List<string> pathNodes = Str.split(path.getLabel(), Str.Delimiter.Dash);
                    bool include = true;
                    if (nodes.Count > 0)
                    {
                        include = UList.isSubsetOf(nodes, pathNodes);
                    }
                    if (include && links.Count > 0)
                    {
                        List<string> pathLinkLabels = new List<string>();
                        foreach (int a in path.getArcIndices()) { pathLinkLabels.Add(SueForm.sue.graph.getLink(a).getLabel()); }
                        include = UList.isSubsetOf(links, pathLinkLabels);
                    }
                    if (include)
                    {
                        DataRow dr = dt.NewRow();
                        dr[0] = w.ToString();
                        dr[1] = k.ToString();
                        dr[2] = path.getLabel();
                        dr[3] = CF[ind][k].ToString();
                        dr[4] = PS[ind][k].ToString();
                        dr[5] = locations[ind][k].ToString();
                        dr[6] = rates[ind][k].ToString();
                        dt.Rows.Add(dr);
                    }
                }
            }
            this.dgv.setDataTable(dt);
        }
        private int getOdPairIndex(string odLabel) { for (int w = 0; w < SueForm.sue.graph.getOdPairs().Length; w++) { if (SueForm.sue.graph.getOdPair(w).getLabel() == odLabel) { return w; } } return -1; }



        // VALIDATING
        private void validating(object sender, DataGridViewCellValidatingEventArgs e)
        {
            int r = e.RowIndex;
            int c = e.ColumnIndex;
            if (c != 5 && c != 6) { return; }
            Control control = (Control)sender; Form parent = control.FindForm();
            string header = "A (location)";
            if (c == 6) { header = "theta (rate)"; }
            if (!Str.isNumeric(e.FormattedValue.ToString())) { MessageBox.Show(header + " should be numeric.", "Validation Error!"); e.Cancel = true; return; }
            double val = Str.toDouble(e.FormattedValue.ToString());
            if (val <= 0 && c == 6) { Msg.show("Error.", header + " should be positive.", parent); e.Cancel = true; return; }
        }
        private void valueChanged(object sender, DataGridViewCellEventArgs e)
        {
            int r = e.RowIndex;
            int c = e.ColumnIndex;
            if (c != 5 && c != 6) { return; }
            int w = dgv.getCellValueInt(r, 0);
            int k = dgv.getCellValueInt(r, 1);
            int ind = selectedOdIndices.IndexOf(w);
            if (c == 5) { locations[ind][k] = dgv.getCellValueDbl(r, 5); }
            else if (c == 6) { rates[ind][k] = dgv.getCellValueDbl(r, 6); }
        }

        public List<double[]> getLocations() { return this.locations; }
        public List<double[]> getRates() { return this.rates; }

        public Form getParent() { foreach (Form frm in Application.OpenForms) { if (frm.GetType() == typeof(MdmExpWizard)) { return frm; } } return null; }
    }
}
