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;
using System.Text.RegularExpressions;
using System.Globalization;
using System.Resources;


namespace EduNetworkBuilder
{
    public partial class NetTestEditor : Form
    {
        NetTest ToEdit;
        NetTest OrigTest;
        List<string> HostNames = new List<string>();
        List<string> Networks = new List<string>();
        List<string> Broadcasts = new List<string>();
        List<string> Interfaces = new List<string>();
        bool processing = false;
        FirewallRule RuleToEdit;
        FirewallRule OrigRule;
        NetworkDevice FirewallDevice = null;
        bool EditingFirewallRule = false;

        public NetTestEditor(NetTest WhatToEdit)
        {
            EditingFirewallRule = false;
            InitializeComponent();
            LanguagifyTestComponents();
            OrigTest = WhatToEdit;
            ToEdit = new NetTest(OrigTest);

            Network mynet = NB.GetNetwork();
            HostNames.AddRange(mynet.GetHostnames(true));
            Networks.AddRange(mynet.GetSubnets());
            Broadcasts.AddRange(mynet.GetBroadcasts());
            UpdateForm();
        }

        public NetTestEditor(FirewallRule WhatToEdit, NetworkDevice DeviceWorkingOn)
        {
            EditingFirewallRule = true;
            InitializeComponent();
            LanguagifyFWComponents();
            OrigRule = WhatToEdit;
            FirewallDevice = DeviceWorkingOn;
            RuleToEdit = new FirewallRule(OrigRule.Source, OrigRule.Destination, OrigRule.Action);
            // Make a list of all interfaces on this device
            foreach (string nname in DeviceWorkingOn.NICNames())
            {
                NetworkCard nic = DeviceWorkingOn.NicFromName(nname);
                for (int i = 0; i < nic.IFCount; i++)
                {
                    NetworkInterface nif = nic.GetInterface(i);
                    Interfaces.Add(nif.nic_name);
                }
            }
            if (Interfaces.Count < 2)
            {
                //we cannot do firewalling on a device that has one or zero interfaces.
                Close();
            }
            UpdateForm();
        }

        private void LanguagifyTestComponents()
        {
            lblSource.Text = NB.Translate("NTE_lblSource");
            lblTest.Text = NB.Translate("NTE_lblTest");
            lblDest.Text = NB.Translate("NTE_lblDest");
            btnOK.Text = NB.Translate("_Done");
            btnCancel.Text = NB.Translate("_Cancel");
            Text = NB.Translate("NTE_Form");
        }

        private void LanguagifyFWComponents()
        {
            LanguagifyTestComponents();
            lblTest.Text = NB.Translate("NTE_lblTestFW");
        }


        private void btnOK_Click(object sender, EventArgs e)
        {
            if (EditingFirewallRule)
            {
                OrigRule.Destination = RuleToEdit.Destination;
                OrigRule.Source = RuleToEdit.Source;
                OrigRule.Action = RuleToEdit.Action;
                Close();
            }
            else
            {
                OrigTest.UpdateValuesFromAnother(ToEdit);
                OrigTest.TaskWasDone = false;  //We edited it.  Set it to false
                OrigTest.SetInitialDoneState(); //Set some of them to true (locked. etc)
                Close();
            }
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void UpdateForm()
        {
            NetworkDevice sItem;
            processing = true;
            List<string> tList = new List<string>();

            Network theNet = NB.GetNetwork();
            //We add all the hostnames as source
            if (EditingFirewallRule)
            {
                cbSource.Items.Clear();
                cbDest.Items.Clear();
                cbTest.Items.Clear();

                foreach (string one in Interfaces)
                {
                    if (one != RuleToEdit.Destination)
                        cbSource.Items.Add(one); //We add all of them except the selected destination
                    if (one != RuleToEdit.Source)
                        cbDest.Items.Add(one);  //We add all of them except the selected source
                }
                foreach (string test in Enum.GetNames(typeof(FirewallRuleType)))
                {
                    tList.Add(test);
                }
                tList.Sort(); //Sort them alphabetically.  Just to make things easier
                foreach (string test in tList)
                {
                    cbTest.Items.Add(test);
                }
                //select the current stuff
                if (cbSource.Items.Contains(RuleToEdit.Source))
                {
                    cbSource.SelectedItem = RuleToEdit.Source;
                }
                else
                {
                    if (cbSource.Items.Count > 0)
                        cbSource.SelectedIndex = 0; //select the first item
                }

                if (cbDest.Items.Contains(RuleToEdit.Destination))
                {
                    cbDest.SelectedItem = RuleToEdit.Destination;
                }
                else
                {
                    if (cbDest.Items.Count > 0)
                        cbDest.SelectedIndex = 0; //select the first item
                }

                if (cbTest.Items.Contains(RuleToEdit.Action.ToString()))
                {
                    cbTest.SelectedItem = RuleToEdit.Action.ToString();
                }
                else
                    cbTest.SelectedIndex = 0;//select first item
            }
            else
            {
                cbSource.Items.Clear();
                foreach (string host in HostNames)
                {
                    cbSource.Items.Add(host);
                }

                //The tests are just the list of available tests.
                cbTest.Items.Clear();
                foreach (string test in Enum.GetNames(typeof(NetTestType)))
                {
                    tList.Add(test);
                }
                tList.Sort(); //Sort them alphabetically.  Just to make things easier
                foreach (string test in tList)
                {
                    cbTest.Items.Add(test);
                }

                cbDest.Items.Clear();
                if (ToEdit.TheTest == NetTestType.NeedsRouteToNet)
                {   //List all the networks
                    foreach (string subnet in Networks)
                    {
                        cbDest.Items.Add(subnet);
                    }
                }
                else if (ToEdit.TheTest == NetTestType.DHCPServerEnabled)
                {
                    cbDest.Items.Add(true.ToString());
                    cbDest.Items.Add(false.ToString());
                }
                else if (ToEdit.TheTest == NetTestType.HelpRequest)
                {
                    foreach (string HelpLevel in Enum.GetNames(typeof(NetTestVerbosity)))
                    {
                        cbDest.Items.Add(HelpLevel);
                    }
                    cbDest.Items.Add("?Button");
                    cbDest.Items.Add("ViewButton");
                }
                else if (ToEdit.TheTest == NetTestType.ReadContextHelp)
                {
                    cbSource.Items.Clear();
                    List<string> theNames = new List<string>();
                    theNames.AddRange(Enum.GetNames(typeof(HelpTopics)));
                    theNames.Sort();
                    theNames.Remove("None");
                    foreach (string ContextHelp in theNames)
                    {
                        cbSource.Items.Add(ContextHelp);
                    }
                    cbDest.Items.Add(NB.Translate("_Read"));
                }
                else if (ToEdit.TheTest == NetTestType.LockAll || ToEdit.TheTest == NetTestType.LockGateway)
                {
                    cbDest.Items.Add(NB.Translate("_All"));
                }
                else if (ToEdit.TheTest == NetTestType.DeviceIsFrozen || ToEdit.TheTest == NetTestType.DeviceBlowsUpWithPower 
                    || ToEdit.TheTest == NetTestType.DeviceNeedsUPS)
                {
                    cbDest.Items.Add(ToEdit.sHost);
                }
                else if (ToEdit.TheTest == NetTestType.LockDHCP)
                {
                    //return all the dhcp ranges
                    sItem = theNet.GetDeviceFromName(ToEdit.sHost);
                    foreach (string ip in sItem.DHCPStrings(false))
                    {
                        cbDest.Items.Add(ip);
                    }
                }
                else if (ToEdit.TheTest == NetTestType.LockIP)
                {
                    //return all the dhcp ranges
                    sItem = theNet.GetDeviceFromName(ToEdit.sHost);
                    foreach (NB_IPAddress ip in sItem.IPAddressList())
                    {
                        cbDest.Items.Add(ip.GetIPString);
                    }
                }
                else if (ToEdit.TheTest == NetTestType.LockRoute)
                {
                    //return all the dhcp ranges
                    sItem = theNet.GetDeviceFromName(ToEdit.sHost);
                    if(sItem != null) 
                        foreach (NB_IPAddress ip in sItem.ListRoutes())
                        {
                            cbDest.Items.Add(ip.GetIPString);
                        }
                }
                else if (ToEdit.TheTest == NetTestType.LockNic || ToEdit.TheTest == NetTestType.DeviceNICSprays)
                {
                    //return all the dhcp ranges
                    sItem = theNet.GetDeviceFromName(ToEdit.sHost);
                    foreach (string nname in sItem.NICNames())
                    {
                        cbDest.Items.Add(nname);
                    }
                }
                else if (ToEdit.TheTest == NetTestType.LockVLANNames)
                {
                    //No items for lockvlannames
                    cbDest.Items.Add(NB.Translate("_All"));
                    cbSource.Items.Clear();
                    cbSource.Items.Add(NB.Translate("_All"));
                }
                else if (ToEdit.TheTest == NetTestType.LockNicVLAN)
                {
                    sItem = theNet.GetDeviceFromName(ToEdit.sHost);
                    foreach (string nname in sItem.NICNames())
                    {
                        NetworkCard nic = sItem.NicFromName(nname);
                        if (!nic.NicCanDoVLANs()) continue;
                        cbDest.Items.Add(nic.NicName());
                    }
                }
                else if (ToEdit.TheTest == NetTestType.LockVLANsOnHost)
                {
                    //No items for lockvlannames
                    cbDest.Items.Add(NB.Translate("_All"));
                }
                else if (ToEdit.TheTest == NetTestType.LockInterfaceVLAN)
                {
                    sItem = theNet.GetDeviceFromName(ToEdit.sHost);
                    foreach (string nname in sItem.NICNames())
                    {
                        NetworkCard nic = sItem.NicFromName(nname);
                        if (!nic.NicCanDoVLANs()) continue;
                        for (int i = 0; i < nic.IFCount; i++)
                        {
                            NetworkInterface nif = nic.GetInterface(i);
                            cbDest.Items.Add(nif.nic_name);
                        }
                    }
                }
                else if (ToEdit.TheTest == NetTestType.NeedsForbiddenVLAN ||
                    ToEdit.TheTest == NetTestType.NeedsTaggedVLAN ||
                    ToEdit.TheTest == NetTestType.NeedsUntaggedVLAN)
                {
                    sItem = theNet.GetDeviceFromName(ToEdit.sHost);
                    foreach (string nname in sItem.NICNames())
                    {
                        NetworkCard nic = sItem.NicFromName(nname);
                        if (!nic.NicCanDoVLANs()) continue;
                        for (int i = 0; i < nic.IFCount; i++)
                        {
                            NetworkInterface nif = nic.GetInterface(i);
                            foreach (VLANName vn in theNet.VlanNames)
                            {
                                cbDest.Items.Add(nif.nic_name + " - " + vn.ID.ToString());
                            }
                        }
                    }
                }
                else if(ToEdit.TheTest == NetTestType.LockLocation)
                {
                    cbDest.Items.Add("--"); //This locks it into one location
                    foreach(string name in theNet.RectangleNames())
                    {
                        cbDest.Items.Add(name);
                    }
                }
                else
                {   //List all the hosts
                    foreach (string host in HostNames)
                    {
                        cbDest.Items.Add(host);
                    }

                    if (ToEdit.TheTest == NetTestType.SuccessfullyPings || 
                        ToEdit.TheTest == NetTestType.SuccessfullyPingsWithoutLoop)
                    {   //List all the network broadcasts
                        foreach (string subnet in Broadcasts)
                        {
                            cbDest.Items.Add(subnet);
                        }
                    }
                }

                //Now we select all the appropriate items.
                if (cbSource.Items.Contains(ToEdit.sHost))
                {
                    cbSource.SelectedItem = ToEdit.sHost;
                }
                else
                {
                    if (cbSource.Items.Count > 0)
                        cbSource.SelectedIndex = 0; //select the first item
                }

                if (cbDest.Items.Contains(ToEdit.dHost))
                {
                    cbDest.SelectedItem = ToEdit.dHost;
                }
                else
                {
                    if (cbDest.Items.Count > 0)
                        cbDest.SelectedIndex = 0; //select the first item
                }

                if (cbTest.Items.Contains(ToEdit.TheTest.ToString()))
                {
                    cbTest.SelectedItem = ToEdit.TheTest.ToString();
                }
                else
                {
                    if (cbTest.Items.Count > 0)
                        cbTest.SelectedIndex = 0; //select the first item
                }
            }
            processing = false;
        }

        private void NetTestEditor_Load(object sender, EventArgs e)
        {

        }

        private bool validate_choices()
        {
            if (processing) return true; //If we are processing, we are all OK.
            Network theNet = NB.GetNetwork();
            if (EditingFirewallRule)
            {
                //The source cannot be the dest.
                //The values need to exist
                return true;
            }
            else
            {
                NetTestType ntt = NB.ParseEnum<NetTestType>(cbTest.SelectedItem.ToString());
                if (ntt == NetTestType.ReadContextHelp) return true;
                if (ntt == NetTestType.DHCPServerEnabled) return true;
                if (cbSource.SelectedItem.ToString() == cbDest.SelectedItem.ToString() && ntt != NetTestType.HelpRequest)
                    return false; //Source cannot equal dest
                if (theNet.GetDeviceFromName(cbSource.SelectedItem.ToString()) == null)
                    return false; //This should never happen with a drop-down list, but just in case...
                if (ntt == NetTestType.LockAll || ntt == NetTestType.LockDHCP || ntt == NetTestType.LockIP ||
                    ntt == NetTestType.LockNic || ntt == NetTestType.LockRoute || ntt == NetTestType.LockLocation)
                    return true;
                if (ntt == NetTestType.NeedsRouteToNet)
                {
                    //We should have a network, not a host.
                }
                else if (ntt == NetTestType.HelpRequest)
                {
                    //This uses a verbosity
                }
                else if (ntt == NetTestType.LockInterfaceVLAN || ntt == NetTestType.LockNicVLAN ||
                    ntt == NetTestType.LockVLANNames || ntt == NetTestType.LockVLANsOnHost)
                {
                    return true;
                }
                else if (ntt == NetTestType.DeviceNICSprays)
                {
                    NetworkDevice tstDevice = theNet.GetDeviceFromName(cbSource.SelectedItem.ToString());
                    if (tstDevice == null) return false;
                    NetworkCard tstNIC = tstDevice.NicFromName(cbDest.Text);
                    if (tstNIC == null) return false;
                    return true;
                }
                else if (ntt == NetTestType.NeedsUntaggedVLAN || ntt == NetTestType.NeedsTaggedVLAN ||
                    ntt == NetTestType.NeedsForbiddenVLAN)
                {
                    //We have an interface and a network ID.  Verify they exist
                    if (cbDest.SelectedIndex < 0) return false;
                    Match result = Regex.Match(cbDest.SelectedItem.ToString(), @"(?<interface>[A-z:0-9]+) - (?<id>\d+)");
                    if (result.Groups["interface"] != null && result.Groups["id"] != null)
                        return true;
                    return false;
                }
                else
                {
                    if (ntt == NetTestType.SuccessfullyPings) return true;
                    if (ntt == NetTestType.SuccessfullyPingsWithoutLoop) return true;
                    if (ntt == NetTestType.SuccessfullyTraceroutes) return true;
                    if (theNet.GetDeviceFromName(cbDest.SelectedItem.ToString()) == null)
                        return false; //This should never happen with a drop-down list, but just in case...
                }                
            }
            return true;
        }

        private void cbTest_SelectedValueChanged(object sender, EventArgs e)
        {
            if (EditingFirewallRule)
            {
                RuleToEdit.Action = NB.ParseEnum<FirewallRuleType>(cbTest.SelectedItem.ToString());
                if (!processing)
                    UpdateForm();
            }
            else
            {
                ToEdit.TheTest = NB.ParseEnum<NetTestType>(cbTest.SelectedItem.ToString());
                if (!processing)
                    UpdateForm();
            }
        }

        private void cbSource_SelectedValueChanged(object sender, EventArgs e)
        {
            if (EditingFirewallRule)
            {
                if (validate_choices() && !processing)
                {
                    RuleToEdit.Source = cbSource.SelectedItem.ToString();
                    UpdateForm();
                }
                else
                    if (!processing)
                    UpdateForm();
            }
            else
            {
                if (validate_choices())
                {
                    ToEdit.sHost = cbSource.SelectedItem.ToString();
                }
                else
                    if (!processing)
                    UpdateForm();
            }
        }

        private void cbDest_SelectedValueChanged(object sender, EventArgs e)
        {
            if (EditingFirewallRule)
            {
                if (validate_choices())
                {
                    if (!processing)
                    {
                        RuleToEdit.Destination = cbDest.SelectedItem.ToString();
                        UpdateForm();
                    }
                }
                else
                    if (!processing)
                    UpdateForm();
            }
            else
            {
                if (validate_choices())
                {
                    ToEdit.dHost = cbDest.SelectedItem.ToString();
                }
                else
                    if (!processing)
                    UpdateForm();
            }
        }

        private void NetTestEditor_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;
            }
        }
    }
}
