using SeSue.Forms.Common;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
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.Forms.Visualization
{
    public partial class Visualization : Form
    {
        private System.Drawing.Color colorMin = System.Drawing.Color.FromArgb(0, 255, 0);
        private System.Drawing.Color colorMax = System.Drawing.Color.FromArgb(255, 0, 0);
        public static byte minR = 0;
        public static byte maxR = 255;
        public static byte minG = 255;
        public static byte maxG = 0;
        public static byte minB = 0;
        public static byte maxB = 0;

        private ColorScale colorScale;
        private bool doResize;
        private Graph graph;
        private DataTable dtOdpairs;
        private DataTable dtNodes;
        private DataTable dtNone;

        private Microsoft.Glee.Drawing.Graph nw;
        private Microsoft.Glee.GraphViewerGdi.GViewer viewer;
        private List<byte> minRgb;
        private List<byte> maxRgb;
        private int selectedValueIndex;
        private int includeIndex;
        private string formText;
        private List<double[]> weights;
        private List<double> maxValues;


        #region CONSTRUCTOR
        public Visualization(Graph graph, int w, int h, int l, int t, FormWindowState parentWindowState)
        {
            InitializeComponent();
            this.ShowInTaskbar = false;
            this.doResize = false;
            if (parentWindowState == FormWindowState.Maximized) { this.WindowState = FormWindowState.Maximized; }
            else { this.Width = w; this.Height = h; this.Left = l; this.Top = t; }
            this.doResize = true;
            this.graph = graph;
            initializeDataTables();
            initializeValues();
            this.colorScale = new ColorScale(new List<string>() { "Flow", "Cost", "Flow / Capacity" });
            this.colorScale.Dock = DockStyle.Fill;
            this.groupColor.Controls.Add(this.colorScale);
            this.colorScale.onResize();
            this.cbInclude.SelectedIndex = 0;
            this.Icon = Properties.Resources.logo;
        }
        private void initializeDataTables()
        {
            dtOdpairs = new DataTable();
            dtNodes = new DataTable();
            dtNone = new DataTable();
            dtOdpairs.Columns.Add("w"); dtOdpairs.Columns.Add("OD Label"); dtOdpairs.Columns.Add("Include");
            dtOdpairs.Columns[2].DataType = typeof(bool);

            dtNodes.Columns.Add("w"); dtNodes.Columns.Add("OD Label"); dtNodes.Columns.Add("Include");
            dtNodes.Columns[2].DataType = typeof(bool);

            for (int w = 0; w < graph.getOdPairs().Length; w++)
            {
                OdPair od = graph.getOdPair(w);
                DataRow dr = dtOdpairs.NewRow();
                dr[0] = w.ToString();
                dr[1] = od.getLabel();
                dr[2] = false;
                dtOdpairs.Rows.Add(dr);
            }
            for (int i = 0; i < graph.getNodes().Length; i++)
            {
                Node node = graph.getNode(i);
                DataRow dr = dtNodes.NewRow();
                dr[0] = i.ToString();
                dr[1] = node.getLabel();
                dr[2] = false;
                dtNodes.Rows.Add(dr);
            }
        }
        private void initializeValues()
        {
            int A = graph.getNbArcs();
            this.maxValues = new List<double>() { 0.0, 0.0, 0.0 };
            this.weights = new List<double[]> { new double[A], new double[A], new double[A] };
            for (int a = 0; a < A; a++)
            {
                Link link = graph.getLink(a);
                maxValues[0] = Math.Max(maxValues[0], link.getFlow());
                maxValues[1] = Math.Max(maxValues[1], link.getFlow() / link.getLinkCost().getCapacity());
                maxValues[2] = Math.Max(maxValues[2], link.getCost());
            }
            for (int i = 0; i < 3; i++) { if (maxValues[i] == 0) { maxValues[i] = 1.0; } }
            for (int a = 0; a < A; a++)
            {
                Link link = graph.getLink(a);
                weights[0][a] = link.getFlow() / maxValues[0];
                weights[1][a] = link.getFlow() / link.getLinkCost().getCapacity() / maxValues[1];
                weights[2][a] = link.getCost() / maxValues[2];
            }
        }
        #endregion

        #region EVENTS
        private void Visualization_Resize(object sender, EventArgs e) { if (doResize) { this.colorScale.onResize(); } }
        private void cbInclude_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (cbInclude.SelectedIndex == 0) { dataGridView1.DataSource = dtNone; }
            else if (cbInclude.SelectedIndex == 1) { dataGridView1.DataSource = dtOdpairs; }
            else if (cbInclude.SelectedIndex == 2) { dataGridView1.DataSource = dtNodes; }
            if (cbInclude.SelectedIndex > 0)
            {
                dataGridView1.Columns[2].HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter;
                dataGridView1.Columns[0].DefaultCellStyle.Padding = new Padding(5, 0, 0, 0);
                dataGridView1.Columns[0].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleLeft;
                dataGridView1.Columns[1].DefaultCellStyle.Padding = new Padding(5, 0, 0, 0);
                dataGridView1.Columns[1].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleLeft;
                dataGridView1.Columns[0].FillWeight = 100;
                dataGridView1.Columns[1].FillWeight = 750;
                dataGridView1.Columns[2].FillWeight = 150;
                dataGridView1.ColumnHeadersHeight = 30;
            }
            dataGridView1.Refresh();
        } 
        #endregion

        #region NETWORK GENERATION

        private void btnGenerate_Click(object sender, EventArgs e)
        {
            System.Windows.Forms.Form form = new System.Windows.Forms.Form();

            nw = new Microsoft.Glee.Drawing.Graph("Network");
            viewer = new Microsoft.Glee.GraphViewerGdi.GViewer();
            minRgb = this.colorScale.getMinRGB();
            maxRgb = this.colorScale.getMaxRGB();
            selectedValueIndex = this.colorScale.cbSelectedIndex();
            includeIndex = cbInclude.SelectedIndex;
            formText = "Network";

            bgw.RunWorkerAsync(); Progress.setText("Creating Network."); Progress.show(this);

            Network frm = new Network(this, viewer, formText, this.Width, this.Height);
            frm.Show(this);
        }

        private void bgw_DoWork(object sender, DoWorkEventArgs e)
        {
            string A = graph.getNbArcs().ToString();
            string N = graph.getNbNodes().ToString();
            string W = graph.getNbOdPairs().ToString();
            List<bool> included = UList.sameValues<bool>(false, graph.getNbArcs());
            if (includeIndex == 0)
            {
                formText = "Entire Network";
                for (int a = 0; a < graph.getNbArcs(); a++)
                {
                    Link link = graph.getLink(a);
                    nw.AddEdge(link.getFromLabel(), link.getToLabel());
                    byte r = Convert.ToByte(minRgb[0] + (maxRgb[0] - minRgb[0]) * weights[selectedValueIndex][a]);
                    byte g = Convert.ToByte(minRgb[1] + (maxRgb[1] - minRgb[1]) * weights[selectedValueIndex][a]);
                    byte b = Convert.ToByte(minRgb[2] + (maxRgb[2] - minRgb[2]) * weights[selectedValueIndex][a]);
                    nw.Edges[nw.Edges.Count - 1].Attr.Color = new Microsoft.Glee.Drawing.Color(r, g, b);
                }
            }
            else if (includeIndex == 1)
            {
                formText = "Selected Origin-Destination Pairs";
                for (int w = 0; w < dtOdpairs.Rows.Count; w++)
                {
                    if (dtOdpairs.Rows[w][2].ToString() == true.ToString())
                    {
                        OdPair od = graph.getOdPair(w);
                        foreach (int k in od.getPathIndices())
                        {
                            Path path = graph.getPath(k);
                            foreach (int a in path.getArcIndices())
                            {
                                if (!included[a])
                                {
                                    included[a] = true;
                                    Link link = graph.getLink(a);
                                    nw.AddEdge(link.getFromLabel(), link.getToLabel());
                                    byte r = Convert.ToByte(minRgb[0] + (maxRgb[0] - minRgb[0]) * weights[selectedValueIndex][a]);
                                    byte g = Convert.ToByte(minRgb[1] + (maxRgb[1] - minRgb[1]) * weights[selectedValueIndex][a]);
                                    byte b = Convert.ToByte(minRgb[2] + (maxRgb[2] - minRgb[2]) * weights[selectedValueIndex][a]);
                                    nw.Edges[nw.Edges.Count - 1].Attr.Color = new Microsoft.Glee.Drawing.Color(r, g, b);
                                }
                            }
                        }
                    }
                }
            }
            else if (includeIndex == 2)
            {
                formText = "Selected Nodes";
                for (int i = 0; i < dtNodes.Rows.Count; i++)
                {
                    if (dtNodes.Rows[i][2].ToString() == true.ToString())
                    {
                        Node node = graph.getNode(i);
                        foreach (int a in node.getInArcIndices())
                        {
                            Link link = graph.getLink(a);
                            if (!included[a])
                            {
                                included[a] = true;
                                nw.AddEdge(link.getFromLabel(), link.getToLabel());
                                byte r = Convert.ToByte(minRgb[0] + (maxRgb[0] - minRgb[0]) * weights[selectedValueIndex][a]);
                                byte g = Convert.ToByte(minRgb[1] + (maxRgb[1] - minRgb[1]) * weights[selectedValueIndex][a]);
                                byte b = Convert.ToByte(minRgb[2] + (maxRgb[2] - minRgb[2]) * weights[selectedValueIndex][a]);
                                nw.Edges[nw.Edges.Count - 1].Attr.Color = new Microsoft.Glee.Drawing.Color(r, g, b);
                            }
                        }
                        foreach (int a in node.getOutArcIndices())
                        {
                            Link link = graph.getLink(a);
                            if (!included[a])
                            {
                                included[a] = true;
                                nw.AddEdge(link.getFromLabel(), link.getToLabel());
                                byte r = Convert.ToByte(minRgb[0] + (maxRgb[0] - minRgb[0]) * weights[selectedValueIndex][a]);
                                byte g = Convert.ToByte(minRgb[1] + (maxRgb[1] - minRgb[1]) * weights[selectedValueIndex][a]);
                                byte b = Convert.ToByte(minRgb[2] + (maxRgb[2] - minRgb[2]) * weights[selectedValueIndex][a]);
                                nw.Edges[nw.Edges.Count - 1].Attr.Color = new Microsoft.Glee.Drawing.Color(r, g, b);
                            }
                        }
                    }
                }
            }
            viewer.Graph = nw;
        }
        private void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { Progress.hide(); }

        #endregion
               



    }
}
