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 LogitCorrectionDgv
    {
        private List<DgvColumn> dgvCols;
        public Dgv dgv;
        private List<double> odThetas;
        private List<double[]> CT;
        private List<double[]> CF;
        private List<double[]> PS;
        private List<int> selectedOdIndices;


        public LogitCorrectionDgv(Control container, List<int> selectedOdIndices, List<double> odThetas, int correctionIndex)
        {
            this.dgvCols = new List<DgvColumn>()
            {
                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("Path", true, true, 0.20, typeof(string), String.Empty, true, DataGridViewContentAlignment.MiddleLeft, SueForm.editableColor, SueForm.labelColor),
                new DgvColumn("theta", true, true, 0.175, typeof(double), "#,##0.0000", true, DataGridViewContentAlignment.MiddleRight, 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("CT", 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, odThetas, correctionIndex);
            this.dgv.getDataGridView().CellValidating += new DataGridViewCellValidatingEventHandler(validating);
            this.dgv.getDataGridView().CellValueChanged += new DataGridViewCellEventHandler(valueChanged);
        }
        private void initialize(List<int> selectedOdIndices, List<double> odThetas, int correctionIndex)
        {
            this.selectedOdIndices = selectedOdIndices;
            this.odThetas = odThetas;
            this.CT = 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[] ct = new double[K];
                double[] cf = UArray.sameValues(-1.0, od.getPathIndices().Length);
                double[] ps = UArray.sameValues(-1.0, od.getPathIndices().Length);
                if (correctionIndex == 0)
                {
                    for (int k = 0; k < K; k++) { ct[k] = 1.0; }
                }
                else if (correctionIndex == 1)
                {
                    cf = od.calcCommonalityFactors(SueForm.sue.graph, SueForm.beta0, SueForm.gamma);
                    for (int k = 0; k < K; k++) { ct[k] = Math.Exp(-odThetas[i] * cf[k]); }
                }
                else if (correctionIndex == 2)
                {
                    ps = od.calcPathSize(SueForm.sue.graph);
                    for (int k = 0; k < K; k++) { ct[k] = ps[k]; }
                }
                this.CT.Add(ct);
                this.CF.Add(cf);
                this.PS.Add(ps);
            }
            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] = odThetas[ind].ToString();
                        dr[4] = CF[ind][k].ToString();
                        dr[5] = PS[ind][k].ToString();
                        dr[6] = CT[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 != 8) { return; }
            string header = "Correction term (CT)";
            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) { 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 != 6) { return; }
            int w = dgv.getCellValueInt(r, 0);
            int k = dgv.getCellValueInt(r, 1);
            int ind = selectedOdIndices.IndexOf(w);
            this.CT[ind][k] = dgv.getCellValueDbl(r, 6);
        }

        public List<double[]> getCorrectionTerms() { return CT; }

    }
}
