using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace EduNetworkBuilder
{
    public partial class VLANConfig : Form
    {

        NetworkDevice TheDevice = null;
        BindingList<VLANName> VLANNames = new BindingList<VLANName>();
        DataTable VlanBindings = new DataTable();
        List<NetworkInterface> interfaces = new List<NetworkInterface>();
        BindingList<VLANName> StashedVLANNameList = new BindingList<VLANName>();
        List<bool> LockedIFs = new List<bool>();
        bool LockedNames = false;

        bool processing = false;

        public VLANConfig(NetworkDevice ToEdit)
        {
            processing = true;
            InitializeComponent();
            TheDevice = ToEdit;

            this.Icon = Properties.Resources.NBIco;
            processing = false;

            dgv_VLANAssignments.DataBindingComplete += AssignmentsDataBindingComplete;
            dgv_VLANNames.DataBindingComplete += NamesDataBindingComplete;

            UpdateForm();
        }

        void AssignmentsDataBindingComplete(object Sender, EventArgs e)
        {
            //Lock any interfaces / NICs that are locked by tests
            for (int i = 0; i < LockedIFs.Count; i++)
            {
                if (i < dgv_VLANAssignments.Rows.Count)
                    dgv_VLANAssignments.Rows[i].ReadOnly = LockedIFs[i];
            }
        }

        void NamesDataBindingComplete(object Sender, EventArgs e)
        {
            Network theNet = NB.GetNetwork();
            if (dgv_VLANNames.Columns.Count > 0)
            {
                dgv_VLANNames.Columns[0].ReadOnly = LockedNames;
                if (theNet.VLANPacketColors && dgv_VLANNames.Columns.Count > 1)
                {
                    dgv_VLANNames.Columns[1].ReadOnly = LockedNames;
                }
                if(theNet.VLANPacketColors && dgv_VLANNames.Columns.Count > 2)
                {
                    dgv_VLANNames.Columns[2].ReadOnly = LockedNames;
                }
                if (LockedNames)
                    dgv_VLANNames.AllowUserToAddRows = false;
            }
        }

        private void UpdateForm()
        {
            if (processing) return;
            string hostname = "";

            LockedNames = false;

            if (TheDevice != null)
            {
                hostname = TheDevice.hostname;
            }

            LockedIFs.Clear();
            UpdateNamesFromForm(); //Read in any changes so far

            processing = true;
            //********************
            //Bind the vlan names
            Network theNet = NB.GetNetwork();
            int selectedrow = -1;
            int selectedcol = -1;
            if (dgv_VLANAssignments.CurrentCell != null)
            {
                selectedrow = dgv_VLANAssignments.CurrentCell.RowIndex;
                selectedcol = dgv_VLANAssignments.CurrentCell.ColumnIndex;
            }

            //theNet.VlanNames.Sort((x, y) => x.ID.CompareTo(y.ID));
            List<VLANName> tList = theNet.VlanNames.OrderBy(x => x.ID).ToList();
            StashedVLANNameList = new BindingList<VLANName>(tList);

            dgv_VLANNames.AutoGenerateColumns = false;
            dgv_VLANNames.Columns.Clear();
            dgv_VLANNames.DataSource = StashedVLANNameList;
            dgv_VLANNames.AllowUserToAddRows = true;

            //The VLAN ID
            DataGridViewTextBoxColumn DGVTB = new DataGridViewTextBoxColumn();
            DGVTB.ValueType = typeof(string);
            DGVTB.DataPropertyName = "ID";
            DGVTB.Name = "ID";
            DGVTB.HeaderText = "ID";
            dgv_VLANNames.Columns.Add(DGVTB);

            //The VLAN name
            DGVTB = new DataGridViewTextBoxColumn();
            DGVTB.ValueType = typeof(string);
            DGVTB.DataPropertyName = "Name";
            DGVTB.Name = "Name";
            DGVTB.HeaderText = "Name";
            dgv_VLANNames.Columns.Add(DGVTB);

            if (theNet.VLANPacketColors)
            {
                //The VLAN color. (optional)
                DataGridViewComboBoxColumn DGVCBC = new DataGridViewComboBoxColumn();
                DGVCBC.ValueType = typeof(string);
                DGVCBC.DataPropertyName = "PacketColorString";
                DGVCBC.Name = "Color";
                DGVCBC.HeaderText = "Color";
                DGVCBC.Items.Add("Blue");
                DGVCBC.Items.Add("Purple");
                DGVCBC.Items.Add("Yellow");
                DGVCBC.Items.Add("Green");
                DGVCBC.Items.Add("Orange");
                DGVCBC.Items.Add("Cyan");
                dgv_VLANNames.Columns.Add(DGVCBC);
            }

            if (TheDevice != null)
            {
                if (theNet.ItemIsLocked(hostname, "", NetTestType.LockVLANNames) || 
                    theNet.ItemIsLocked(hostname, "", NetTestType.LockVLANsOnHost))
                    LockedNames = true;
                else
                    LockedNames = false;
            }

            //**************************************
            //Start building the VLAN/Interface list
            VlanBindings.Columns.Clear();
            VlanBindings.Columns.Add("IF", typeof(string));
            foreach (VLANName vn in theNet.VlanNames)
            {
                VlanBindings.Columns.Add(vn.Name, typeof(string));
            }


            VlanBindings.Rows.Clear();
            List<string> theNics = TheDevice.NICNames();
            //Fill out the interfaces
            foreach (string oneNic in theNics)
            {
                NetworkCard NIC = TheDevice.NicFromName(oneNic);
                if (NIC.GetNicType == NicType.lo) continue;
                //if (NIC.GetNicType == NicType.management_interface) continue; //so we can lock outselves out
                if (NIC.GetNicType == NicType.wport) continue;
                if (NIC.GetNicType == NicType.wlan) continue;
                if (NIC.GetNicType == NicType.vpn) continue;
                if (NIC.GetNicType == NicType.none) continue;
                if (NIC.GetNicType == NicType.tun) continue;
                bool locked = false;
                
                //Lock the interface if it needs to be locked
                if (TheDevice != null) {
                    if (theNet.ItemIsLocked(hostname, oneNic, NetTestType.LockNic))
                        locked = true;
                    if (theNet.ItemIsLocked(hostname, oneNic, NetTestType.LockAll))
                        locked = true;
                    if (theNet.ItemIsLocked(hostname, oneNic, NetTestType.LockNicVLAN))
                        locked = true;
                    if (theNet.ItemIsLocked(hostname, oneNic, NetTestType.LockVLANsOnHost))
                        locked = true;
                }
                bool pastlock = locked;
                for (int i = 0; i < NIC.IFCount; i++)
                {
                    locked = pastlock;
                    NetworkInterface nif = NIC.GetInterface(i);
                    if (TheDevice != null)
                    {
                        //If the interface itself is locked...
                        if (theNet.ItemIsLocked(hostname, nif.nic_name, NetTestType.LockInterfaceVLAN))
                            locked = true;
                    }
                    DataRow DR = VlanBindings.NewRow();
                    DR["IF"] = nif.nic_name;
                    foreach (VLANName vn in theNet.VlanNames)
                    {
                        DR[vn.Name] = nif.GetVLANTag(vn.ID).ToString();
                    }
                    VlanBindings.Rows.Add(DR);
                    LockedIFs.Add(locked);
                }
            }
            dgv_VLANAssignments.AutoGenerateColumns = false;
            dgv_VLANAssignments.Columns.Clear();

            //dgv_VLANAssignments.Columns.Add("IF","IF");
            DataGridViewTextBoxColumn scol = new DataGridViewTextBoxColumn();
            scol.ValueType = typeof(string);
            scol.DataPropertyName = "IF";
            scol.Name = "IF";
            scol.HeaderText = "Interface";
            scol.ReadOnly = true;
            scol.Frozen = true;
            dgv_VLANAssignments.Columns.Add(scol);

            List<string> enumvalues = new List<string>();
            foreach (VLANTagType vtt in Enum.GetValues(typeof(VLANTagType)))
                enumvalues.Add(vtt.ToString());

            foreach (VLANName vn in theNet.VlanNames)
            {
                DataGridViewComboBoxColumn col = new DataGridViewComboBoxColumn();
                col.Name = vn.Name;
                col.DataPropertyName = vn.Name;
                col.DataSource = enumvalues;
                col.Width = 75;
                dgv_VLANAssignments.Columns.Add(col);
            }

            dgv_VLANAssignments.DataSource = VlanBindings;
            int many = theNet.VlanNames.Count;
            if (many > 3) many = 3;
            int checksize = 50 + 120 + (many * 80) + 25; //the record indicator, and the size of the name.  + width of each item
            if (Width < checksize) Width = checksize;  //Make it fit better

            processing = false;

            if (selectedcol >=0 && selectedcol < dgv_VLANAssignments.Columns.Count && selectedrow < dgv_VLANAssignments.Rows.Count)
                dgv_VLANAssignments.CurrentCell = dgv_VLANAssignments.Rows[selectedrow].Cells[selectedcol];
        }

        bool NamesGridHasID(int id)
        {
            string IDString = id.ToString();
            foreach (DataRow DR in dgv_VLANNames.Rows)
            {
                if (DR["ID"].ToString() == IDString)
                    return true;
            }
            return false;
        }

        bool VLANNamesHasID(BindingList<VLANName> names, int id)
        {
            foreach (VLANName VN in names)
            {
                if (VN.ID == id)
                    return true;
            }
            return false;
        }

        void UpdateNamesFromForm()
        {
            Network theNet = NB.GetNetwork();
            if (dgv_VLANNames.RowCount == 0) return;//If we have not put anything in it yet.

            //if (dgv_VLANNames.RowCount == theNet.VlanNames.Count) return; //Nothing was added or removed.

            BindingList<VLANName> oList = new BindingList<VLANName>();
            foreach (VLANName vn in theNet.VlanNames)
                oList.Add(vn); //stash it for keeping colors for now

            theNet.VlanNames.Clear(); //Remove them all.  We will re-add them

            //add it if it was added
            int id;
            foreach (DataGridViewRow DR in dgv_VLANNames.Rows)
            {
                id = -1;
                if (DR.Cells["ID"] == null || DR.Cells["ID"].Value == null) continue;

                int.TryParse(DR.Cells["ID"].Value.ToString(), out id);
                if (id > 0)
                {
                    if (!VLANNamesHasID(theNet.VlanNames, id))
                    {
                        Color tColor = Color.Blue;
                        if(theNet.VlanNames.Count < oList.Count ) tColor = oList[theNet.VlanNames.Count].PacketColor;
                        if (DR.Cells["Name"].Value == null) //When we are still adding
                            theNet.VlanNames.Add(new VLANName(id, "----", tColor));
                        else
                            theNet.VlanNames.Add(new VLANName(id, DR.Cells["Name"].Value.ToString(),tColor));
                    }
                }
            }

            if (!VLANNamesHasID(theNet.VlanNames, 1))
                theNet.VlanNames.Add(new VLANName(1, "Default"));

        }

        private void btnDone_Click(object sender, EventArgs e)
        {
            //We will probably do a lot more than this later.
            Close();
        }

        private void dgv_VLANNames_CellParsing(object sender, DataGridViewCellParsingEventArgs e)
        {
            //BindingList<VLANName> tempitem = new BindingList<VLANName>();
            //VLANName current = ((BindingList<VLANName>)dgv_VLANNames.DataSource)[e.RowIndex];
            //string key = current.ID.ToString();
            //int id = current.ID;
            //string value = current.Name;
            //string cellValue = e.Value.ToString();
            //if (e.ColumnIndex == 0) key = cellValue;
            //else value = cellValue;
            //((BindingList<VLANName>)dgv_VLANNames.DataSource)[e.RowIndex] = new VLANName { ID = id, Name = value };
        }

        private void dgv_VLANNames_CellValueChanged(object sender, DataGridViewCellEventArgs e)
        {
            if (!processing)
                UpdateForm();
        }

        private void dgv_VLANNames_RowsRemoved(object sender, DataGridViewRowsRemovedEventArgs e)
        {
            //if (!processing)
            //{
            //    UpdateForm();
            //}
        }

        private void dgv_VLANNames_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
        {
            //return;
            string headerText = dgv_VLANNames.Columns[e.ColumnIndex].Name;
            if (processing) return;

            dgv_VLANNames.Rows[e.RowIndex].ErrorText = ""; //clear the old one out
            Network theNet = NB.GetNetwork();

            if (headerText.Equals("ID"))
            {
                // Confirm that the cell is not empty.
                if (string.IsNullOrEmpty(e.FormattedValue.ToString()))
                {
                    dgv_VLANNames.Rows[e.RowIndex].ErrorText =
                        "The ID cannot be empty";
                    e.Cancel = true;
                    return;
                }
                else
                {

                    int value;
                    int.TryParse(e.FormattedValue.ToString(), out value);
                    if (value <= 0)
                    {
                        dgv_VLANNames.Rows[e.RowIndex].ErrorText =
                        "The ID cannot be negative or zero";
                        e.Cancel = true;
                        return;
                    }
                    //Verify that the ID is unique.  it is a zero-based index
                    for (int i = 0; i < StashedVLANNameList.Count; i++)
                    {
                        if (e.RowIndex == i) continue; //do not check ourself
                        if (StashedVLANNameList[i].ID == value)
                        {
                            dgv_VLANNames.Rows[e.RowIndex].ErrorText =
                            "You cannot duplicate VLAN IDs.  They must be unique";
                            e.Cancel = true;
                            return;
                        }
                    }
                    //MessageBox.Show(e.RowIndex.ToString() + " out of " + StashedVLANNameList.Count);
                }
            }
            if (headerText.Equals("Color"))
            {
                //Checking the color
                Console.WriteLine("Here "+ e.RowIndex);
            }
        }

        private void dgv_VLANNames_UserDeletedRow(object sender, DataGridViewRowEventArgs e)
        {
            if (!processing)
            {
                UpdateForm();
            }
        }

        private void SetIFVLAN(string ifname, int ID, VLANTagType Tag)
        {
            List<string> theNics = TheDevice.NICNames();
            
            foreach (string oneNic in theNics)
            {
                NetworkCard NIC = TheDevice.NicFromName(oneNic);
                if (NIC.GetNicType == NicType.lo) continue;
                //if (NIC.GetNicType == NicType.management_interface) continue;
                for (int i = 0; i < NIC.IFCount; i++)
                {
                    NetworkInterface nif = NIC.GetInterface(i);
                    if (nif.nic_name == ifname)
                        nif.SetVLANTag(ID, Tag);
                }
            }
        }

        private void dgv_VLANAssignments_CellValueChanged(object sender, DataGridViewCellEventArgs e)
        {
            //We are working on a vlan tag.
            Network theNet = NB.GetNetwork();
            if (e.ColumnIndex == 0) return; //we should never get here.

            VLANTagType VTT = NB.TryParseEnum<VLANTagType>(dgv_VLANAssignments.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString(), VLANTagType.Forbidden);
            string Which = dgv_VLANAssignments.Rows[e.RowIndex].Cells[0].Value.ToString();
            string VLANName = dgv_VLANAssignments.Columns[e.ColumnIndex].HeaderText;
            int ID = theNet.VLANIDFromName(VLANName);
            SetIFVLAN(Which, ID, VTT);
            UpdateForm();
        }

        private void dgv_VLANAssignments_CurrentCellDirtyStateChanged(object sender, EventArgs e)
        {
            if (dgv_VLANAssignments.IsCurrentCellDirty)
            {
                // This fires the cell value changed handler below
                dgv_VLANAssignments.CommitEdit(DataGridViewDataErrorContexts.Commit);
            }
        }

        private void VLANConfig_Shown(object sender, EventArgs e)
        {
            BuilderWindow BW = NB.GetBuilderWin();
            if (BW != null)
            {
                Point tLocation = new Point(BW.Location.X + ((BW.Width - Width) / 2), BW.Location.Y + ((BW.Height - Height) / 2));
                Location = tLocation;
            }
        }
    }
}
