using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//using System.Deployment.Application;
using System.Windows.Forms;
using System.Globalization;
using System.Resources;
using System.Xml;
using System.Drawing;
using System.Media;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Xml.Serialization;
using System.IO;

namespace EduNetworkBuilder
{
    public enum PacketStatus { 
        processing, //It is inside a device. It needs to be routed, masqueraded, or whatever
        input,      //It is hitting the interface/nic of a device.   
        output,     //It is leaving a device.  Make sure the mac address is what it should be & that we are going out the right link
        waiting_for_arp,    //It is in the output chain, has been procesed, but is waiting for an arp packet to give it the dest MAC
        moving,     //It is traveling along a link. We increment the distance it has gone and re-draw the packet.
        encapsulated,       //It has been put inside another packet.
        finished_ok,//The packet has finished and is ready to be removed from the network
        finished_failed, //The packet is finished (failed) and is ready to be removed from the network.
        finished    //There was an appropriate reason this packet finished.  It stopped
    }
    public enum VLANTagType { Tagged, Untagged, Forbidden }
    public enum NetShapeType { none, circle, rectangle, }
    public enum LinkType { normal, wireless, broken }
    public enum PacketType { none, ping_request, ping_answer, arp_request, arp_answer, dhcp_request,
        dhcp_answer, vpn_packet, tun_packet, tracert_request, tracert_reply, bad_packet }
    public enum ResponseToPacket { none, accept, masq, drop, reject }
    public enum DebugLevel { none=0, info=1, routing=2, switching=4, natting=8, filtering=16, debug=32 , packet=64, all=127}
    public enum NetworkComponentType { none, router, net_switch, net_hub, laptop, pc, server, wap , tree,
        wrouter, wbridge, wrepeater, link, firewall, ip_phone, printer, copier, microwave, fluorescent, cellphone, tablet }
    public enum NicType { none, lo, eth, wlan, wan, vpn, tun, management_interface, port, wport }
    public enum IPAddressType {  ip, gw, route, ip_only }
    public enum nb_direction { none, to_src, to_dst }
    public enum GeneralComponentType { none, link, device }
    public enum NBSoundType { none, success, saved_ok, saved_failed }
    public enum RTFWindowContents { help, about, release_notes }
    public enum NetTestType { NeedsLocalIPTo, NeedsDefaultGW, NeedsLinkToDevice, NeedsRouteToNet,
        NeedsUntaggedVLAN, NeedsTaggedVLAN, NeedsForbiddenVLAN,
        SuccessfullyPings, SuccessfullyPingsAgain, SuccessfullyArps, SuccessfullyDHCPs, HelpRequest, ReadContextHelp, FailedPing,
        DHCPServerEnabled, SuccessfullyTraceroutes, SuccessfullyPingsWithoutLoop,
        LockAll, LockIP, LockRoute, LockNic, LockDHCP, LockGateway, LockLocation,
        LockVLANsOnHost, LockNicVLAN, LockInterfaceVLAN, LockVLANNames,
        DeviceIsFrozen, DeviceBlowsUpWithPower, DeviceNeedsUPS, DeviceNICSprays,
    }
    public enum AnimationName { Spark1, Fire1, Smoke1, Explo1, Lightning1 }
    public enum ContextTest {  ping, arp, traceroute }
    public enum NetTestVerbosity { none, basic, hints, full }
    public enum LBContents { routes, messages, dhcp, puzzles, regressiontest }
    public enum HelpTopics { 
        None, DHCP, DHCPServer, Firewall, Gateway, Help, IPAddress, Link, Subnet, Ping,
        VPN, Hub, Switch, ARP, StaticRoute, Subnetting, WhenToSubnet, ComparingAddresses, MACAddress,
        Network, Packet, NIC, Interface, Router, PacketCorruption, GeneralWireless, WirelessSSID, WirelessKey,
        WirelessAP, WirelessRouter, WirelessRepeater, WirelessBridge, VLAN, Power, Traceroute
    }
    public enum CaptionType {  none=0, full = 1, host =2, ip=3, host_ip=4,  }
    public enum FirewallRuleType { Allow, Drop }
    public enum SolvedNetworkNames { DHCP, OneNet, TwoNets, ThreeNets, firewalls, VLAN, InternetHomeAndOffice,
        OfficeBldgWired, OfficeBldgWireless }
    public enum PuzzleNames
    {
        Level0_IP, Level1_NoGateway, Level0_NeedsLink, Level0_NoSwitch, Level1_BadDHCP, Level1_BadGateway,
        Level0_SimpleDHCP, Level1_BadIP, Level0_Help, Level0_Ping, Level0_HubVsSwitch, Level0_Power,
        Level0_NetworkLoop2, Level0_BrokenLink, Level0_HiddenSwitch, Level0_Frozen,
        Level0_BadPower1, Level0_BadPower2,
        Level0_PacketCorruption1, Level0_PacketCorruption2, Level0_Traceroute, Level1_AddingDevices,
        Level1_MidDHCP, Level1_OneNetTwoSubnets, Level1_DuplicateIPs, Level0_NetworkLoop, Level1_DuplicateMAC,
        Level1_BadNetmask, Level1_VPNTraceroute,
        Level1_Practice1, Level1_Practice2, Level1_Practice3, Level1_Practice4, Level1_Practice5,
        Level1_Practice6, Level1_Practice7,
        Level2_FirewallDemo, Level1_OneNetTwoSubnets2, Level2_VPN_Demo, Level2_Bad_VPN_IP, Level2_Bad_Encryption,
        Level2_Bad_Route, Level2_Blast_From_Past, Level2_Not_Working, Level2_Build_A_VPN, Level2_Connect_The_Dots,
        Level2_VPN_woes, Level2_FirewallTest2, Level2_CannotConnect,
        Level3_BlackHole, Level3_Busted, Level3_Middle_Man_Out, Level3_PhoneyNetwork, Level3_VPNify, Level3_EncryptionTroubles,
        Level3_NowhereToGo, Level3_GrandCentralStation, Level3_Dead, 
        Level3_TwoDHCPServers, Level3_invisible,
        Level4_DualWans, Level4_SinglesLife, Level4_SmallSubnets, Level4_OneRoute, Level4_RouterReplacement,
        Level4_InternalSubnetting, Level4_Internalhemorrhage, Level4_WhoDidThat,
        Level5_WirelessRouters, Level5_WirelessDevices, Level5_WirelessBridge, Level5_WirelessRepeater, Level5_WirelessRepeater2,
        Level5_WirelessAccessPoint, Level5_WirelessCorruption, Level5_Failed, Level5_LostPacket, Level5_HereComesTrouble,
        Level5_APProblems, Level5_LineOfSight,
        Level5_Practice1, Level5_Practice2, Level5_Practice3, Level5_Practice4,
        Level5_Practice5, Level5_Practice6, 
        Level6_VLAN_Intro, Level6_VLAN_Intro2, Level6_Intro3_LockedOut, Level6_ForbiddenVLAN, Level6_TaggedBetweenSwitches,
        Level6_VLANRouting, Level6_VLANRouting2, level6_UntaggedAndDHCP, Level6_SorryBoss, Level6_VLANFrustrations,
        Level6_TwoAccessPoints, Level6_VlanRouting3, Level6_ConnectTheLaptop, Level6_CleanSlate, Level6_WhereFrom,
        Level6_NeedVLANs, Level6_SwitchedUp,

    }
    public enum HomeworkSolvedStatus { NeverChecked, CheckedFailed, CheckedSucceeded }
    public enum DebugPausePoint { none=0, packet_create=1, packet_kill=2, 
        packet_in=4, packet_out=8, packet_duplicate=16, all=63, 
        dump=256, pause=512}
    public enum TraversalTechnology { any, none, gateway, static_route, vlan, ethernet, wireless, firewall,
        vpn, vpn_encryption, vpn_decryption, ip_address, masquerade, forward, arrived, network_interface}
    public enum HowToBreak { PowerOff, EthernetBreak, EthernetCorrupt, EthernetRemoveLink, LockOutSwitch,
        WirelessBreakSSID, WirelessBreakKey, DeviceChangeIP, DeviceChangeGW, StaticRouteClear,
        StaticRouteCorrupt, VLANChange, VPNChangeEndpoint, VPNChangeKey, BreakDevice }
    public enum NBAction { none, newdevice, changelocation, changecomponent, deletecomponent,
        ping, traceroute, arp, cleararp, dhcp,
        replaceUPS, replace, poweroff, poweron, reset,
    }

    [Serializable]
    public struct HostNicID //This holds a unique identifier for a network card.  Links use this to know what it is connected to
    {
        public int HostID;
        public int NicID;
        public string HostName;
        public string NicName;
        public HostNicID(int host, int nic, string hostname, string nicname)
        {
            HostID = host;
            NicID = nic;
            HostName = hostname;
            NicName = nicname;
        }
        public HostNicID(XmlNode theNode)
        {
            HostID = 0;
            NicID = 0;
            HostName = "";
            NicName = "";
            foreach (XmlNode Individual in theNode.ChildNodes)
            {
                XmlNodeType myNodetype = Individual.NodeType;
                if (myNodetype == XmlNodeType.Element)
                {
                    switch (Individual.Name.ToLower())
                    {
                        case "hostid":
                            int.TryParse(Individual.InnerText, out HostID);
                            break;
                        case "nicid":
                            int.TryParse(Individual.InnerText, out NicID);
                            break;
                        case "hostname":
                            HostName = Individual.InnerText;
                            break;
                        case "nicname":
                            NicName = Individual.InnerText;
                            break;
                    }
                }
            }
        }
        public void Save(XmlWriter writer, string tag)
        {
            writer.WriteStartElement(tag);
            writer.WriteElementString("hostid", HostID.ToString());
            writer.WriteElementString("nicid", NicID.ToString());
            writer.WriteElementString("hostname", HostName);
            writer.WriteElementString("nicname", NicName);
            writer.WriteEndElement();
        }
        public string HostNicIDString
        {
            get { return HostID.ToString()+"-"+NicID.ToString(); }
        }
        public bool Equals(HostNicID toCheck)
        {
            if (HostID != toCheck.HostID) return false;
            if (NicID != toCheck.NicID) return false;
            if (HostName != toCheck.HostName) return false;
            if (NicName != toCheck.NicName) return false;
            return true;
        }

    }

    [Serializable]
    public struct IPConnectionEntry
    {
        public NB_IPAddress destIP; //where we are sending the packet to.  We expect a response to come from here
        public PacketType What; //ping, dhcp, etc
        public ResponseToPacket Response; //accept, masq
        public NB_IPAddress internalIP; //Used if we are masquerading
        public IPConnectionEntry(NB_IPAddress dest, PacketType what, ResponseToPacket response)
        {
            destIP = dest;
            What = what;
            Response = response;
            internalIP = null;
        }
        public IPConnectionEntry(NB_IPAddress dest, PacketType what, ResponseToPacket response, NB_IPAddress internal_ip)
        {
            destIP = dest;
            What = what;
            Response = response;
            internalIP = internal_ip;
        }
    }
    [Serializable]
    public class PingTestStatus
    {
        public string Source;
        public string Dest;
        public bool Succeeded = false;
    }

    [Serializable]
    public struct ArpEntry
    {
        public string MACAddress;
        public string IPAddr;
        public HostNicID NicOnWhichItIsFound;
        public ArpEntry(string mac, string ip, HostNicID thenic)
        {
            MACAddress = mac;
            IPAddr = ip;
            NicOnWhichItIsFound = thenic;
        }

        public bool Equals(ArpEntry toCompare)
        {
            if (MACAddress != toCompare.MACAddress) return false;
            if (IPAddr != toCompare.IPAddr) return false;
            if (!NicOnWhichItIsFound.Equals(toCompare.NicOnWhichItIsFound)) return false;
            return true;
        }
    }

    [Serializable]
    public class PuzzleInfo
    {
        public string PuzzleName;
        public string PuzzleTitle;
        public string PuzzleDescription;
        public List<string> PuzzleTags = new List<string>();
        public int Level=0;
        public string strLevel {  get { return "Level_" + Level; } }
        public double SortOrder=0;
        public LanguageStrings NetMessage;
        public LanguageStrings NetTitle;

        public void Load(XmlNode TheNode, string Name)
        {
            PuzzleName = Name;
            NetMessage = new LanguageStrings("message");  //Do not translate this string "message"  It is an important word
            NetTitle = new LanguageStrings("title"); //Do not translate this string "title".  It is an important word

            foreach (XmlNode Individual in TheNode.ChildNodes)
            {
                XmlNodeType myNodetype = Individual.NodeType;
                if (myNodetype == XmlNodeType.Element)
                {
                    switch (Individual.Name.ToLower())
                    {
                        case "edunetworkbuilder":
                        case "network":
                            Load(Individual, PuzzleName);
                            break;
                        case "message":
                            PuzzleDescription = Individual.InnerText;
                            break;
                        case "title":
                            PuzzleTitle = Individual.InnerText;
                            break;
                        case "tag":
                            PuzzleTags.Add(Individual.InnerText);
                            break;
                        case "level":
                            PuzzleTags.Add("Level_" + Individual.InnerText);
                            int.TryParse(Individual.InnerText, out Level);
                            break;
                        case "sortorder":
                            double.TryParse(Individual.InnerText, out SortOrder);
                            break;
                        default:
                            if (Regex.IsMatch(Individual.Name.ToLower(), "message"))
                            {
                                NetMessage.Add(Individual);
                            }
                            else
                                if (Regex.IsMatch(Individual.Name.ToLower(), "title"))
                            {
                                NetTitle.Add(Individual);
                            }

                            break;
                    }
                }
            }
        }
    }

    [Serializable]
    public class FirewallRule
    {
        public string Source;
        public string Destination;
        public FirewallRuleType Action;

        public FirewallRule() { }
        public FirewallRule(string source, string dest, FirewallRuleType action)
        {
            Source = source;
            Destination = dest;
            Action = action;
        }

        public FirewallRule(XmlNode theNode)
        {
            foreach (XmlNode Individual in theNode.ChildNodes)
            {
                XmlNodeType myNodetype = Individual.NodeType;
                if (myNodetype == XmlNodeType.Element)
                {
                    switch (Individual.Name.ToLower())
                    {
                        case "source":
                            Source = Individual.InnerText;
                            break;
                        case "destination":
                            Destination = Individual.InnerText;
                            break;
                        case "action":
                            Action = NB.ParseEnum<FirewallRuleType>(Individual.InnerText);
                            break;
                    }
                }
            }
        }

        public bool Equals(FirewallRule toCompare)
        {
            if (Source != toCompare.Source) return false;
            if (Destination != toCompare.Destination) return false;
            if (Action != toCompare.Action) return false;
            return true;
        }

        public void Save(XmlWriter writer, string tag)
        {
            writer.WriteStartElement(tag);
            writer.WriteElementString("source", Source);
            writer.WriteElementString("destination", Destination);
            writer.WriteElementString("action", Action.ToString());
            writer.WriteEndElement();
        }
    }

    [Serializable]
    public class HelpURL
    {
        public string URL = "";
        public string LangTag = "";
        public string HelpTopicString = "";
    }

    static class NB
    {

        public static string BroadcastMACString = "FF:FF:FF:FF:FF:FF";  //The broadcast MAC address
        public static string BroadcastIPString = "255.255.255.255"; //the generic broadcast IP address
        public static string ZeroIPString = "0.0.0.0";
        public static string LoopbackIPString = "127.0.0.1";
        public static int LinkStep = 8;//The percentage of the link we move at each "tick"
        public static int PacketPixelSize = 16; //The size of the packet pixel
        public static int PacketVersionNum = 2; //2 uses the new stuff.  Anything else uses the old stuff
        public const int GridSize = 10;
        public static string[,] LanguageChoices = { { NB.Translate("NB_NBEn"), "en" }, { NB.Translate("NB_NBFr"), "fr" } };
        public static int WirelessMaxUnsuccessfulLink = 120; //The link will connect, but the packet will drop
        public static int WirelessMaxSuccessfulLink = 100; //Packets will drop after this distance
        public static int WirelessReconnectDistance = 70; //Try to find a closer AP if we are this far out.
        public static int UntaggedVLAN = -1; //If the packet is not tagged.
        public static int MaxPacketsBeforeOptimizing = 50;
        public static int DefaultPasswordLen = 6;
        public static int DefaultMachinePasswordLen = 20;
        public static int DefaultSaltLen = 50;
        public static int NormalRotation = 5;
        public static int PacketDamageDistance = 25;

        public static bool DebugActions = false;
        public static bool DebugTests = false;

        public static int NumBadPackets = 7; //the number of packets to spray out

        public static string AllowedPasswordCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-=!~@#$%^&*()_+{}[]/?<>,.";
        public static string AllowedUsernameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890._";

        public static int MillisecondsBetweenReplays = 500;
        public static int MillisecondsBetweenPacketMoves = 15;
        /// <summary>
        /// Find the global random number generator.
        /// </summary>
        /// <returns>A valid random number generator</returns>
        public static Random GetRandom()
        {
            BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"];
            if (myWin == null) return new Random();
            if (myWin.GameRandomGen == null) return new Random();
            return myWin.GameRandomGen;
        }
        /// <summary>
        /// Find the global random number generator.
        /// </summary>
        /// <returns>A valid random number generator</returns>
        public static CultureInfo GetCulture(NBSettings theSettings = null)
        {
            BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"];
            CultureInfo CI=null;
            NBSettings oursettings;

            if (theSettings == null) oursettings = NB.GetSettings();
            else oursettings = theSettings;

            if (myWin != null)
            {
                CI = myWin.GetCulture();
            }
            if(CI == null || myWin == null)
            {
                string CL = oursettings.ChosenLanguage;
                CI = CultureInfo.CreateSpecificCulture(CL);
            }
            return CI;
        }
        /// <summary>
        /// Find the global random number generator.
        /// </summary>
        /// <returns>A valid random number generator</returns>
        public static ResourceManager GetResource()
        {
            ResourceManager myresource = null;
            BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"];
            if (myWin != null)
            {
                myresource = myWin.GetResource();
            }
            if(myresource == null || myWin == null)
            {
                System.Reflection.Assembly MyAssembly;
                MyAssembly = Assembly.GetCallingAssembly();
                myresource = new ResourceManager("EduNetworkBuilder.Resources.languages.edustrings", MyAssembly);
            }
            return myresource;
        }

        public static NBSettings GetSettings()
        {
            //Try getting the user settings
            PersonClass User = GetUser();
            if (User != null) return User.UserSettings;

            //If no user, get the settings for the program.
            BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"];
            if (myWin != null)
            {
                return myWin.OurSettings;
            }
            return new NBSettings(); //This is only in case we are blowing up.  Try to avoid that.
        }

        /// <summary>
        /// Determine if we are using Mono or .Net.  Some things get killed using Mono.
        /// </summary>
        /// <returns>True if we are using Mono</returns>
        public static bool IsRunningOnMono()
        {
            return Type.GetType("Mono.Runtime") != null;
        }

        public static void NoteLoopHappened()
        {
            Network myNet = GetNetwork();
            if (myNet != null) myNet.HadLoop = true;
        }

        public static Point GetSnapped(Point Location)
        {
            int x = (Location.X / NB.GridSize) * NB.GridSize;
            int y = (Location.Y / NB.GridSize) * NB.GridSize;
            Point newlocation = new Point(x, y);
            return newlocation;
        }

        public static Network GetNetwork()
        {
            BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"];
            if (myWin == null) return null;
            if (myWin.GameRandomGen == null) return null;
            return myWin.GetNetwork();
        }

        public static void RegisterInvisibleNetwork(Network ToRegister)
        {
            BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"];
            if (myWin == null) return;
            myWin.RegisterInvisibleNet(ToRegister);
        }

    
        public static void UnregisterInvisibleNetwork()
        {
            BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"];
            if (myWin == null) return;
            myWin.UnregisterInvisibleNet();
        }

        public static bool ProcessingInvisibleNetwork()
        {
            BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"];
            if (myWin == null) return false;
            return myWin.ProcessingInvisibleNet();
        }

        /// <summary>
        /// Make sure we update the visuals when we have the opportunity to do so
        /// </summary>
        public static void MarkToUpdate()
        {
            BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"];
            if (myWin == null) return;
            myWin.NeedsUpdate = true;
        }

        public static int nextPacketID()
        {
            BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"];
            if (myWin == null) return 1;  //return something.
            return myWin.nextPacketID();
        }

        public static BuilderWindow GetBuilderWin()
        {
            BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"];
            if (myWin == null) return null;
            return myWin;
        }

        public static void SetBuilderWindowStatis(string text)
        {
            BuilderWindow myWin = GetBuilderWin();
            if (myWin != null)
                myWin.ChangeStatusText(text);
        }

        public static PersonProfileForm GetProfileWin()
        {
            PersonProfileForm myWin = (PersonProfileForm)Application.OpenForms["PersonProfileForm"];
            if (myWin == null) return null;
            return myWin;
        }
        public static PersonClass GetUser()
        {
            BuilderWindow BW = GetBuilderWin();
            if (BW == null) return null;
            return BW.CurrentUser;
        }

        /// <summary>
        /// Return a translated string in the current chosen language
        /// </summary>
        /// <param name="key">The key for the item we are translating</param>
        /// <returns>A string of the translated information</returns>
        public static string Translate(string key, NBSettings theSettings=null)
        {
            BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"];
            if (myWin == null)
            {
                ResourceManager RM = GetResource();
                CultureInfo CI = GetCulture(theSettings);

                string answer="";
                answer = RM.GetString(key, CI);
                if (answer == null) return "";
                return answer;
            }
            return myWin.Translate(key);
        }

        public static string GetHelpTopicKey(HelpTopics What)
        {
            return "H_" + What.ToString() + "_Key";
        }
        public static string GetHelpTopicTitle(HelpTopics What)
        {
            return "H_" + What.ToString() + "_Title";
        }

        public static DebugPausePoint GetDebugPauseSetting()
        {
            BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"];
            if (myWin == null) return DebugPausePoint.none;
            if (myWin.GameRandomGen == null) return DebugPausePoint.none;
            return myWin.DebugSetting;
        }

        public static PuzzleInfo GetPuzzleInfoFromName(string PuzzleName)
        {
            BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"];
            if (myWin == null) return null;
            return myWin.PuzzleInfoFromName(PuzzleName);
        }

        public static string LeftPad(string what, int amount=-1)
        {
            int UseAmount = 10;
            if (amount != -1) UseAmount = amount;
            string format = "{0," + (0 - UseAmount).ToString() + "}";
            string mystring = string.Format(format, what);
            return mystring;
        }

        public static void ChangeLanguage(NBSettings theSettings=null)
        {
            //Find the window.  If it exists, use /set the language setting there.  If not, use / set the default.
            BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"];
            NBSettings oursettings;

            if (theSettings == null) oursettings = NB.GetSettings();
            else oursettings = theSettings;

            string lang = oursettings.ChosenLanguage;
            if (lang == "") lang = "en";

            string StartingItem = "";
            for (int i = 0; i < LanguageChoices.GetLength(0); i++)
            {
                if (lang == LanguageChoices[i, 1])
                {
                    StartingItem = LanguageChoices[i, 0];
                }
            }


            //we need to choose a language:
            Form LanguageForm = new Form();
            LanguageForm.Text = NB.Translate("NB_ChangeLang1");
            Label lblText = new Label();
            lblText.Location = new Point(5, 5);
            lblText.AutoSize = true;
            lblText.Text = NB.Translate("NB_ChangeLang2");
            LanguageForm.Icon = Properties.Resources.NBIco;

            ComboBox cbQuestions = new ComboBox();
            cbQuestions.Location = new Point(lblText.Location.X + lblText.Width + 10, lblText.Location.Y);
            cbQuestions.Width = 60;
            for (int i = 0; i < LanguageChoices.GetLength(0); i++ )
            {
                cbQuestions.Items.Add(LanguageChoices[i,0]);
            }
            if(cbQuestions.Items.Contains(StartingItem))
            {
                cbQuestions.SelectedItem = StartingItem;
            }
            else
                cbQuestions.SelectedIndex = 0;

            LanguageForm.Width = cbQuestions.Location.X + cbQuestions.Width + 70;
            LanguageForm.Height = 90;
            LanguageForm.AutoSize = true;

            Button btnAccept = new Button();
            btnAccept.Location = new Point(cbQuestions.Location.X, cbQuestions.Location.Y + cbQuestions.Height + 10);
            btnAccept.Text = NB.Translate("_OK");
            btnAccept.Click += (s, g) => { Button b = (Button)s; Form f = (Form)b.Parent; f.Close(); };

            LanguageForm.Controls.Add(lblText);
            LanguageForm.Controls.Add(cbQuestions);
            LanguageForm.Controls.Add(btnAccept);

            LanguageForm.ShowDialog();
            if (cbQuestions.SelectedIndex >= 0)
            {
                oursettings.LanguageHasBeenChosen = true;
                string mychoice = LanguageChoices[cbQuestions.SelectedIndex, 1];
                if (myWin == null)
                {
                    oursettings.ChosenLanguage = mychoice;
                    //oursettings.Save(); //We do this when we exit.  No need to save it right this instant.
                }
                else
                {
                    myWin.ChosenLanguage = mychoice;
                }
            }
        }



        public static void PlaySound(NBSoundType What)
        {
            BuilderWindow BW = GetBuilderWin();
            if (BW != null && BW.ProcessingInvisibleNet())
                return; //Do not ding if we are doing invisible stuff
            SoundPlayer sndClick;
            switch (What)
            {
                case NBSoundType.none:
                    break;
                case NBSoundType.success:
                    sndClick = new SoundPlayer(Properties.Resources.wavBellDing);
                    sndClick.Play();
                    break;
                case NBSoundType.saved_failed:
                    sndClick = new SoundPlayer(Properties.Resources.noBeep);
                    sndClick.Play();
                    break;
                case NBSoundType.saved_ok:
                    sndClick = new SoundPlayer(Properties.Resources.click);
                    sndClick.Play();
                    break;

            }
        }

        /// <summary>
        /// Serialize any serializable class to an XML string.
        /// </summary>
        /// <typeparam name="T">The type of object</typeparam>
        /// <param name="toSerialize">The object to serialize</param>
        /// <returns>A string containing the serialized object in XML</returns>
        public static string SerializeObject<T>(T toSerialize)
        {
            XmlSerializer xmlSerializer = new XmlSerializer(toSerialize.GetType());

            using (StringWriter textWriter = new StringWriter())
            {
                xmlSerializer.Serialize(textWriter, toSerialize);
                return textWriter.ToString();
            }
        }

        /// <summary>
        /// Deserialize (oposite of SerializeObject) an object from an xml string.
        /// </summary>
        /// <typeparam name="T">The type of object to deserialize</typeparam>
        /// <param name="toDeserialize">the xml string containing the object</param>
        /// <returns>An object of the specified type</returns>
        public static T Deserialize<T>(string toDeserialize)
        {
            XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
            StringReader textReader = new StringReader(toDeserialize);
            return (T)xmlSerializer.Deserialize(textReader);
        }

        public static List<string> GetPuzzleTags()
        {
            BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"];
            if (myWin == null) return null;
            return myWin.GetPuzzleTags();
        }

        public static bool PuzzleLevelHasUnsolved(string LevelName)
        {
            BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"];
            if (myWin == null) return false;
            return myWin.PuzzleLevelHasUnsolved(LevelName);
        }

        public static List<string> GetPuzzleNames()
        {
            BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"];
            if (myWin == null) return null;
            return myWin.GetPuzzleNames();
        }

        public static void LoadNetworkFromResource(string resource)
        {
            BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"];
            if (myWin == null) return;
            myWin.LoadNetworkFromResource(resource);
        }

        public static void SetProgress(double HowFar, double total)
        {
            BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"];
            if (myWin == null) return;
            myWin.SetProgress(HowFar, total);
        }

        public static void UpdateMessages()
        {
            BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"];
            if (myWin == null) return;
            myWin.UpdateMessages();
        }

        public static int GetUniqueIdentifier()
        {
            Network myNet = GetNetwork();
            if(myNet == null)
            {
                //We should never get here.  If so, we are in a bad sort of way.
                Random rnd = GetRandom();
                return rnd.Next(1,100);
            }
            return myNet.GetUniqueIdentifier();
        }

        public static void Delay(int amount)
        {
            System.Threading.Thread.Sleep(amount);
        }

        public static T ParseEnum<T>(string value)
        {
                // Do not initialize this variable here.
                return (T)Enum.Parse(typeof(T), value, true);                
        }

        public static T TryParseEnum<T>(string value, T Default )
        {
            if (!Enum.IsDefined(typeof(T), value))
                return Default;

            return (T)Enum.Parse(typeof(T), value);
        }

        public static GeneralComponentType GetComponentType(NetworkComponent What)
        {
            GeneralComponentType theType = GeneralComponentType.none;
            if(What.GetType().ToString() == "EduNetworkBuilder.NetworkDevice")
                theType = GeneralComponentType.device;
            if (What.GetType().ToString() == "EduNetworkBuilder.NetworkLink")
                theType = GeneralComponentType.link;
            return theType;
        }

        public static void ReadContextHelp(HelpTopics What)
        {
            RTFWindow tForm = null;
            //make a new window if needed
            foreach(Form myfrm in Application.OpenForms)
            {
                if(myfrm.Name == NB.Translate("NB_RdCtxtHelp"))
                {
                    //We have a context window
                    tForm = (RTFWindow)myfrm;
                    break;
                }
            }
            if(tForm == null)
            { 
                //We do not have one yet.  Make a new one
                tForm = new RTFWindow(RTFWindowContents.help);
                tForm.Name = NB.Translate("NB_RdCtxtHelp");
            }
            //load help
            tForm.Show();
            //Jump to the correct location
            if(tForm != null)
            {
                tForm.JumpToSelection(What);
            }
        }

        public static string GenerateMACAddress()
        {
            var sBuilder = new StringBuilder();
            var random = GetRandom();
            int number;
            byte b;
            for (int i = 0; i < 6; i++)
            {
                number = random.Next(0, 255);
                b = Convert.ToByte(number);
                if (i == 0)
                {
                    b = setBit(b, 6); //--> set locally administered
                    b = unsetBit(b, 7); // --> set unicast 
                }
                sBuilder.Append(number.ToString("X2"));
            }
            string mac= sBuilder.ToString().ToUpper();
            if (MAC_Exists(mac))
                return GenerateMACAddress(); //If it already exists, generate another
            return mac;
        }

        public static string TextPromptBox(string Prompt, Icon theIcon=null, bool isPassword = false)
        {
            return TextPromptBox(Prompt, "", "", theIcon, isPassword);
        }
        public static string TextPromptBox(string Prompt, string Title, Icon theIcon = null, bool isPassword=false)
        {
            return TextPromptBox(Prompt, Title, "", theIcon, isPassword);
        }
        public static string TextPromptBox(string Prompt, string Title, string oldtext, Icon theIcon, bool isPassword)
        {
            //we need to choose a language:
            int yspace = 10;
            Form TextInputForm = new Form();
            TextInputForm.Text = Title;
            Label lblText = new Label();
            lblText.Location = new Point(5, 5);
            lblText.AutoSize = true;
            lblText.Text = Prompt;
            if(theIcon != null)
                TextInputForm.Icon = theIcon;
            if (oldtext == null) oldtext = "";

            TextBox tbEvent = new TextBox();
            tbEvent.Location = new Point(lblText.Location.X, lblText.Location.Y + lblText.Height + yspace);
            tbEvent.Width = 120;
            tbEvent.Text = oldtext;//Populate it with the old data if we can
            if (isPassword)
                tbEvent.PasswordChar = '*';

            TextInputForm.Width = tbEvent.Location.X + tbEvent.Width + 30;
            TextInputForm.Height = 90;
            TextInputForm.AutoSize = true;

            Button btnAccept = new Button();
            btnAccept.Location = new Point(tbEvent.Location.X, tbEvent.Location.Y + tbEvent.Height + yspace);
            btnAccept.Text = "OK";
            btnAccept.Click += (s, g) => { Button b = (Button)s; Form f = (Form)b.Parent; f.Close(); };

            Button btnCancel = new Button();
            btnCancel.Location = new Point(btnAccept.Location.X + btnAccept.Width + 10, tbEvent.Location.Y + tbEvent.Height + 10);
            btnCancel.Text = "Cancel";
            btnCancel.Click += (s, g) => { Button b = (Button)s; Form f = (Form)b.Parent; tbEvent.Text = ""; f.Close(); };


            TextInputForm.Controls.Add(lblText);
            TextInputForm.Controls.Add(tbEvent);
            TextInputForm.Controls.Add(btnAccept);
            TextInputForm.Controls.Add(btnCancel);

            TextInputForm.AcceptButton = btnAccept;
            TextInputForm.CancelButton = btnCancel;

            TextInputForm.ShowDialog();
            return tbEvent.Text;
        }


        public static Dictionary<string, bool> CheckPromptBox(Dictionary<string, bool> Checks)
        {
            return CheckPromptBox(Checks, "", null);
        }
        public static Dictionary<string, bool> CheckPromptBox(Dictionary<string, bool> Checks, string Title)
        {
            return CheckPromptBox(Checks, Title, null);
        }
        public static Dictionary<string, bool> CheckPromptBox(Dictionary<string,bool> Checks, string Title, Icon theIcon)
        {
            //we need to choose a language:
            Dictionary<string, bool> responses = new Dictionary<string, bool>();

            int yspace = 10;
            Form CheckInputForm = new Form();
            CheckInputForm.Text = Title;
            if (theIcon != null)
                CheckInputForm.Icon = theIcon;

            int startx = 20;

            int y = 0;
            int lastY = 0;
            int lastHeight = 0;
            foreach(KeyValuePair<string, bool> entry in Checks)
            {
                //Make a checkbox
                CheckBox cb = new CheckBox();
                cb.Name = entry.Key;  //Name it so we can know what it is.
                cb.Text = entry.Key;  //Have it display the right value for a label
                cb.Checked = entry.Value; //Have it checked, or not, depending on the value we passed in

                //Put it in the appropriate location
                cb.Location = new Point(startx, (y * (cb.Height + yspace)) + yspace);
                cb.AutoSize = true;
                lastY = cb.Location.Y;
                lastHeight = cb.Height;
                CheckInputForm.Controls.Add(cb);
                y++;
            }
                        
            CheckInputForm.AutoSize = true;

            Button btnAccept = new Button();
            btnAccept.Location = new Point(startx, lastY + lastHeight + yspace);
            btnAccept.Text = "OK";
            btnAccept.Click += (s, g) => { Button b = (Button)s; Form f = (Form)b.Parent; f.Close(); };

            Button btnCancel = new Button();
            btnCancel.Location = new Point(btnAccept.Location.X + btnAccept.Width + 10,btnAccept.Location.Y);
            btnCancel.Text = "Cancel";
            btnCancel.Click += (s, g) => { Button b = (Button)s; Form f = (Form)b.Parent; responses = null; f.Close(); };

            CheckInputForm.Controls.Add(btnAccept);
            CheckInputForm.Controls.Add(btnCancel);

            CheckInputForm.AcceptButton = btnAccept;
            CheckInputForm.CancelButton = btnCancel;
            CheckInputForm.Height = btnCancel.Location.Y + btnCancel.Height + 10;

            CheckInputForm.ShowDialog();
            foreach (KeyValuePair<string, bool> entry in Checks)
            {
                if(responses != null && CheckInputForm.Controls[entry.Key] != null && CheckInputForm.Controls[entry.Key] is CheckBox)
                {
                    CheckBox One = (CheckBox)CheckInputForm.Controls[entry.Key];
                    responses.Add(One.Name, One.Checked);
                }
            }
            return responses;
        }

        public static bool MAC_Exists(string MAC)
        {
            Network myNet = GetNetwork();
            if(myNet == null) return false;
            return myNet.MAC_Exists(MAC);
        }

        public static List<string> arp(UInt32 IP)
        {
            List<string> arps = new List<string>();
            Network myNet = GetNetwork();
            if (myNet == null) return arps;
            return myNet.arp(IP);
        }

        private static byte setBit(byte b, int BitNumber)
        {
            if (BitNumber < 8 && BitNumber > -1)
            {
                return (byte)(b | (byte)(0x01 << BitNumber));
            }
            else
            {
                throw new InvalidOperationException(
                string.Format(NB.Translate("NB_BitError"), BitNumber.ToString()));
            }
        }

        private static byte unsetBit(byte b, int BitNumber)
        {
            if (BitNumber < 8 && BitNumber > -1)
            {
                return (byte)(b | (byte)(0x00 << BitNumber));
            }
            else
            {
                throw new InvalidOperationException(
                string.Format(NB.Translate("NB_BitError"), BitNumber.ToString()));
            }
        }

        /// <summary>
        /// Randomize a list
        /// </summary>
        /// <typeparam name="T">The type of list to return</typeparam>
        /// <param name="list">The list to randomize</param>
        /// <returns>a new list that is randomized</returns>
        public static List<T> Randomize<T>(List<T> list)
        {

            List<T> randomizedList = new List<T>(list);
            Random rnd = GetRandom();
            int n = randomizedList.Count;
            int counter = 0;
            T value;
            while (n > 1)
            {
                n--;
                int k = rnd.Next(n + 1);
                value = randomizedList[k];
                randomizedList[k] = randomizedList[n];
                randomizedList[n] = value;
                counter++;
                if (counter > 10)
                {
                    counter = 0;
                }
            }
            return randomizedList;
        }

        public static void AddNetMessage(string host, string message)
        {
            Network thenet = GetNetwork();
            //Console.WriteLine("Adding message: " + host + " : " + message);
            if (thenet == null) return; //we cannot add it.  do not blow up
            thenet.AddMessage(new PacketMessage(host, message));
        }

        public static bool OpenURLInExternalBrowser(string URL)
        {
            Uri uriResult;
            bool result = Uri.TryCreate(URL, UriKind.Absolute, out uriResult)
                && (uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps);
            if(result)
            {
                System.Diagnostics.Process.Start(URL);
            }
            return false;
        }

        public static List<TreeNode> GetAllNodes(this TreeView _self)
        {
            List<TreeNode> result = new List<TreeNode>();
            foreach (TreeNode child in _self.Nodes)
            {
                result.AddRange(child.GetAllNodes());
            }
            return result;
        }
        public static List<TreeNode> GetAllNodes(this TreeNode _self)
        {
            List<TreeNode> result = new List<TreeNode>();
            result.Add(_self);
            foreach (TreeNode child in _self.Nodes)
            {
                result.AddRange(child.GetAllNodes());
            }
            return result;
        }
        public static bool ValidateString(string tovalidate, string AllowedCharacters)
        {
            if (tovalidate == null || tovalidate == "") return false;
            if (AllowedCharacters == null || AllowedCharacters == "") return false;
            foreach (char one in tovalidate)
                if (!AllowedCharacters.Contains(one)) return false;
            return true;
        }
        public static bool ValidatePassword(string password)
        {
            return ValidateString(password, AllowedPasswordCharacters);
        }
        public static bool ValidateUsername(string password)
        {
            return ValidateString(password, AllowedUsernameCharacters);
        }
        public static bool ValidateFullName(string password)
        {
            return ValidateString(password, AllowedUsernameCharacters + " ");
        }

        public static OpenFileDialog SelectDirectoryDialog(string Title, string InitialDirectory="")
        {
            OpenFileDialog OFD = new OpenFileDialog();
            OFD.Title = Title;
            if (InitialDirectory != "")
                OFD.InitialDirectory = InitialDirectory;
            OFD.ValidateNames = false;
            OFD.CheckFileExists = false;
            OFD.CheckPathExists = true;
            OFD.FileName = NB.Translate("PPF_SelectThisFolder");
            DialogResult answer = OFD.ShowDialog();
            if (answer == DialogResult.Cancel) OFD.FileName = ""; //This is how we cancel out
            return OFD;
        }


        /// <summary>
        /// Move a file out of the way, making a rotating backup at the same time.
        /// </summary>
        /// <param name="SourceFileWithDir">A source filename with a directory</param>
        /// <param name="DestDir">The directory where to put the file</param>
        /// <param name="rotation">The number of rotation backups to make</param>
        public static void MoveFileWithRotation(string SourceFileWithDir, string DestDir, int rotation)
        {
            if (!File.Exists(SourceFileWithDir)) return; //we do not rotate if the source does not exist
            if (!Directory.Exists(DestDir))
                Directory.CreateDirectory(DestDir);
            //Rotate the old file first, then move the new one over.
            string dest_file = Path.Combine(DestDir, Path.GetFileName(SourceFileWithDir));
            RotateFile(dest_file, rotation);
            File.Move(SourceFileWithDir, dest_file);
        }

        /// <summary>
        /// Move a file out of the way, making a rotating backup at the same time.  backup to appdata
        /// </summary>
        /// <param name="SourceFileWithDir">A source filename with a directory</param>
        /// <param name="rotation">The number of rotation backups to make</param>
        public static void MoveFileWithRotation(string SourceFileWithDir, int rotation)
        {
            string StandardDest = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "EduNetworkBuilder");
            MoveFileWithRotation(SourceFileWithDir, StandardDest, rotation);
        }

        /// <summary>
        /// Move a file out of the way, making a rotating backup at the same time.  backup to appdata
        /// </summary>
        /// <param name="SourceFileWithDir">A source filename with a directory</param>
        public static void MoveFileWithRotation(string SourceFileWithDir)
        {
            string StandardDest = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "EduNetworkBuilder");
            MoveFileWithRotation(SourceFileWithDir, StandardDest, NB.NormalRotation);
        }

        /// <summary>
        /// Given a file, rotate it with the specified number of versions.
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="count"></param>
        public static void RotateFile(string filename, int count)
        {
            if (count < 1) return;
            string currentfile = GenFilenameWithInt(filename, count);
            string rotatefile;
            if (File.Exists(currentfile)) File.Delete(currentfile); //The last rotation gets deleted
            for(int i=count -1; i >= 1; i--)
            {
                currentfile = GenFilenameWithInt(filename, i);
                rotatefile = GenFilenameWithInt(filename, i + 1);
                if (File.Exists(currentfile))
                    File.Move(currentfile, rotatefile);
            }
            //The final case is when there is no version number on the file.
            currentfile = filename;
            rotatefile = GenFilenameWithInt(filename, 1);
            if (File.Exists(currentfile))
                File.Move(currentfile, rotatefile);
        }

        private static string GenFilenameWithInt(string filename, int version)
        {
            string FileOnly = Path.GetFileNameWithoutExtension(filename);
            string FileWithInt = FileOnly + "-" + version.ToString("00") + Path.GetExtension(filename);
            string Combined = Path.Combine(Path.GetDirectoryName(filename), FileWithInt);
            return Combined;
        }

        public static Font GetFont()
        {
            PersonProfileForm PPF = GetProfileWin();
            if (PPF != null) return PPF.GetFont();
            return new Font(FontFamily.GenericSansSerif, 10.0F, FontStyle.Bold);
        }

        public static void NotImplimentedMessage()
        {
            MessageBox.Show(Translate("NB_NotImplimented"));
        }

        public static string CSVSafeString(string source)
        {
            string dest = source;
            char[] chars = { '\t', '\r', '\n', '\"', ',' };

            if (dest.IndexOfAny(chars) >= 0)
            {
                dest = '\"' + dest.Replace("\"", "\"\"") + '\"'; //quotes around outside, replace " with ""
            }
            return dest;
        }

        /// <summary>
        /// return a list of ways to break a given technology
        /// </summary>
        /// <param name="What"></param>
        /// <returns></returns>
        public static List<HowToBreak> WaysToBreakATechnology(TraversalTechnology What)
        {
            switch(What)
            {
                case TraversalTechnology.ethernet:
                    return new List<HowToBreak>() { HowToBreak.EthernetBreak, HowToBreak.EthernetCorrupt, HowToBreak.EthernetRemoveLink };
                case TraversalTechnology.forward:
                    return new List<HowToBreak>() { HowToBreak.PowerOff, HowToBreak.LockOutSwitch };
                case TraversalTechnology.gateway:
                    return new List<HowToBreak>() { HowToBreak.DeviceChangeGW };
                case TraversalTechnology.firewall:
                    return new List<HowToBreak>() { };
                case TraversalTechnology.ip_address:
                    return new List<HowToBreak>() { HowToBreak.DeviceChangeIP };
                case TraversalTechnology.masquerade:
                    return new List<HowToBreak>() { };
                case TraversalTechnology.static_route:
                    return new List<HowToBreak>() { HowToBreak.StaticRouteClear, HowToBreak.StaticRouteCorrupt };
                case TraversalTechnology.vlan:
                    return new List<HowToBreak>() { HowToBreak.VLANChange};
                case TraversalTechnology.vpn:
                    return new List<HowToBreak>() { HowToBreak.VPNChangeEndpoint, HowToBreak.VPNChangeKey };
                case TraversalTechnology.vpn_decryption:
                    return new List<HowToBreak>() { HowToBreak.VPNChangeKey };
                case TraversalTechnology.vpn_encryption:
                    return new List<HowToBreak>() { HowToBreak.VPNChangeKey };
                case TraversalTechnology.wireless:
                    return new List<HowToBreak>() { HowToBreak.WirelessBreakKey, HowToBreak.WirelessBreakSSID };
            }
            return new List<HowToBreak>(); //An empty list
        }

        public static TraversalTechnology TechnologyNeededToBreak(HowToBreak How)
        {
            switch(How)
            {
                case HowToBreak.DeviceChangeGW:
                    return TraversalTechnology.gateway;
                case HowToBreak.DeviceChangeIP:
                    return TraversalTechnology.network_interface;
                case HowToBreak.EthernetBreak:
                case HowToBreak.EthernetCorrupt:
                case HowToBreak.EthernetRemoveLink:
                    return TraversalTechnology.ethernet;
                case HowToBreak.LockOutSwitch:
                    return TraversalTechnology.forward; //we can only lock ourselves out of switchs and hubs
                case HowToBreak.PowerOff:
                    return TraversalTechnology.any; //Any will only return devices
                case HowToBreak.StaticRouteClear:
                case HowToBreak.StaticRouteCorrupt:
                    return TraversalTechnology.static_route;
                case HowToBreak.VLANChange:
                    return TraversalTechnology.vlan;
                case HowToBreak.VPNChangeEndpoint:
                    return TraversalTechnology.vpn;
                case HowToBreak.VPNChangeKey:
                    return TraversalTechnology.vpn;
                case HowToBreak.WirelessBreakKey:
                case HowToBreak.WirelessBreakSSID:
                    return TraversalTechnology.wireless;
                case HowToBreak.BreakDevice:
                    return TraversalTechnology.any;
            }
            return TraversalTechnology.none;
        }

        #region Generic XML Funcs


        public static T LoadObjectFromXmlFile<T>(string XMLResourceToLoad) where T : new()
        {
            //Load in the sprite data
            XmlSerializer serializer = new XmlSerializer(typeof(T));

            System.Reflection.Assembly thisExe;
            thisExe = System.Reflection.Assembly.GetExecutingAssembly();
            // Creates the ResourceManager.
            System.Resources.ResourceManager myManager = Properties.Resources.ResourceManager;

            // Retrieves String and Image resources.
            object titem = myManager.GetObject(XMLResourceToLoad);
            byte[] item = (byte[])System.Text.Encoding.UTF8.GetBytes((string)titem);

            try
            {
                return (T)serializer.Deserialize(new MemoryStream(item));
            }
            finally
            {

            }
        }

        /// <summary>
        /// Writes the given object instance to an XML file.
        /// <para>Only Public properties and variables will be written to the file. These can be any type though, even other classes.</para>
        /// <para>If there are public properties/variables that you do not want written to the file, decorate them with the [XmlIgnore] attribute.</para>
        /// <para>Object type must have a parameterless constructor.</para>
        /// </summary>
        /// <typeparam name="T">The type of object being written to the file.</typeparam>
        /// <param name="filePath">The file path to write the object instance to.</param>
        /// <param name="objectToWrite">The object instance to write to the file.</param>
        public static void WriteToXmlFile<T>(string filePath, T objectToWrite) where T : new()
        {
            TextWriter writer = null;
            try
            {
                var serializer = new XmlSerializer(typeof(T));
                writer = new StreamWriter(filePath);
                serializer.Serialize(writer, objectToWrite);
            }
            finally
            {
                if (writer != null)
                    writer.Close();
            }
        }

        /// <summary>
        /// Reads an object instance from an XML file.
        /// <para>Object type must have a parameterless constructor.</para>
        /// </summary>
        /// <typeparam name="T">The type of object to read from the file.</typeparam>
        /// <param name="filePath">The file path to read the object instance from.</param>
        /// <returns>Returns a new instance of the object read from the XML file.</returns>
        public static T ReadFromXmlFile<T>(string filePath) where T : new()
        {
            TextReader reader = null;
            try
            {
                var serializer = new XmlSerializer(typeof(T));
                reader = new StreamReader(filePath);
                return (T)serializer.Deserialize(reader);
            }
            finally
            {
                if (reader != null)
                    reader.Close();
            }
        }

        /// <summary>
        /// Reads an object instance from an XML resource.
        /// <para>Object type must have a parameterless constructor.</para>
        /// </summary>
        /// <typeparam name="T">The type of object to read from the file.</typeparam>
        /// <param name="filePath">The name of the resource to use.</param>
        /// <returns>Returns a new instance of the object read from the XML resource.</returns>
        public static T ReadFromXmlResource<T>(string resource) where T : new()
        {
            System.Reflection.Assembly MyAssembly;
            BuilderWindow tWin = GetBuilderWin();
            MyAssembly = tWin.GetType().Assembly;

            // Creates the ResourceManager.
            System.Resources.ResourceManager myManager = new
               System.Resources.ResourceManager("EduNetworkBuilder.Properties.Resources",
               MyAssembly);

            // Retrieves String and Image resources.
            //System.String myString;
            byte[] item = Encoding.UTF8.GetBytes((string)myManager.GetObject(resource));
            // myString = new StreamReader(new MemoryStream(item), true).ReadToEnd(*/);
            //myString = System.Text.Encoding.Default.GetString(item);

            //TextReader reader = null;
            try
            {
                var serializer = new XmlSerializer(typeof(T));
                return (T)serializer.Deserialize(new MemoryStream(item));
            }
            catch(Exception e)
            {
                MessageBox.Show(e.ToString());
            }
            return default(T);
        }
        #endregion

        #region ActionFunctions
        public static void RegisterAction(ActionClass What)
        {
            if (What == null) return;
            NBSettings mySettings = GetSettings();
            if (mySettings == null) return;
            mySettings.RegisterActionDone(What);
        }

        public static void DoActionMoveDevice(int HostID, Point Location)
        {
            //Make an action for the location, register the action, and do the action
            ActionClass AC = new ActionClass();
            AC.Action = NBAction.changelocation;
            AC.SourceID = HostID;
            AC.Location = Location;

            RegisterAction(AC);

            AC.DoAction();
        }

        public static NetworkComponent DoActionAddDevice(NetworkComponentType WhatType, Point Location)
        {
            //Make an action for the location, register the action, and do the action
            ActionClass AC = new ActionClass();
            AC.Action = NBAction.newdevice;
            AC.newItemType = WhatType;
            AC.Location = Location;

            RegisterAction(AC);

            AC.DoAction();

            return AC.ChangedComponent;
        }

        public static void DoActionPingDevice(int HostID, NB_IPAddress Destination)
        {
            ActionClass AC = new ActionClass();
            AC.Action = NBAction.ping;
            AC.SourceID = HostID;
            AC.Destination = new NB_IPAddress(Destination);

            RegisterAction(AC);

            AC.DoAction();

        }

        public static void DoActionTracertDevice(int HostID, NB_IPAddress Destination)
        {
            ActionClass AC = new ActionClass();
            AC.Action = NBAction.traceroute;
            AC.SourceID = HostID;
            AC.Destination = Destination;

            RegisterAction(AC);

            AC.DoAction();

        }
        public static void DoActionDHCP(int HostID)
        {
            ActionClass AC = new ActionClass();
            AC.Action = NBAction.dhcp;
            AC.SourceID = HostID;

            RegisterAction(AC);

            AC.DoAction();

        }
        public static void DoActionArpDevice(int HostID, NB_IPAddress Destination)
        {
            ActionClass AC = new ActionClass();
            AC.Action = NBAction.arp;
            AC.SourceID = HostID;
            AC.Destination = Destination;

            RegisterAction(AC);

            AC.DoAction();

        }
        public static void DoActionClearArpDevice(int HostID)
        {
            ActionClass AC = new ActionClass();
            AC.Action = NBAction.cleararp;
            AC.SourceID = HostID;

            RegisterAction(AC);

            AC.DoAction();
        }
        public static void DoActionReplaceDevice(int HostID)
        {
            ActionClass AC = new ActionClass();
            AC.Action = NBAction.replace;
            AC.SourceID = HostID;

            RegisterAction(AC);

            AC.DoAction();
        }
        public static void DoActionResetDevice(int HostID)
        {
            ActionClass AC = new ActionClass();
            AC.Action = NBAction.reset;
            AC.SourceID = HostID;

            RegisterAction(AC);

            AC.DoAction();
        }
        public static void DoActionReplaceDeviceUPS(int HostID)
        {
            ActionClass AC = new ActionClass();
            AC.Action = NBAction.replaceUPS;
            AC.SourceID = HostID;

            RegisterAction(AC);

            AC.DoAction();
        }
        public static void DoActionPowerOff(int HostID)
        {
            ActionClass AC = new ActionClass();
            AC.Action = NBAction.poweroff;
            AC.SourceID = HostID;

            RegisterAction(AC);

            AC.DoAction();
        }
        public static void DoActionPowerOn(int HostID)
        {
            ActionClass AC = new ActionClass();
            AC.Action = NBAction.poweron;
            AC.SourceID = HostID;

            RegisterAction(AC);

            AC.DoAction();
        }
        public static void DoActionDeleteComponent(int HostID)
        {
            ActionClass AC = new ActionClass();
            AC.Action = NBAction.deletecomponent;
            AC.SourceID = HostID;

            RegisterAction(AC);

            AC.DoAction();

        }
        public static void DoActionChangeComponent(int HostID, NetworkComponent Changed)
        {
            ActionClass AC = new ActionClass();
            AC.Action = NBAction.changecomponent;
            AC.SourceID = HostID;
            AC.ChangedComponent = NetworkComponent.Clone(Changed);

            RegisterAction(AC);

            AC.DoAction();

        }
        /// <summary>
        /// Make an adjustment to a preexisting component
        /// </summary>
        /// <param name="Changed"></param>
        public static void DoActionChangeComponent(NetworkComponent Changed)
        {
            DoActionChangeComponent(Changed.GetUniqueIdentifier, Changed);

        }
        #endregion ActionFunctions

    }
}
