using StatisticalDistribution;
using SeSue.FormClasses.Dgv;
using SeSue.Forms;
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 NormalParamsDgv
    {
        private List<DgvColumn> dgvCols;
        public Dgv dgv;
        private List<double[]> PS;
        private List<double[]> mus;
        private List<double[]> sigmas;
        private List<int> selectedOdIndices;

        public NormalParamsDgv(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.2125, typeof(string), String.Empty, true, DataGridViewContentAlignment.MiddleLeft, SueForm.editableColor, SueForm.labelColor),
                new DgvColumn("PS", true, true, 0.2125, typeof(double), "#,##0.0000", true, DataGridViewContentAlignment.MiddleRight, SueForm.editableColor, SueForm.labelColor),
                new DgvColumn("mu (mean)", true, false, 0.2125, typeof(double), "#,##0.0000", true, DataGridViewContentAlignment.MiddleRight, SueForm.editableColor, SueForm.regularFontColor),
                new DgvColumn("sigma (std)", true, false, 0.2125, 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.mus = new List<double[]>();
            this.sigmas = 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[] ps = UArray.sameValues(-1.0, od.getPathIndices().Length);
                double[] mu = UArray.sameValues(-1.0, od.getPathIndices().Length);
                double[] sigma = UArray.sameValues(-1.0, od.getPathIndices().Length);

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

                // locations - As
                if (od.getPathIndices().Length == 1) { mu[0] = 0.0; }
                else if (correctionIndex == 0) { for (int p = 0; p < ps.Length; p++) { mu[p] = 0.0; } }
                else if (correctionIndex == 1)
                {
                    ps = od.calcPathSize(SueForm.sue.graph);
                    double sumPs = 0.0;
                    for (int p = 0; p < ps.Length; p++) { sumPs += ps[p]; }
                    for (int p = 0; p < ps.Length; p++) { mu[p] = -sigma[p] * StandardNormalDist.CdfInv(1.0 - ps[p] / sumPs); }
                }
                this.PS.Add(ps);
                this.sigmas.Add(sigma);
                this.mus.Add(mu);
            }
            filter(selectedOdIndices, SueForm.sue.graph.getOdPair(selectedOdIndices[0]).getLabel(), String.Empty, String.Empty);
        }
        public void filter(List<int> selectedOdIndices, 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] = PS[ind][k].ToString();
                        dr[4] = mus[ind][k].ToString();
                        dr[5] = sigmas[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 != 4 && c != 5) { return; }
            string header = "mu (mean)";
            if (c == 5) { header = "sigma (std)"; }
            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 == 5) { MessageBox.Show(header + " should be positive.", "Validation Error!"); e.Cancel = true; return; }
        }
        private void valueChanged(object sender, DataGridViewCellEventArgs e)
        {
            int r = e.RowIndex;
            int c = e.ColumnIndex;
            if (c != 4 && c != 5) { return; }
            int w = dgv.getCellValueInt(r, 0);
            int k = dgv.getCellValueInt(r, 1);
            int ind = selectedOdIndices.IndexOf(w);
            if (c == 4) { mus[ind][k] = dgv.getCellValueDbl(r, 4); }
            else if (c == 5) { sigmas[ind][k] = dgv.getCellValueDbl(r, 5); }
        }



        public List<double[]> getMus() { return mus; }
        public List<double[]> getSigmas() { return sigmas; }


    }
}
