using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Windows.Forms;
using System.Text.RegularExpressions;
using System.Xml;
using System.Drawing.Imaging;

namespace EduNetworkBuilder
{
    [Serializable]
    public class NetworkDevice : NetworkComponent
    {
        public List<NetworkCard> NICs = new List<NetworkCard>();
        public NB_IPAddress DefaultGW = new NB_IPAddress(NB.ZeroIPString, NB.ZeroIPString, IPAddressType.gw);
        protected Image MyImage = null;
        public Point MyLocation;
        public int Size;
        protected List<ArpEntry> ArpTable = new List<ArpEntry>();
        public NetworkComponentType myType = NetworkComponentType.none;
        public List<NB_IPAddress> RouteTable = new List<NB_IPAddress>();
        public List<NB_IPAddress> DHCPRanges = new List<NB_IPAddress>();
        protected List<ArpEntry> DHCPLeases = new List<ArpEntry>();
        protected List<IPConnectionEntry> IPConnections = new List<IPConnectionEntry>();
        public bool isDNSServer = false;
        public bool isDHCPServer = false;
        public bool CanServeDHCP = false;
        public bool CanUseDHCP = false;
        public bool MustUseDHCP = false;
        public bool CanAddNics = false;
        public bool HasAdvFirewall = false;
        public bool IsBurned = false;
        public Color BackgroundColor = Color.Empty;
        protected Color MorphColor = Color.Empty;
        public  List<FirewallRule> FirewallRules = new List<FirewallRule>();
        public bool PowerOff = false;
        private List<string> tracertmessages = new List<string>();
        public int BadSprayCount = 0;
        public List<int> PacketIDsPassedThrough = new List<int>();

        public NetworkDevice() { }
        public NetworkDevice(NetworkComponentType what, string tHostname, Point tLocation, NicType firstNic = NicType.eth)
        {
            hostname = tHostname;
            MyLocation = tLocation;
            myType = what;

            SetImageFromType(what);
            NetworkCard tnic = new NetworkCard(0,GetUniqueIdentifier,hostname,NicType.lo);
            NICs.Add(tnic);
            if (what == NetworkComponentType.net_switch || what == NetworkComponentType.net_hub)
            {
                if (firstNic != NicType.none)
                {
                    tnic = new NetworkCard(0, GetUniqueIdentifier, hostname, NicType.management_interface);
                    NICs.Add(tnic);
                }
                for(int looper=1; looper < 8; looper++)
                {
                    tnic = new NetworkCard(looper, GetUniqueIdentifier, hostname, NicType.port);
                    NICs.Add(tnic);
                }
            }
            else
            {
                if (firstNic != NicType.none)
                {
                    tnic = new NetworkCard(0, GetUniqueIdentifier, hostname);
                    NICs.Add(tnic);
                }
                if(what == NetworkComponentType.router)
                {
                    tnic = new NetworkCard(1, GetUniqueIdentifier, hostname);
                    NICs.Add(tnic);
                }
                //**********Wireless***********
                //Add a wireless network card to laptops, wireless bridge and wireless repeater
                if (what == NetworkComponentType.laptop )
                {
                    tnic = new NetworkCard(NICs.Count(), GetUniqueIdentifier, hostname,NicType.wlan); //Add a wireless nic
                    tnic.UsesDHCP = true;
                    NICs.Add(tnic);
                }
                if (what == NetworkComponentType.wbridge)
                {
                    NICs.Clear();
                    tnic = new NetworkCard(0, GetUniqueIdentifier, hostname, NicType.lo);
                    NICs.Add(tnic);
                    //tnic = new NetworkCard(0, GetUniqueIdentifier, hostname, NicType.management_interface);
                    //NICs.Add(tnic); --we use the wlan port for this
                    tnic = new NetworkCard(NICs.Count(), GetUniqueIdentifier, hostname, NicType.wlan); //Add a wireless nic
                    NICs.Add(tnic);
                    //A bridge is a switch with a wireless link, add 4 ports
                    for (int a = 0; a < 4; a++)
                    {
                        tnic = new NetworkCard(NICs.Count(), GetUniqueIdentifier, hostname, NicType.port); //Add a wireless nic
                        NICs.Add(tnic);
                    }
                }
                if (what == NetworkComponentType.wap)
                {
                    NICs.Clear();
                    tnic = new NetworkCard(0, GetUniqueIdentifier, hostname, NicType.lo);
                    NICs.Add(tnic);
                    tnic = new NetworkCard(0, GetUniqueIdentifier, hostname, NicType.management_interface);
                    NICs.Add(tnic);
                    //tnic = new NetworkCard(0, GetUniqueIdentifier, hostname, NicType.management_interface);
                    tnic = new NetworkCard(NICs.Count(), GetUniqueIdentifier, hostname, NicType.port); //Add a physical network card
                    NICs.Add(tnic);
                    //A bridge is a switch with an ethernet nic, add some wireless ports
                    for (int a = 0; a < 6; a++)
                    {
                        tnic = new NetworkCard(NICs.Count(), GetUniqueIdentifier, hostname, NicType.wport); //Add a wireless nic
                        NICs.Add(tnic);
                    }
                }
                if (what == NetworkComponentType.wrepeater)
                {
                    NICs.Clear();
                    tnic = new NetworkCard(0, GetUniqueIdentifier, hostname, NicType.lo);
                    NICs.Add(tnic);
                    //tnic = new NetworkCard(0, GetUniqueIdentifier, hostname, NicType.management_interface);
                    //NICs.Add(tnic);  --we use the wlan interface
                    tnic = new NetworkCard(NICs.Count(), GetUniqueIdentifier, hostname, NicType.wlan); //Add a wireless nic
                    NICs.Add(tnic);
                    tnic = new NetworkCard(NICs.Count(), GetUniqueIdentifier, hostname, NicType.wport); //Add a wireless port
                    NICs.Add(tnic);
                }
                if (what == NetworkComponentType.wrouter)
                {
                    NICs.Clear();
                    tnic = new NetworkCard(0, GetUniqueIdentifier, hostname, NicType.lo);
                    NICs.Add(tnic);
                    tnic = new NetworkCard(0, GetUniqueIdentifier, hostname, NicType.management_interface);
                    NICs.Add(tnic);
                    //A wireless router has multiple ports
                    for (int a = 0; a < 4; a++)
                    {
                        tnic = new NetworkCard(NICs.Count(), GetUniqueIdentifier, hostname, NicType.port); //Add a switched port
                        NICs.Add(tnic);
                    }
                    for (int a = 0; a < 8; a++)
                    {
                        tnic = new NetworkCard(NICs.Count(), GetUniqueIdentifier, hostname, NicType.wport); //Add a wireless port
                        NICs.Add(tnic);
                    }
                    //Add one vpn port
                    tnic = new NetworkCard(0, GetUniqueIdentifier, hostname, NicType.vpn);
                    NICs.Insert(1, tnic); //Make this first in the list - becomes second
                    //Add one wan port
                    tnic = new NetworkCard(0, GetUniqueIdentifier, hostname, NicType.wan);
                    NICs.Insert(1, tnic); //Make this first in the list
                }
                if (what == NetworkComponentType.firewall)
                {
                    //Have two lan ports
                    tnic = new NetworkCard(1, GetUniqueIdentifier, hostname, NicType.eth);
                    NICs.Add(tnic);
                    //Add one wan port
                    tnic = new NetworkCard(0, GetUniqueIdentifier, hostname, NicType.wan);
                    NICs.Insert(1,tnic); //Make this first in the list
                } 
                if (what == NetworkComponentType.cellphone || what == NetworkComponentType.tablet)
                {
                    NICs.Clear();
                    tnic = new NetworkCard(0, GetUniqueIdentifier, hostname, NicType.lo);
                    NICs.Add(tnic);
                    tnic = new NetworkCard(0, GetUniqueIdentifier, hostname, NicType.wlan);
                    tnic.UsesDHCP = true;
                    NICs.Add(tnic);
                }

            }
            ApplyRulesToDevice();
        }
        public int CountNics(NicType TheType)
        {
            int count = 0;
            foreach(NetworkCard nic in NICs)
            {
                if(nic.GetNicType == TheType)
                {
                    count++;
                }
            }
            return count;
        }
        public int FirstEmptySlot(NicType TheType)
        {
            int count = 0;
            while (true)
            {
                bool found = false;
                string tname = TheType.ToString() + count.ToString();
                foreach (NetworkCard nic in NICs)
                {
                    if(nic.NicName() == tname)
                    {
                        found = true;
                        break;
                    }
                }
                if (!found)
                    return count;
                count++;
            }
        }

        public NetworkCard AddNic(NicType TheType = NicType.eth)
        {
            NetworkCard tnic;
            int count = FirstEmptySlot(TheType);
            tnic = new NetworkCard(count, GetUniqueIdentifier, hostname, TheType);
            NICs.Add(tnic);
            ApplyRulesToDevice();
            return tnic;
        }
        private void ApplyRulesToDevice()
        {
            if (myType == NetworkComponentType.server || myType == NetworkComponentType.firewall)
            {
                CanServeDHCP = true;
                CanUseDHCP = false;
                MustUseDHCP = false;
                CanAddNics = true;
                setNicsCanUseDHCP(false);
            }
            if (myType == NetworkComponentType.router)
            {
                CanServeDHCP = false;
                CanUseDHCP = false;
                MustUseDHCP = false;
                CanAddNics = true;
                setNicsCanUseDHCP(false);
            }
            if (myType == NetworkComponentType.pc || myType == NetworkComponentType.laptop || 
                myType == NetworkComponentType.copier || myType == NetworkComponentType.printer ||
                myType == NetworkComponentType.tablet || myType == NetworkComponentType.cellphone)
            {
                CanServeDHCP = false;
                CanUseDHCP = true;
                MustUseDHCP = false;
                CanAddNics = true;
                setNicsCanUseDHCP(true);
            }
            if (myType == NetworkComponentType.net_switch || myType == NetworkComponentType.net_hub ||
                myType == NetworkComponentType.wap || myType == NetworkComponentType.wbridge ||
                myType == NetworkComponentType.wrepeater)
            {
                CanServeDHCP = false;
                CanUseDHCP = true;
                MustUseDHCP = false;
                CanAddNics = false;
                setNicsCanUseDHCP(true);
            }
            if (myType == NetworkComponentType.ip_phone)
            {
                CanServeDHCP = false;
                CanUseDHCP = true;
                MustUseDHCP = true;
                CanAddNics = false;
                setNicsCanUseDHCP(true);
            }
            if (myType == NetworkComponentType.wrouter)
            {
                CanServeDHCP = true;
                CanUseDHCP = true;
                MustUseDHCP = false;
                CanAddNics = false;
                setNicsCanUseDHCP(true);
            }
        }

        private void setNicsCanUseDHCP(bool CanUse)
        {
            foreach(NetworkCard nic in NICs)
            {
                //if the device must use DHCP. we set it here.
                if (MustUseDHCP && nic.CanUseDHCP)
                {
                    nic.UsesDHCP = true;
                    nic.MustUseDHCP = true;
                }
                else
                {
                    //we can only turn it off.
                    nic.CanUseDHCP = CanUse && nic.CanUseDHCP;
                    nic.MustUseDHCP = false;
                }
            }
        }

        public NetworkDevice(XmlNode theNode)
        {
            IsDirty = true;
            Load(theNode);
            SetImageFromType(myType);
        }

        public override bool Equals(NetworkComponent toCompare)
        {
            if (!(toCompare is NetworkDevice)) return false; //comparing a link to a device
            NetworkDevice CompareDevice = (NetworkDevice)toCompare;
            if (IsDirty != CompareDevice.IsDirty) return false;
            if (UniqueIdentifier != CompareDevice.UniqueIdentifier) return false;
            if (hostname != CompareDevice.hostname) return false;
            if (isInvisible != CompareDevice.isInvisible) return false;
            if (NICs.Count != CompareDevice.NICs.Count) return false;
            for (int i = 0; i < NICs.Count; i++)
                if (!NICs[i].Equals(CompareDevice.NICs[i])) return false;
            if (!DefaultGW.Equals(CompareDevice.DefaultGW)) return false;
            if (MyLocation != CompareDevice.MyLocation) return false;
            if (Size != CompareDevice.Size) return false;

            if (ArpTable.Count != CompareDevice.ArpTable.Count) return false;
            for (int i = 0; i < ArpTable.Count; i++)
                if (!ArpTable[i].Equals(CompareDevice.ArpTable[i])) return false;

            if (myType != CompareDevice.myType) return false;
            if (RouteTable.Count != CompareDevice.RouteTable.Count) return false;
            for (int i = 0; i < RouteTable.Count; i++)
                if (!RouteTable[i].Equals(CompareDevice.RouteTable[i])) return false;
            if (DHCPLeases.Count != CompareDevice.DHCPLeases.Count) return false;
            for (int i = 0; i < DHCPLeases.Count; i++)
                if (!DHCPLeases[i].Equals(CompareDevice.DHCPLeases[i])) return false;
            if (IPConnections.Count != CompareDevice.IPConnections.Count) return false;
            for (int i = 0; i < IPConnections.Count; i++)
                if (!IPConnections[i].Equals(CompareDevice.IPConnections[i])) return false;

            if (isDNSServer != CompareDevice.isDNSServer) return false;
            if (isDHCPServer != CompareDevice.isDHCPServer) return false;

            if (CanServeDHCP != CompareDevice.CanServeDHCP) return false;
            if (CanUseDHCP != CompareDevice.CanUseDHCP) return false;
            if (MustUseDHCP != CompareDevice.MustUseDHCP) return false;
            if (CanAddNics != CompareDevice.CanAddNics) return false;
            if (HasAdvFirewall != CompareDevice.HasAdvFirewall) return false;
            if (IsBurned != CompareDevice.IsBurned) return false;
            if (BackgroundColor != CompareDevice.BackgroundColor) return false;
            if (MorphColor != CompareDevice.MorphColor) return false;
            if (PowerOff != CompareDevice.PowerOff) return false;
            if (FirewallRules.Count != CompareDevice.FirewallRules.Count) return false;
            for (int i = 0; i < FirewallRules.Count; i++)
                if (!FirewallRules[i].Equals(CompareDevice.FirewallRules[i])) return false;
            if (!tracertmessages.SequenceEqual(CompareDevice.tracertmessages)) return false;
            return true;
        }

        public override void Destroy()
        {
            Network myNet = NB.GetNetwork();
            NetworkLink nl;
            if (myNet != null)
            {
               foreach(NetworkCard nic in NICs)
               {
                   if(nic.ConnectedLink != -1)
                   {
                        nl = myNet.GetLinkFromID(nic.ConnectedLink);
                        if(nl != null)
                        {
                            myNet.RemoveComponent(nl);
                            nl.Destroy();
                        }
                        nic.ConnectedLink = -1;
                   }
               }
            }
        }

        public void EditGateway(Form ParentForm)
        {
            DefaultGW.Edit(this,ParentForm,NB.Translate("ND_EdtGteway"));
        }

        public NB_IPAddress GetGateway()
        {
            if(!HasNonDHCPConnected() && CanUseDHCP)
            {               
                foreach(NetworkCard nic in NICs)
                {
                    if(nic.UsesDHCP)
                    {
                        List<NB_IPAddress> tlist = nic.IPAddressList();
                        if(tlist.Count > 0)
                        {
                            NB_IPAddress newIP = new NB_IPAddress(tlist[0].GetGateway.ToIpString());
                            return newIP;
                        }
                    }
                }
            }
            return DefaultGW;
        }

        public NetworkComponentType GetNetType()
        {
            return myType;
        }

        public bool isFrozen()
        {
            Network mynet = NB.GetNetwork();
            if (mynet.ItemHasTest(hostname, NetTestType.DeviceIsFrozen))
            {
                if (!mynet.ItemTestIsComplete(hostname, NetTestType.DeviceIsFrozen))
                {
                    return true;
                }
            }
            return false;
        }

        public override void Load(XmlNode theNode)
        {
            NetworkCard newNic;
            foreach (XmlNode Individual in theNode.ChildNodes)
            {
                XmlNodeType myNodetype = Individual.NodeType;
                if (myNodetype == XmlNodeType.Element)
                {
                    switch(Individual.Name.ToLower())
                    {
                        case "location":
                            string[] pointstr = Individual.InnerText.Split(',');
                            int x, y;
                            int.TryParse(pointstr[0], out x);
                            int.TryParse(pointstr[1], out y);
                            MyLocation = new Point(x, y);
                            break;
                        case "size":
                            int.TryParse(Individual.InnerText, out Size);
                            break;
                        case "uniqueidentifier":
                            int.TryParse(Individual.InnerText, out UniqueIdentifier);
                            break;
                        case "gateway":
                            DefaultGW = new NB_IPAddress(Individual);
                            break;
                        case "hostname":
                            hostname = Individual.InnerText;
                            break;
                        case "mytype":
                            myType = NB.ParseEnum<NetworkComponentType>(Individual.InnerText);
                            break;
                        case "nic":
                            newNic = new NetworkCard(Individual);
                            //if (myType == NetworkComponentType.wap && newNic.GetNicType == NicType.eth)
                            //{
                                //    //This happened once upon a time.  Waps did not have management interfaces.
                                //    //Make a management interface for the wap and move the IP from the eth to that.
                                //    //Then, change the nic to a port instead of an eth.
                                //    NetworkCard tNic = new NetworkCard(newNic);
                                //    tNic.ChangeType(NicType.management_interface);
                                //    NICs.Add(tNic);
                                // newNic.ChangeType(NicType.port);
                            //}
                            NICs.Add(newNic);
                            break;
                        case "route":
                            NB_IPAddress ip = new NB_IPAddress(Individual);
                            RouteTable.Add(ip);
                            break;
                        case "isdns":
                            bool.TryParse(Individual.InnerText, out isDNSServer);
                            break;
                        case "isburned":
                            bool.TryParse(Individual.InnerText, out IsBurned);
                            break;
                        case "isdhcp":
                            bool.TryParse(Individual.InnerText, out isDHCPServer);
                            break;
                        case "dhcprange":
                             NB_IPAddress dhcpip = new NB_IPAddress(Individual);
                            DHCPRanges.Add(dhcpip);
                            break;
                        case "hasadvfirewall":
                            bool.TryParse(Individual.InnerText, out HasAdvFirewall);
                            break;
                        case "firwallrule":
                            FirewallRule fwr = new FirewallRule(Individual);
                            FirewallRules.Add(fwr);
                            break;
                        case "morphcolor":
                            MorphColor = Color.FromName(Individual.InnerText);
                            break;
                        case "poweroff":
                            bool.TryParse(Individual.InnerText, out PowerOff);
                            break;
                        case "invisible":
                        case "isinvisible":
                            bool.TryParse(Individual.InnerText, out isInvisible);
                            break;
                    }
                }
            }
            ApplyRulesToDevice();
        }

        public override void Save(XmlWriter writer)
        {
            writer.WriteStartElement("device");
            writer.WriteElementString("hostname", hostname);
            writer.WriteElementString("size", Size.ToString());
            writer.WriteElementString("uniqueidentifier", UniqueIdentifier.ToString());
            writer.WriteElementString("location", MyLocation.X.ToString() + "," + MyLocation.Y.ToString());
            writer.WriteElementString("mytype", myType.ToString());
            writer.WriteElementString("isdns", isDNSServer.ToString());
            writer.WriteElementString("isdhcp", isDHCPServer.ToString());
            if(IsBurned)
                writer.WriteElementString("isburned", IsBurned.ToString());
            if (HasAdvFirewall)
                writer.WriteElementString("hasadvfirewall", HasAdvFirewall.ToString());
            if (MorphColor != Color.Empty)   
                writer.WriteElementString("morphcolor", MorphColor.Name);
            if(PowerOff == true)
                writer.WriteElementString("poweroff", PowerOff.ToString());
            if (isInvisible == true)
                writer.WriteElementString("isinvisible", isInvisible.ToString());
            DefaultGW.Save(writer, "gateway");
            foreach (NetworkCard nic in NICs)
            {
                nic.Save(writer);
            }
            foreach (NB_IPAddress ip in RouteTable)
            {
                ip.Save(writer, "route");
            }
            foreach (NB_IPAddress dhcp in DHCPRanges)
            {
                dhcp.Save(writer, "dhcprange");
            }
            if (HasAdvFirewall)
            {
                foreach (FirewallRule fwr in FirewallRules)
                {
                    fwr.Save(writer, "firwallrule");
                }
            }
            writer.WriteEndElement();
        }

        public bool IsLockedInLocation()
        {
            if (myType == NetworkComponentType.tree) return true; //Trees are always stationary
            Network myNet = NB.GetNetwork();
            if (myNet.ItemHasTest(hostname, NetTestType.LockLocation)) return true;
            return false;
        }

        public void SetDNSServer(bool isDNS)
        {
            isDNSServer = isDNS;
        }
        public bool GetIsDNSServer()
        {
            return isDNSServer;
        }

        public void SetAdvFirewall(bool AdvFirewall)
        {
            HasAdvFirewall = AdvFirewall;
        }

        public void SetDHCPServer(bool isDHCP)
        {
            isDHCPServer = isDHCP;
        }
        public bool GetIsDHCPServer()
        {
            return isDHCPServer;
        }

        public string TooltipString()
        {
            string answer = hostname;
            //Add IP Addresses that are assigned
            if (myType == NetworkComponentType.fluorescent)
                return NB.Translate("ND_FluorescentTooltip");
            if (myType == NetworkComponentType.microwave)
                return NB.Translate("ND_MicrowaveTooltip");
            foreach (NetworkCard nic in NICs)
            {
                if (nic.GetNicType == NicType.wport || nic.GetNicType == NicType.port) 
                    continue;
                foreach(string addr in nic.IPAddresses())
                {
                    answer += System.Environment.NewLine + addr;   
                }
            }
            if(BackgroundColor != Color.Empty)
            {
                //There is something wrong with it?
                Network myNet = NB.GetNetwork();
                List<string> DeviceMessages = myNet.GetTestMessages(hostname);
                foreach (string tString in DeviceMessages)
                {
                    answer += System.Environment.NewLine + tString;   
                }
            }
            return answer;
        }

        public List<string> ListOfConnectedHosts()
        {
            List<string> thelist = new List<string>();
            foreach(NetworkCard nic in NICs)
            {
                if(nic.ConnectedLink != -1)
                {
                    Network myNet = NB.GetNetwork();
                    NetworkLink Link = myNet.GetLinkFromID(nic.ConnectedLink);
                    if(Link != null)
                    {
                        NetworkDevice tmp = myNet.GetDeviceFromID(Link.Src);
                        if (tmp == null) continue;
                        if (tmp.hostname != hostname) thelist.Add(tmp.hostname);
                         tmp = myNet.GetDeviceFromID(Link.Dst);
                        if (tmp.hostname != hostname) thelist.Add(tmp.hostname);
                    }
                }
            }
            return thelist;
        }

        public void RemoveLinkTo(string host)
        {
            Network myNet = NB.GetNetwork();
            NetworkLink Link;
            NetworkDevice item;
            foreach (NetworkCard nic in NICs)
            {
                if (nic.ConnectedLink != -1)
                {
                    Link = myNet.GetLinkFromID(nic.ConnectedLink);
                    if (Link != null)
                    {
                        item = myNet.GetDeviceFromID(Link.Dst);
                        if (item.hostname == host)
                        {
                            myNet.RemoveComponent(Link);
                            return;
                        }
                        item = myNet.GetDeviceFromID(Link.Src);
                        if (item.hostname == host)
                        {
                            myNet.RemoveComponent(Link);
                            return;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Check to see if the device has a link to the specified host
        /// </summary>
        /// <param name="host"></param>
        public bool HasLinkTo(string host)
        {
            Network myNet = NB.GetNetwork();
            NetworkLink Link;
            NetworkDevice item;
            foreach (NetworkCard nic in NICs)
            {
                if (nic.ConnectedLink != -1)
                {
                    Link = myNet.GetLinkFromID(nic.ConnectedLink);
                    if (Link != null)
                    {
                        if (Link.theLinkType == LinkType.broken) return false; //A broken link does not work
                        item = myNet.GetDeviceFromID(Link.Dst);
                        if (item.hostname == host)
                        {
                            return true;
                        }
                        item = myNet.GetDeviceFromID(Link.Src);
                        if (item.hostname == host)
                        {
                            return true;
                        }
                    }
                }
            }
            return false;
        }
        public void SetImageFromType()
        {
            SetImageFromType(myType);
        }
        private void SetImageFromType(NetworkComponentType what)
        {
            switch (what)
            {
                case NetworkComponentType.laptop:
                    MyImage = Properties.Resources.Laptop;
                    break;
                case NetworkComponentType.pc:
                    MyImage = Properties.Resources.PC;
                    break;
                case NetworkComponentType.server:
                    MyImage = Properties.Resources.Server;
                    break;
                case NetworkComponentType.net_hub:
                    MyImage = Properties.Resources.Hub;
                    break;
                case NetworkComponentType.net_switch:
                    MyImage = Properties.Resources.Switch;
                    break;
                case NetworkComponentType.wap:
                    MyImage = Properties.Resources.wap;
                    break;
                case NetworkComponentType.wrepeater:
                    MyImage = Properties.Resources.WRepeater;
                    break;
                case NetworkComponentType.wbridge:
                    MyImage = Properties.Resources.WBridge;
                    break;
                case NetworkComponentType.wrouter:
                    MyImage = Properties.Resources.WRouter;
                    break;
                case NetworkComponentType.router:
                    MyImage = Properties.Resources.Router;
                    break;
                case NetworkComponentType.ip_phone:
                    MyImage = Properties.Resources.ip_phone;
                    break;
                case NetworkComponentType.firewall:
                    MyImage = Properties.Resources.firewall;
                    break;
                case NetworkComponentType.printer:
                    MyImage = Properties.Resources.Printer;
                    break;
                case NetworkComponentType.copier:
                    MyImage = Properties.Resources.Copier;
                    break;
                case NetworkComponentType.fluorescent:
                    MyImage = Properties.Resources.fluorescent;
                    break;
                case NetworkComponentType.microwave:
                    MyImage = Properties.Resources.microwave;
                    break;
                case NetworkComponentType.cellphone:
                    MyImage = Properties.Resources.cellphone;
                    break;
                case NetworkComponentType.tablet:
                    MyImage = Properties.Resources.tablet;
                    break;
                case NetworkComponentType.tree:
                    MyImage = Properties.Resources.tree;
                    break;
            }
        }

        /// <summary>
        /// Return a copy of the image for this device
        /// </summary>
        /// <returns></returns>
        public Image GetImage()
        {
            return new Bitmap(MyImage);
        }

        //This function heavily borrowed from: http://stackoverflow.com/questions/1563038/fast-work-with-bitmaps-in-c-sharp
        public Image ColoredImage(Image BaseImage)
        {
            Bitmap b = new Bitmap(BaseImage);

            BitmapData bData = b.LockBits(new Rectangle(0, 0, BaseImage.Width, BaseImage.Height), ImageLockMode.ReadWrite, b.PixelFormat);

            /* GetBitsPerPixel just does a switch on the PixelFormat and returns the number */
            int bitsPerPixel = Image.GetPixelFormatSize(bData.PixelFormat);

            /*the size of the image in bytes */
            int size = bData.Stride * bData.Height;

            /*Allocate buffer for image*/
            byte[] data = new byte[size];

            /*This overload copies data of /size/ into /data/ from location specified (/Scan0/)*/
            System.Runtime.InteropServices.Marshal.Copy(bData.Scan0, data, 0, size);

            List<NetworkComponentType> HasScreens = new List<NetworkComponentType>() {
                NetworkComponentType.cellphone,NetworkComponentType.ip_phone, NetworkComponentType.laptop,
                NetworkComponentType.microwave, NetworkComponentType.pc, NetworkComponentType.tablet,
            };

            for (int i = 0; i < size; i += bitsPerPixel / 8)
            {
                //double magnitude = 1 / 3d * (data[i] + data[i + 1] + data[i + 2]);

                if (PowerOff)
                {
                    byte bcol = data[i];     //This is the blue color
                    byte gcol = data[i + 1]; //this is the green color
                    byte rcol = data[i + 2]; //This is the red color
                    byte acol = data[i + 3]; //this is the transparency

                    //Check to see if it is green.  If so, we make it mostly not-green.
                    if (rcol == 70 && gcol == 217 && bcol == 31)
                        data[i + 1] = 0; //set green to none
                    if(HasScreens.Contains(myType))
                    {
                        //5c7df9 - blue color
                        //46d91f - green color
                        if (rcol == 92 && gcol == 125 && bcol == 249)
                        {
                            data[i] = 0; //set blue to none on items that have screens
                            data[i+1] = 0; //set green to none on items that have screens
                            data[i+2] = 0; //set red to none on items that have screens
                        }
                    }
                }
                //data[i] is the first of 3 bytes of color
                if (MorphColor != Color.Empty)
                {
                    if (data[i + 3] != 0) //We only change the color if it is not transparent.
                    {
                        data[i] = (byte)((data[i] + MorphColor.B) / 2);
                        data[i + 1] = (byte)((data[i + 1] + MorphColor.G) / 2);
                        data[i + 2] = (byte)((data[i + 2] + MorphColor.R) / 2);
                    }
                }
            }

            /* This override copies the data back into the location specified */
            System.Runtime.InteropServices.Marshal.Copy(data, 0, bData.Scan0, data.Length);

            b.UnlockBits(bData);

            return b;
        }

        /// <summary>
        /// We concoct a burn image overlay the same shape of the object we are drawing.  Loop through the image
        /// and turn the burn-image transparent everywhere the original image is transparent.  Then, draw the
        /// shaped burn-image on top of the original image.
        /// </summary>
        /// <param name="BaseImage"></param>
        /// <returns>A burnt-looking network device.</returns>
        public Image BurnedImage(Image BaseImage)
        {
            Bitmap b = new Bitmap(BaseImage);
            //Make a burn image that is the same size as the base image
            Bitmap Burn = new Bitmap(b.Width, b.Height);
            Graphics.FromImage(Burn).DrawImage(Properties.Resources.BurnMark, new Rectangle(0, 0, b.Width, b.Height));

            BitmapData bData = b.LockBits(new Rectangle(0, 0, BaseImage.Width, BaseImage.Height), ImageLockMode.ReadWrite, b.PixelFormat);
            BitmapData burnData = Burn.LockBits(new Rectangle(0, 0, BaseImage.Width, BaseImage.Height), ImageLockMode.ReadWrite, b.PixelFormat);

            /* GetBitsPerPixel just does a switch on the PixelFormat and returns the number */
            int bitsPerPixel = Image.GetPixelFormatSize(bData.PixelFormat);

            /*the size of the image in bytes */
            int size = bData.Stride * bData.Height;

            /*Allocate buffer for image*/
            byte[] OrigImagedata = new byte[size];
            byte[] BurnImagedata = new byte[size];

            /*This overload copies data of /size/ into /data/ from location specified (/Scan0/)*/
            System.Runtime.InteropServices.Marshal.Copy(bData.Scan0, OrigImagedata, 0, size);
            System.Runtime.InteropServices.Marshal.Copy(burnData.Scan0, BurnImagedata, 0, size);

            for (int i = 0; i < size; i += bitsPerPixel / 8)
            {
                //double magnitude = 1 / 3d * (data[i] + data[i + 1] + data[i + 2]);
                if (OrigImagedata[i + 3] == 0) //If the original image is transparent, make the burn image transparent
                {
                    BurnImagedata[i + 3] = 0;//Make it transparent
                    //Console.Write(" " + i);
                }
                else
                {
                    //Console.Write("no");
                }
            }
            Console.WriteLine("");
            /* This override copies the data back into the location specified */
            System.Runtime.InteropServices.Marshal.Copy(OrigImagedata, 0, bData.Scan0, OrigImagedata.Length);
            System.Runtime.InteropServices.Marshal.Copy(BurnImagedata, 0, burnData.Scan0, OrigImagedata.Length);

            b.UnlockBits(bData);
            Burn.UnlockBits(burnData);

            Graphics.FromImage(b).DrawImage(Burn, new Point(0,0));

            return b;
        }


        public bool AtLocation(Point location)
        {
            if (location.X >= MyLocation.X && location.X <= MyLocation.X + Size &&
            location.Y >= MyLocation.Y && location.Y <= MyLocation.Y + Size)
                return true;
            return false;
        }
        public Point myLocation()
        {
            return MyLocation;
        }
        /// <summary>
        /// returns the centerpoint of the device
        /// </summary>
        /// <returns>a point that is the center of the device</returns>
        public Point GetCenter()
        {
            int delta = Size / 2;
            return new Point(MyLocation.X + delta, MyLocation.Y + delta);
        }

        public Rectangle GetMyRectangle()
        {
            return new Rectangle(MyLocation.X, MyLocation.Y, Size, Size);

        }

        private Point AdjustedForRectangle(Point Location, Rectangle rec)
        {
            int x = Location.X;
            int y = Location.Y;
            if (x < rec.X) x = rec.X;
            if (x > rec.X + rec.Width - Size) x = rec.X + rec.Width - Size;
            if (y < rec.Y) y = rec.Y;
            if (y > rec.Y + rec.Height - Size) y = rec.Y + rec.Height - Size;
            return new Point(x, y);
        }

        private void TryPutLocation(Point Location)
        {
            Network myNet = NB.GetNetwork();
            if (myNet == null) {
                MyLocation = Location; // We cannot do checking.  Hope for the best.
                return;
            }
            Point AdjustPoint = AdjustedForRectangle(Location, new Rectangle(0, 0, myNet.myWidth, myNet.myHeight));
            foreach(string Name in myNet.DeviceLockedToShapes(hostname))
            {
                AdjustPoint = AdjustedForRectangle(AdjustPoint, myNet.RectangleByNamedShape(Name));
            }
            MyLocation = AdjustPoint;
            IsDirty = true;

        }
        public void ChangeLocation(Point Location)
        {
            TryPutLocation(NB.GetSnapped(Location));
        }
        public void ChangeLocationUnsnapped(Point Location)
        {
            TryPutLocation(Location);
        }

        public void SetSize(int tSize)
        {
            if (Size != tSize)
                IsDirty = true;
            Size = tSize;
        }
        public void AddNicInterface(int NicIndex)
        {
            if (NicIndex >= 0 && NicIndex < NICs.Count())
            {
                NICs[NicIndex].AddInterface();
            }
        }

        public void EditNicInterface(int NicIndex, int ifIndex, Form ParentForm)
        {
            if(NicIndex >=0 && NicIndex < NICs.Count())
            {
                NICs[NicIndex].EditInterface(ifIndex, ParentForm);
            }
        }
        public void DeleteNicInterface(int NicIndex, int ifIndex)
        {
            if (NicIndex >= 0 && NicIndex < NICs.Count())
            {
                NICs[NicIndex].DeleteInterface(ifIndex);
            }
        }
        public void EditNicInterface(string  NicName, int ifIndex, Form ParentForm)
        {
            NetworkCard nic = NicFromName(NicName);
            if (nic != null)
            {
                nic.EditInterface(ifIndex, ParentForm);
            }
        }

        /// <summary>
        /// Duplicate the ssid and key to all NICs of identical type on this device
        /// </summary>
        /// <param name="SSID">The ssid to set everything to</param>
        /// <param name="Key">the Key to set everything to</param>
        /// <param name="NType">the type of nic (must be a wireless type)</param>
        private void duplicateSSIDnKey(string SSID, string Key, NicType NType)
        {
            if (NType != NicType.wport && NType != NicType.wlan) return; // Not a wireless port.  Do nothing.
            foreach(NetworkCard NC in NICs)
            {
                if(NC.GetNicType == NType)
                {
                    NC.SSID = SSID;
                    NC.WirelessKey = Key;
                }
            }
        }
        public void EditNic(int index)
        {
            if (index < 0) return;
            if (index > NICs.Count) return;
            NICs[index].Edit();
            //If the nic was a wireless, make sure we copy the ssid and key to all other of identical type
            if (NICs[index].GetNicType == NicType.wport || NICs[index].GetNicType == NicType.wlan)
            {
                duplicateSSIDnKey(NICs[index].SSID, NICs[index].WirelessKey, NICs[index].GetNicType);
            }
        }
        public void DeleteNic(int index)
        {
            if (index < 0) return;
            if (index > NICs.Count) return;
            if (NICs[index].GetNicType == NicType.lo) return;
            if (NICs[index].GetNicType == NicType.management_interface) return;
            if (NICs[index].GetNicType == NicType.none) return;
            Network theNet = NB.GetNetwork();
            if(!theNet.ItemIsLocked(hostname,NICs[index].NicName(),NetTestType.LockNic))
            {
                if (theNet != null) theNet.RemoveLinksToNic(NICs[index].myID);                
                NICs.RemoveAt(index);
            }
            else
            {
                MessageBox.Show(string.Format(NB.Translate("ND_DelNicNicLockStr"), NICs[index].NicName()), NB.Translate("ND_DelNicNicLock"));
            }
        }
        public bool AutoJoinWireless()
        {
            bool didsomething = false;
            bool tryit = false;
            Network myNet = NB.GetNetwork();
            if (PowerOff) return false; //We do not do anything if we are powered off

            foreach(NetworkCard nic in NICs)
            {
                tryit = false;
                if (nic.GetNicType != NicType.wlan) continue;
                if (nic.SSID == "") continue;
                if (!nic.isConnected(false)) 
                    tryit = true;
                if(!tryit)
                {
                    //Check distance and power for AP
                    NetworkComponent nc = myNet.GetComponentFromID(nic.ConnectedLink);
                    if(nc != null)
                    {
                        NetworkLink nl = (NetworkLink)nc;
                        double distance = nl.LinkDistance();
                        if (distance > NB.WirelessReconnectDistance)
                            tryit = true;
                        //Make sure the far end is powered on
                        HostNicID EndPoint = nl.Dst;
                        if (nic.myID.HostID == EndPoint.HostID) EndPoint = nl.Src;
                        NetworkDevice End = myNet.GetDeviceFromID(EndPoint);
                        if (End != null && End.PowerOff)
                            tryit = true;

                    }
                }
                //Tryit tells us if we should try to reconnect.
                if (tryit)
                {
                    if(nic.isConnected(false))
                    {
                        //remove old connection
                        NetworkLink oNL = myNet.GetLinkFromID(nic.ConnectedLink);
                        if(oNL != null)
                        {
                            myNet.RemoveComponent(oNL);
                            oNL.Destroy();
                        }
                    }
                    //We want to find the closest device with an open wport that matches ssid/key and connect to it.
                    NetworkCard Closest = myNet.BestWirelessLinkForDevice(nic);
                    if(Closest != null)
                    {
                        NetworkLink newLink = new NetworkLink(nic.myID, Closest.myID, LinkType.wireless);
                        nic.ConnectedLink = newLink.GetUniqueIdentifier;
                        Closest.ConnectedLink = newLink.GetUniqueIdentifier;
                        myNet.AddItem(newLink);
                        didsomething = true;
                    }
                }
            }
            return didsomething;
        }

        public NetworkCard HasWPortSSIDKey(string SSID, string Key)
        {
            if (SSID == null) return null;
            if (Key == null) return null;
            foreach(NetworkCard nic in NICs)
            {
                if(nic.GetNicType == NicType.wport && !nic.isConnected(false))
                {
                    if (nic.SSID == SSID && nic.EncryptionKey == Key)
                        return nic;
                }
            }
            return null;
        }

        public List<string> NetworkCardStrings(bool OnlyUnused=true, bool OnlyLinkable=false, NicType fromNic = NicType.none)
        {
            List<string> macStrings = new List<string>();
            int counter = 0;
            bool CanUse = true;
            if (myType == NetworkComponentType.microwave || myType == NetworkComponentType.fluorescent)
                return macStrings;
            foreach (NetworkCard nic in NICs)
            {
                if (OnlyUnused)
                    CanUse = nic.ConnectedLink == -1; //if it is not linked to anything
                if (OnlyLinkable && nic.GetNicType == NicType.vpn) CanUse = false;
                if (OnlyLinkable && nic.GetNicType == NicType.tun) CanUse = false;
                if (fromNic != NicType.none  &&
                    fromNic == NicType.wlan && nic.GetNicType != NicType.wport) CanUse = false;
                if (fromNic != NicType.none && 
                    fromNic == NicType.wport && nic.GetNicType != NicType.wlan) CanUse = false;
                if (nic.GetNicType != NicType.lo && (nic.GetNicType != NicType.management_interface || OnlyUnused == false))
                {
                    if(CanUse)
                        macStrings.Add(nic.NicString(counter++));
                }
            }
            return macStrings;
        }

        public List<string> NetworkCardInterfaceStrings(int index)
        {
            List<string> myList = new List<string>();
            if (myType == NetworkComponentType.microwave || myType == NetworkComponentType.fluorescent)
                return myList;
            if (index >= 0 && index < NICs.Count)
            {
                myList.AddRange(NICs[index].IPAddresses());
            }
            return myList;
        }
        public List<string> NetworkCardInterfaceStrings(string NicName)
        {
            List<string> myList = new List<string>();
            NetworkCard nic = NicFromName(NicName);
            if(nic != null)
            {
                myList.AddRange(nic.IPAddresses());
            }
            return myList;
        }


        public NetworkCard NicFromID(int ID)
        {
            foreach (NetworkCard nic in NICs)
            {
                if (nic.GetUniqueIdentifier == ID)
                    return nic;
            }
            return null;
        }
        public NetworkCard NicFromID(HostNicID ID)
        {
            return NicFromID(ID.NicID);
        }

        public NetworkCard NicFromName(string name)
        {
            string tstr = name;
            tstr = Regex.Replace(name, " .*", "");
            foreach (NetworkCard nic in NICs)
            {
                if (nic.NicName() == tstr)
                    return nic;
            }
            return null;
        }
        /// <summary>
        /// returns true if it has a connection to something.
        /// </summary>
        /// <returns></returns>
        public bool isConnected()
        {
            return false;
        }

        private void ValidateSize()
        {
            if (Size > 200) Size = 200;
            if (Size < 10) Size = 10;

            DateTime Test = DateTime.UtcNow + TimeSpan.FromMilliseconds(100);
        }


        public void CenterString(Image BaseImage, int x, int y, string ToPrint, Color ToDraw)
        {
            string measureString = ToPrint;
            Font stringFont = new Font("Consolas", 17);
            Color othercolor = Color.White;
            if (ToDraw == Color.White)
                othercolor = Color.Black;

            // Measure string.
            SizeF stringSize = new SizeF();
            Graphics myGraphics = Graphics.FromImage(BaseImage);
            stringSize = myGraphics.MeasureString(measureString, stringFont);
            Brush myBrush = new SolidBrush(ToDraw);
            Brush otherBrush = new SolidBrush(othercolor);
            // Draw string to screen.
            myGraphics.DrawString(measureString, stringFont, otherBrush, new PointF(x - (stringSize.Width / 2) +1, y +1));
            myGraphics.DrawString(measureString, stringFont, myBrush, new PointF(x - (stringSize.Width / 2), y));
        }

        public override void Print(Image BaseImage, CaptionType DrawTitle)
        {
            ValidateSize();
            if (MyImage == null) return; //nothing to print
            if (BaseImage == null) return; //nothing to print on
            if (MyLocation.X < 0 || MyLocation.X > BaseImage.Width) return;
            if (MyLocation.Y < 0 || MyLocation.Y > BaseImage.Height) return;

            Rectangle Location = new Rectangle(MyLocation.X, MyLocation.Y, Size, Size);

            if (!isInvisible)
            {
                if (IsLockedInLocation()) //We darken the area around it slightly to show it is locked
                {
                    Color darken = Color.Black;
                    Brush brush = new SolidBrush(Color.FromArgb(32, darken.R, darken.G, darken.B));
                    Pen DrawPen = new Pen(brush, 2);
                    Graphics.FromImage(BaseImage).DrawEllipse(DrawPen, Location);
                    Network myNet = NB.GetNetwork();
                    myNet.Invalidate(Location);
                }
                if (BackgroundColor != Color.Empty)
                {
                    Brush brush = new SolidBrush(Color.FromArgb(128, BackgroundColor.R, BackgroundColor.G, BackgroundColor.B));
                    Graphics.FromImage(BaseImage).FillRectangle(brush, Location);
                    Network myNet = NB.GetNetwork();
                    myNet.Invalidate(Location);
                }
                Image tImage = MyImage;
                if (MorphColor != Color.Empty || PowerOff == true)
                    tImage = ColoredImage(MyImage);
                if (IsBurned)
                    tImage = BurnedImage(tImage);
                Graphics.FromImage(BaseImage).DrawImage(tImage, MyLocation.X, MyLocation.Y, Size, Size);

                if (DrawTitle != CaptionType.none)
                {
                    int x = MyLocation.X + (Size / 2);
                    int y = MyLocation.Y + Size - (Size / 6);
                    int gap = 22;


                    List<string> toShow = DeviceCaptions(DrawTitle);
                    for(int counter=0; counter < toShow.Count; counter++)
                    {
                        CenterString(BaseImage, x, y + (counter * gap), toShow[counter], Color.Black);
                    }
                }
            } //if it is not invisible
            IsDirty = false;  //We printed it, now we are content that we are clean
        }

        private List<string> DeviceCaptions(CaptionType What)
        {
            List<string> WhatToShow = new List<string>();
            if (myType == NetworkComponentType.tree) return WhatToShow; //return nothing
            switch(What)
            {
                case CaptionType.none:
                    break; //nothing to show
                case CaptionType.full:
                    WhatToShow.Add(hostname);
                    if (myType == NetworkComponentType.microwave || myType == NetworkComponentType.fluorescent) break;
                    foreach (NetworkCard nic in NICs)
                    {
                        if (nic.GetNicType != NicType.lo && nic.GetNicType != NicType.port && nic.GetNicType != NicType.wport)
                        {
                            string title = "";
                            if (nic.GetNicType == NicType.management_interface)
                                title += "if: ";
                            else
                                title += nic.NicName() + ": ";

                            foreach (string addr_str in nic.IPAddresses(true))
                            {
                                WhatToShow.Add(title + addr_str);
                            }
                        }
                    }
                    break;
                case CaptionType.host:
                    WhatToShow.Add(hostname);
                    break;
                case CaptionType.host_ip:
                    WhatToShow.Add(hostname);
                    if (myType == NetworkComponentType.microwave || myType == NetworkComponentType.fluorescent) break;
                    foreach (NetworkCard nic in NICs)
                    {
                        if (nic.GetNicType != NicType.lo && nic.GetNicType != NicType.port && nic.GetNicType != NicType.wport)
                        {
                            string title = "";
                            
                            foreach (string addr_str in nic.IPAddresses(true))
                            {
                                WhatToShow.Add(title + addr_str);
                            }
                        }
                    }
                    break;
                case CaptionType.ip:
                    if (myType == NetworkComponentType.microwave || myType == NetworkComponentType.fluorescent) break;
                    foreach (NetworkCard nic in NICs)
                    {
                        if (nic.GetNicType != NicType.lo && nic.GetNicType != NicType.port && nic.GetNicType != NicType.wport)
                        {
                            string title = "";

                            foreach (string addr_str in nic.IPAddresses(true))
                            {
                                WhatToShow.Add(title + addr_str);
                            }
                        }
                    }
                    break;
            }
            return WhatToShow;
        }

        /// <summary>
        /// Check all the network cards on this device to see if it has a nic with the given MAC address
        /// </summary>
        /// <param name="MAC">The MAC address we are looking for</param>
        /// <returns>True if we have it, false if we do not.</returns>
        public override bool HasMac(string MAC)
        {
            foreach(NetworkCard nic in NICs)
            {
                if (nic.MAC == MAC) return true;
            }
            return false;
        }


        /// <summary>
        /// Get the host nic IDentifier for the specified MAC address
        /// </summary>
        /// <param name="MacIndex">The index of the network card</param>
        /// <returns>The unique host-nic-ID</returns>
        public HostNicID GetHostNicID(int MacIndex)
        {
            if (MacIndex < 0 || MacIndex > NICs.Count())
                return new HostNicID(-1, -1, hostname, "");
            return NICs[MacIndex].myID;
        }

        /// <summary>
        /// Get the host nic IDentifier for the specified MAC address
        /// </summary>
        /// <param name="MacIndex">The index of the network card</param>
        /// <returns>The unique host-nic-ID</returns>
        public List<HostNicID> GetHostNicIDs()
        {
            List<HostNicID> tList = new List<HostNicID>();
            for (int looper = 0; looper < NICs.Count; looper++)
            {
                tList.Add(NICs[looper].myID);
            }
            return tList;
        }

        public bool HasIPAddress(NB_IPAddress dest)
        {
            foreach(NetworkCard nic in NICs)
            {
                if (nic.HasIPAddresses(dest))
                    return true;
            }
            return false;
        }

        public NB_IPAddress RouteMatching(NB_IPAddress dest)
        {
            //If we are comparing a route that has a 'special' netmask, make sure it is the right netmask
            foreach (NB_IPAddress ip in RouteTable)
            {
                if (dest.GetMask != 0 && dest.GetMask.ToIpString() != "255.255.255.0")
                {
                    if (dest.GetMask == ip.GetMask && ip.IsLocal(dest))
                        return ip;
                }
                else
                {
                    if (ip.IsLocal(dest))
                        return ip;
                }
            }
            return null;
        }

        public bool HasRouteMatching(NB_IPAddress dest)
        {
            NB_IPAddress matched = RouteMatching(dest);
            if (matched != null) return true;
            return false;
        }
        public bool HasRouteMatching(string destString)
        {
            NB_IPAddress dest = new NB_IPAddress(destString);
            if (dest.GetIPString == NB.ZeroIPString) return false;
            return HasRouteMatching(dest);
        }

        //public bool HasBroadcastAddress(IPAddress dest)
        //{
        //    foreach (NetworkCard nic in NICs)
        //    {
        //        if (nic.HasBroadcastAddresses(dest))
        //            return true;
        //    }
        //    return false;
        //}
        public bool HasBroadcastAddress(NB_IPAddress dest)
        {
            if (dest.BroadcastAddress == dest.GetIP) return true;
            foreach(NetworkCard nic in NICs)
            {
                if (nic.HasBroadcastAddresses(dest))
                    return true;
            }
            return false;
        }

        public bool HasBroadcastAddress(Packet tPacket)
        {
            return HasBroadcastAddress(tPacket.destIP);
        }

        public bool DoesRouting()
        {
            if (myType == NetworkComponentType.router) return true;
            if (myType == NetworkComponentType.firewall) return true;
            //We changed this to a port so it forwards, not routes
            //if (myType == NetworkComponentType.wap) return true;
            return false;
        }

        public bool CanBeLockedOut()
        {
            if (myType == NetworkComponentType.net_switch) return true;
            //if (myType == NetworkComponentType.wrouter) return true;
            return false;
        }

        public bool DoesForwarding()
        {
            if (myType == NetworkComponentType.net_hub)
                return true;
            if (myType == NetworkComponentType.net_switch)
                return true;
            if (myType == NetworkComponentType.wap) 
                return true;
            if (myType == NetworkComponentType.wbridge) 
                return true;
            if (myType == NetworkComponentType.wrepeater) 
                return true;
            if (myType == NetworkComponentType.wrouter) 
                return true;
            return false;
        }

        public bool DoesFirewall()
        {
            if (myType == NetworkComponentType.firewall)
                return true;
            if (myType == NetworkComponentType.wrouter)
                return true;
            return false;
        }

        public bool DoesVLANs()
        {
            if (myType == NetworkComponentType.net_switch)
                return true;
            //if (myType == NetworkComponentType.wrouter)
            //    return true;
            if (myType == NetworkComponentType.firewall)
                return true;
            if (myType == NetworkComponentType.router)
                return true;
            return false;
        }

        public override List<string> arp(UInt32 IP)
        {
            List<string> arps = new List<string>();
            foreach (NetworkCard nic in NICs)
            {
                if (nic.HasIP(IP)) arps.Add(nic.MAC);
            }
            return arps;
        }

        public override void UpdateFromComponent(NetworkComponent CopyFrom, bool NoteAllChanges = false)
        {
            if (CopyFrom.GetType() != this.GetType()) return; //we cannot copy from it if it is different
            NetworkDevice ndCopyFrom = (NetworkDevice)CopyFrom;
            if (Object.ReferenceEquals(this, CopyFrom)) return; //No need to copy values to itself

            Network mainnet = NB.GetNetwork();
            string indent = "    ";
            //if(NoteAllChanges && mainnet != null) mainnet.AddMessage(new PacketMessage("", indent + NB.Translate("NDUpdateComponent")));

            if (hostname != ndCopyFrom.hostname)
            {
                if (NoteAllChanges && mainnet != null) mainnet.AddMessage(new PacketMessage("", indent + "hostname: " + hostname + " -> " + ndCopyFrom.hostname));
                hostname = ndCopyFrom.hostname;
            }

            Size = ndCopyFrom.Size;
            if (DefaultGW.GetIPString != ndCopyFrom.DefaultGW.GetIPString)
            {
                if (NoteAllChanges && mainnet != null) mainnet.AddMessage(new PacketMessage("", indent + "DefaultGW: " + DefaultGW.GetIPString + " -> " + ndCopyFrom.DefaultGW.GetIPString));
                DefaultGW = ndCopyFrom.DefaultGW;
            }
            if (ndCopyFrom.MyImage != null)
                MyImage = new Bitmap(ndCopyFrom.MyImage);
            else
                MyImage = null;

            if (CanAddNics != ndCopyFrom.CanAddNics)
            {
                if (NoteAllChanges && mainnet != null) mainnet.AddMessage(new PacketMessage("", indent + "CanAddNics: " + CanAddNics + " -> " + ndCopyFrom.CanAddNics));
                CanAddNics = ndCopyFrom.CanAddNics;
            }

            if (CanServeDHCP != ndCopyFrom.CanServeDHCP)
            {
                if (NoteAllChanges && mainnet != null) mainnet.AddMessage(new PacketMessage("", indent + "CanServeDHCP: " + CanServeDHCP + " -> " + ndCopyFrom.CanServeDHCP));
                CanServeDHCP = ndCopyFrom.CanServeDHCP;
            }

            if (CanUseDHCP != ndCopyFrom.CanUseDHCP)
            {
                if (NoteAllChanges && mainnet != null) mainnet.AddMessage(new PacketMessage("", indent + "CanUseDHCP: " + CanUseDHCP + " -> " + ndCopyFrom.CanUseDHCP));
                CanUseDHCP = ndCopyFrom.CanUseDHCP;
            }

            if (MustUseDHCP != ndCopyFrom.MustUseDHCP)
            {
                if (NoteAllChanges && mainnet != null) mainnet.AddMessage(new PacketMessage("", indent + "MustUseDHCP: " + MustUseDHCP + " -> " + ndCopyFrom.MustUseDHCP));
                MustUseDHCP = ndCopyFrom.MustUseDHCP;
            }

            if (isDHCPServer != ndCopyFrom.isDHCPServer)
            {
                if (NoteAllChanges && mainnet != null) mainnet.AddMessage(new PacketMessage("", indent + "IsDHCPServer: " + isDHCPServer + " -> " + ndCopyFrom.isDHCPServer));
                isDHCPServer = ndCopyFrom.isDHCPServer;
            }

            if (isDNSServer != ndCopyFrom.isDNSServer)
            {
                if (NoteAllChanges && mainnet != null) mainnet.AddMessage(new PacketMessage("", indent + "IsDNSserver: " + isDNSServer + " -> " + ndCopyFrom.isDNSServer));
                isDNSServer = ndCopyFrom.isDNSServer;
            }

            if (HasAdvFirewall != ndCopyFrom.HasAdvFirewall)
            {
                if (NoteAllChanges && mainnet != null) mainnet.AddMessage(new PacketMessage("", indent + "HasAdvancedFirewall: " + HasAdvFirewall + " -> " + ndCopyFrom.HasAdvFirewall));
                HasAdvFirewall = ndCopyFrom.HasAdvFirewall;
            }
            
            MyLocation = ndCopyFrom.MyLocation;

            //Process NICs.
            if (NoteAllChanges && mainnet != null)
            {
                //List all nics that we are dropping
                foreach (NetworkCard nic in NICs)
                {
                    NetworkCard foundnic = ndCopyFrom.NicFromName(nic.NicName());
                    if (foundnic == null)
                        mainnet.AddMessage(new PacketMessage("", indent + "DropNIC: " + nic.NicName()));
                    else
                        {
                            //The nic still exists.  Note any major changes.  IP, netmask
                            if((foundnic.myNicType == NicType.wport || foundnic.myNicType == NicType.wlan) && foundnic.SSID != nic.SSID)
                                mainnet.AddMessage(new PacketMessage("", indent + "SSID: " + nic.SSID + " -> " + foundnic.SSID));
                        if ((foundnic.myNicType == NicType.vpn || foundnic.myNicType == NicType.vpn) && foundnic.EncryptionKey != nic.EncryptionKey)
                            mainnet.AddMessage(new PacketMessage("", indent + "EncryptionKey: " + nic.EncryptionKey + " -> " + foundnic.EncryptionKey));

                        //Compare interfaces - should be done at nic level...
                        if (foundnic.AllInterfacesString() != nic.AllInterfacesString())
                                mainnet.AddMessage(new PacketMessage("", indent + "Interfaces: " + nic.AllInterfacesString(true) + " -> " + foundnic.AllInterfacesString(true)));
                    }
                }
                //List all nics that we are dropping
                foreach (NetworkCard nic in ndCopyFrom.NICs)
                {
                    NetworkCard mynic = NicFromName(nic.NicName());
                    if (mynic == null)
                        mainnet.AddMessage(new PacketMessage("", indent + "AddNIC: " + nic.NicName() + " " +nic.AllInterfacesString()));
                }
            }

            //Now, copy across the NICs
            NICs.Clear();
            foreach(NetworkCard nic in ndCopyFrom.NICs)
            {
                nic.UpdateAllNicsVLANInfoAfterClone();
                NICs.Add(NetworkCard.Clone(nic));
            }

            FirewallRules.Clear();
            FirewallRules.AddRange(ndCopyFrom.FirewallRules);
            RouteTable.Clear();
            RouteTable.AddRange(ndCopyFrom.RouteTable);
            DHCPRanges.Clear();
            DHCPRanges.AddRange(ndCopyFrom.DHCPRanges);
            DHCPLeases.Clear();
            DHCPLeases.AddRange(ndCopyFrom.DHCPLeases);

            PowerOff = ndCopyFrom.PowerOff;
            IsBurned = ndCopyFrom.IsBurned;
        }

        public void DHCPRequestFromHere()
        {
            if (isFrozen() || IsBurned || PowerOff) return;
            bool tryit = false;
            if (CanUseDHCP)
            {
                foreach (NetworkCard tnic in NICs)
                {
                    if (tnic.UsesDHCP)
                        tryit = true;
                }
            }
            if (tryit)
            {
                //We need to create a packet
                foreach (NetworkCard nic in NICs)
                {
                    nic.SetIPForDHCP(); //clear the source IP
                }
                Packet DHCPPacket = new Packet(this, "", NB.BroadcastMACString, NB.Translate("NB_NetViewDHCP"), PacketType.dhcp_request);
                DHCPPacket.destIP = new NB_IPAddress(NB.BroadcastIPString);
                Network myNet = NB.GetNetwork();
                myNet.addPacket(DHCPPacket);
            }
        }

        public void ClearDHCPInfo()
        {
            bool tryit = false;
            if (CanUseDHCP)
            {
                foreach (NetworkCard tnic in NICs)
                {
                    if (tnic.UsesDHCP)
                        tryit = true;
                }
            }
            if (tryit)
            {
                foreach (NetworkCard nic in NICs)
                {
                    nic.SetIPForDHCP(); //clear the source IP
                }
            }
        }

        public void PingFromHere(NB_IPAddress Destination)
        {
            if (isFrozen() || IsBurned || PowerOff) return;
            //We need to create a packet
            Packet PingPacket = new Packet(this,Destination, NB.Translate("H_Ping_Title"), PacketType.ping_request);
            Network myNet = NB.GetNetwork();
            string dHost = myNet.ReverseDNSLookup(this, Destination);
            myNet.RegisterPingTest(hostname, dHost);
            myNet.addPacket(PingPacket);
        }

        public void BadPacketFromHere()
        {
            NB_IPAddress Destination = new NB_IPAddress(NB.ZeroIPString);  //this works like a broadcast
             
            if (isFrozen() || IsBurned || PowerOff) return;
            //We need to create a packet
            Packet BadPacket = new Packet(this, Destination, "----", PacketType.bad_packet); //generate a bad packet
            Network myNet = NB.GetNetwork();
            myNet.addPacket(BadPacket);
        }

        public void BadPacketIfIShould()
        {
            if(BadSprayCount > 0)
            {
                BadPacketFromHere();
                BadSprayCount--;
            }
        }

        public void TracerouteFromHere(NB_IPAddress Destination)
        {
            //We need to create a traceroute packet - start with 1 TTL
            //We pass it the destination as the payload string, so we have that for all traceroutes.
            Packet TracertPacket = new Packet(this, Destination, Destination.GetIPString, PacketType.tracert_request, -1, 1);
            Network myNet = NB.GetNetwork();
            myNet.addPacket(TracertPacket);
            tracertmessages.Clear(); //Start with a fresh bunch of messages
        }

        public void AskArpFromHere(NB_IPAddress Destination, PacketMessage Tracker=null)
        {
            //We need to create a packet
            if (isFrozen() || IsBurned || PowerOff) return;
            Packet ArpPacket = new Packet(this, Destination, NB.Translate("H_ARP_Title2"), PacketType.arp_request);
            if (Tracker != null)
                ArpPacket.ReplaceMessage(Tracker);
            Network myNet = NB.GetNetwork();
            myNet.addPacket(ArpPacket);
        }

        public void TunnelPacketFromHere(NB_IPAddress Destination, Packet Payload, string Encryption = "")
        {
            if(Destination == null)
            {
                Payload.MyStatus = PacketStatus.finished_failed;
                Payload.Tracking.AddMessage(DebugLevel.info, hostname, NB.Translate("ND_TunnelPacketFromHere_Error"));
                return;
            }
            PacketType TunType = PacketType.tun_packet;
            if (Encryption != "") 
                TunType = PacketType.vpn_packet;
            Packet TunnelPacket = new Packet(this, Destination, NB.Translate("ND_TunlPckTunl"), TunType);
            TunnelPacket.payloadPacket = Payload;            
            TunnelPacket.EncryptionString = Encryption;
            if(Payload != null)
                Payload.Tracking.AddMessage(DebugLevel.info, this, NB.Translate("ND_TunnelPacketFromHere_Message"));
            Network myNet = NB.GetNetwork();
            myNet.addPacket(TunnelPacket);
        }

        public void StoreOutgoingPacketInfo(Packet tpacket, ResponseToPacket response = ResponseToPacket.accept)
        {
            IPConnectionEntry ipc;
            if (response == ResponseToPacket.accept)
            {
                ipc = new IPConnectionEntry(tpacket.destIP, tpacket.MyType, ResponseToPacket.accept);
            }else
            {
                ipc = new IPConnectionEntry(tpacket.destIP, tpacket.MyType, ResponseToPacket.masq, tpacket.sourceIP);
            }
            IPConnections.Add(ipc);

        }
        public void ClearIPConnectionInfo()
        {
            IPConnections.Clear();
        }

        public void LockUsOutOfDevice()
        {
            foreach(NetworkCard nic in NICs)
            {
                if (nic.GetNicType == NicType.lo) continue;
                nic.LockUsOutOfCard();
            }
        }

        public ResponseToPacket HowToRespondToPacket(Packet tPacket)
        {
            bool typesMatch=false;
            if (tPacket.sourceIP == null) return ResponseToPacket.reject;
            if (tPacket.TsourceIP != null && !tPacket.TsourceIP.IsLocal(tPacket.destIP) && !HasBroadcastAddress(tPacket.destIP)) return ResponseToPacket.none;
            foreach(IPConnectionEntry ipc in IPConnections)
            {
                if (ipc.destIP.GetIP == tPacket.sourceIP.GetIP || HasBroadcastAddress(ipc.destIP))
                {
                    if (ipc.What == PacketType.arp_request && tPacket.MyType == PacketType.arp_answer)
                        typesMatch = true;
                    if (ipc.What == PacketType.dhcp_request && tPacket.MyType == PacketType.dhcp_answer)
                    {
                        //Console.WriteLine("  " + NB.LeftPad(hostname) + ": True");
                        typesMatch = true;
                    }
                    if (ipc.What == PacketType.ping_request && tPacket.MyType == PacketType.ping_answer)
                        typesMatch = true;
                    if (ipc.What == PacketType.tracert_request && tPacket.MyType == PacketType.tracert_reply)
                        typesMatch = true;
                    if (typesMatch)
                    {
                        return ipc.Response;
                    }
                }
                if (ipc.What == PacketType.tracert_request && tPacket.MyType == PacketType.tracert_reply)
                    return ipc.Response;
            }
            //If we get here, we were not expecting the packet
            return ResponseToPacket.reject;
        }

        public NB_IPAddress PacketMasqueradeSource(Packet tPacket)
        {
            bool typesMatch = false;
            foreach (IPConnectionEntry ipc in IPConnections)
            {
                if (ipc.destIP.GetIP == tPacket.sourceIP.GetIP && ipc.Response == ResponseToPacket.masq)
                {
                    if (ipc.What == PacketType.ping_request && tPacket.MyType == PacketType.ping_answer)
                        typesMatch = true;
                    if (ipc.What == PacketType.tracert_request && tPacket.MyType == PacketType.tracert_reply)
                        typesMatch = true;
                    if (typesMatch)
                    {
                        return ipc.internalIP;
                    }
                }
                else
                {
                    if (ipc.What == PacketType.tracert_request && tPacket.MyType == PacketType.tracert_reply)
                        return ipc.internalIP;
                }
            }
            //If we get here, we were not expecting the packet
            return null;
        }

        public bool IsWirelessForwarder()
        {
            if (myType == NetworkComponentType.wrepeater) return true;
            if (myType == NetworkComponentType.wap) return true;
            if (myType == NetworkComponentType.wbridge) return true;
            if (myType == NetworkComponentType.wrouter) return true;
            return false;
        }

        public bool LocalMatches(Packet tPacket)
        {
            //return false;
            //the tSourceIP is local to something on the device
            //The dest IP exists on the device.
            //If we have multiple IPs, the tdest is one, and the actual dest is another
            bool MatchesSource = false;
            bool MatchesDest = false;
            foreach(NetworkCard nic in NICs)
            {
                //If no IPs are defined, is it 0.0.0.0/0.0.0.0 which is local to everything
                if (nic.GetNicType == NicType.port) continue;
                if (nic.GetNicType == NicType.wport) continue;
                if (nic.HasLocalInterface(tPacket.TsourceIP))
                    MatchesSource = true;
                if (nic.HasIPAddresses(tPacket.destIP))
                    MatchesDest = true;
            }
            if (MatchesDest && MatchesSource) return true;
            return false;
        }

        public override void ProcessPacket(Packet tPacket)
        {
            //Psuedo code for processing a packet
            //We have already come in the interface and nic
            //We will set the outbound nic in this process here
            //All packets terminate in the device and either stop or are duplicated and sent out the next link
            //Store the nic this came from so we skip sending the packet back out the same one
            //   We only skip sending it out the same one if it is a port.

            //See if it arrives here.
            //  We route it if the dmac is this machine, but the dstIP does not match the IP of this machine
            //  if the dstIP matches exactly, it ends here.
            //  if the dstIP matches (broadcast), we process it but it still continues
            //  Set the "we have processed it" flag
            //  and we process arrival

            bool MacAddressMatch = HasMac(tPacket.destMAC);
            //It is an exact match if it is coming from a local source.
            bool HasIp = HasIPAddress(tPacket.destIP);
            bool ExactMatch = HasIp && (tPacket.TsourceIP == null || tPacket.TsourceIP.IsLocal(tPacket.destIP));
            bool LocalMatch = LocalMatches(tPacket);
            bool BroadcastMatch = HasBroadcastAddress(tPacket.destIP);
            bool NeedsRouting = MacAddressMatch && (!ExactMatch && !BroadcastMatch);

            int tID = tPacket.packetID;
            if (!tPacket.MyType.ToString().EndsWith("request"))
                tID = tID * -1;
            if(PacketIDsPassedThrough.Contains(tID))
            {
                NB.NoteLoopHappened(); //Note that we found a loop
            }
            else PacketIDsPassedThrough.Add(tID);

            if(ExactMatch || BroadcastMatch || LocalMatch)
            {
                    //Change this.  Need a new ProcessArrival
                if (tPacket.MyType != PacketType.dhcp_answer) //If it is a match, it should be handled elsewhere
                    ProcessArrival(tPacket);
                if (ExactMatch && tPacket.isFinshed())
                    return;
            }

            if (tPacket.DebugOn)
                Console.WriteLine("Debug");

            //Routing
            //if we are supposed to route (do-not-route flag not set) or if the packet is "fresh"
            //   determine which nic it is supposed to exit.
            //   loop through all the routes and nics to see if local delivery or if we use a gateway
            if(MacAddressMatch || tPacket.isFresh)
            {
                //It was destined for here, or it is starting from scratch.  See if we need to route it.
                if (tPacket.destIP == null) tPacket.destIP = new NB_IPAddress(NB.ZeroIPString);
                NB_IPAddress dest = DestinationFromIP(tPacket.destIP); //Get the IP, or GW
                if(dest.GetIPString == NB.ZeroIPString && tPacket.destIP.GetIPString != NB.BroadcastIPString)
                {
                    //No gateway set and no route...
                    string errString = string.Format(NB.Translate("ND_NoRouteStr"), hostname, tPacket.destIP.GetIPString);
                    tPacket.AddMessage(DebugLevel.info, errString);
                    tPacket.Tracking.Status = errString;
                    tPacket.MyStatus = PacketStatus.finished_failed;
                    return;
                }
                tPacket.TraversalInformation.AddPath(this.hostname, TraversalTechnology.ip_address,""); //We will use an outbound ip.
                if (dest.GetIP == tPacket.destIP.GetIP)
                {
                    //It is a local packet.  Let it go out the interface it needs to go out
                    tPacket.OutboundIP = tPacket.destIP;
                    tPacket.TsourceIP = null;
                }
                else if(tPacket.destIP.GetIPString != NB.BroadcastIPString)
                {
                    //it needs to go to a gateway.  Set the next destination is the GW
                    tPacket.OutboundIP = dest;
                    tPacket.TraversalInformation.AddPath(this.hostname, TraversalTechnology.gateway,""); //We just used a gateway
                    tPacket.TsourceIP = null;
                }
                else
                {
                    tPacket.OutboundIP = tPacket.destIP;
                    tPacket.TsourceIP = null;
                }

            }

            if (tPacket.isFinshed() && !BroadcastMatch) return;

            NetworkCard dNic = null;
            NetworkCard sNic = null;

            if (DoesForwarding())
            {
                foreach (ArpEntry arp in ArpTable)
                {
                    if (arp.MACAddress == tPacket.destMAC)
                    {
                        dNic = NicFromID(arp.NicOnWhichItIsFound);
                        break;
                    }
                    //if (arp.MACAddress == tPacket.sourceMAC)
                    //{
                    //    sNic = NicFromID(arp.NicOnWhichItIsFound);
                    //}
                }
            }
            sNic = tPacket.InboundNic; //We get the inbound nic from here.

            //Delivery
            //Loop through all nics (skip the interface) it came in on
            //  if it is a port, gen a new packet and send it out the port
            //      if it is broadcast, or if we have not processed it.
            //  if it is lo or management interface, skip the nic
            //  if it is a nic and we are supposed to route it, pass it to the nic.
            //     The nic will send it out all its interfaces
            //  If we need arp, the nic/interface holds onto it until the arp returns
            //     Store the nic on the packet, store the interface on the packet
            //     Resume processing at the nic level, not the device level when the arp comes back
            int count = 0;
            bool PacketSentOutWAN = false;
            foreach (NetworkCard nic in NICs)
            {
                NicType NT = nic.GetNicType;
                //bridges and waps are basically switches
                if ((myType == NetworkComponentType.wap || myType == NetworkComponentType.wbridge 
                    || myType == NetworkComponentType.wrepeater) && NT != NicType.management_interface)
                    NT = NicType.port;
                switch(NT)
                {
                    case NicType.lo:
                    case NicType.management_interface:
                    case NicType.none:
                        break; //Do nothing
                    case NicType.eth:
                    case NicType.tun:
                    case NicType.vpn:
                    case NicType.wan:
                    case NicType.wlan:
                        //If the packet is a new packet and is not connecting to itself
                        //or, if it is routing away.
                        if ((tPacket.isFresh && !ExactMatch ) || (NeedsRouting && DoesRouting()) ||
                            IsWirelessForwarder())
                        {
                            // if (nic == tPacket.InboundNic) break;  //this case is dealt with in nic.SendPacketOutNic
                            //Pass it to the NIC to send out each nic+interface.
                            //The nic checks to see if it works and then processes it
                            if(myType != NetworkComponentType.wbridge && myType != NetworkComponentType.wrepeater)  
                                if (!tPacket.isFresh && HasBroadcastAddress(tPacket.destIP))
                                    break;
                            string tMAC = tPacket.destMAC;
                            string ttMAC = tPacket.OutboundDestMAC;
                            
                            tPacket.VLANID = NB.UntaggedVLAN;  //we are routing, so we adopt the outgoing vlanID - state it needs to be tagged

                            if (BroadcastMatch && tPacket.MyType != PacketType.dhcp_answer)
                                tPacket.OutboundDestMAC = NB.BroadcastMACString;
                            tPacket.destMAC = tPacket.OutboundDestMAC;

                            if (nic.SendPacketOutNIC(tPacket))
                            {
                                count++;
                                if (nic.GetNicType == NicType.wan)
                                    PacketSentOutWAN = true;
                            }
                            tPacket.destMAC = tMAC;
                            tPacket.OutboundDestMAC = ttMAC;
                        }
                        break;
                    case NicType.port:
                    case NicType.wport:
                        if (PacketSentOutWAN)
                        {
                            continue; //do not send packets out of ports if they have been sent out a WAN nic
                        }
                        NetworkCard tdNic = dNic;
                        if (myType == NetworkComponentType.wrouter)
                        {
                            //On wRouters, the wPorts are hubs, but the ports are switches
                            if (dNic != null && dNic.GetNicType == NicType.wport && nic.GetNicType == NicType.wport)
                                tdNic = null;
                        }
                        else
                        {
                            if (nic.GetNicType == NicType.port && myType == NetworkComponentType.net_hub)
                                tdNic = null; //Hubs/WAPs never know the dnic.  They still need the sNic, however
                            if (nic.GetNicType == NicType.wport)
                                tdNic = null; //Hubs/WAPs never know the dnic.  They still need the sNic, however
                        }
                        if (!ExactMatch && (!MacAddressMatch || ForwardsPackets()))
                        {
                            //If the packet does not terminate here, and we are not routing it to here...
                            //Pass it to the port.  The port duplicates it and sends it out
                            //Do not send it out the port it came in on (sNic)
                            //If we know the dNic, only send it out that
                            //But if we do not know a dnic, send it out all of them (except the sNic)                            
                            if (sNic != nic && (tdNic == null || (tdNic != null && tdNic.ConnectedLink == -1) || tdNic == nic))
                            {
                                tPacket.TraversalInformation.AddPath(hostname, TraversalTechnology.forward,"");
                                if (nic.SendPacketOutNIC(tPacket))
                                {
                                    count++;
                                }
                            }
                        }
                        break;
                }
            }
            //The packet has either been duplicated or has finished
            if(count == 0)
            {
                if (tPacket.destMAC == "")
                {
                    if (tPacket.MyType == PacketType.arp_request)
                    {
                        //The packet was not successfully sent anywhere.  DMac = "".  This means no host with the specified IP
                        tPacket.AddMessage(DebugLevel.info, string.Format(NB.Translate("ND_ArpNoIPLocalStr"), hostname));
                        tPacket.Tracking.Status = string.Format(NB.Translate("ND_NoIPLocalStr"), hostname);
                        tPacket.MyStatus = PacketStatus.finished_failed;
                    }
                    else
                    {
                        //The packet was not successfully sent anywhere.  DMac = "".  This means no host with the specified IP
                        tPacket.AddMessage(DebugLevel.info, string.Format(NB.Translate("ND_NoIPStr"), hostname));
                        tPacket.Tracking.Status = string.Format(NB.Translate("ND_NoIPStr"), hostname);
                        tPacket.MyStatus = PacketStatus.finished_failed;
                    }
                }
                else
                {
                    //The packet was not successfully sent anywhere.  No interface to send out the packet
                    tPacket.AddMessage(DebugLevel.info, string.Format(NB.Translate("ND_NoLocalIfStr"), hostname));
                    tPacket.Tracking.Status = string.Format(NB.Translate("ND_NoLocalIfStr"), hostname);
                    tPacket.MyStatus = PacketStatus.finished_failed;
                }
            }
            if (tPacket.MyStatus != PacketStatus.finished_failed && tPacket.MyStatus != PacketStatus.finished_ok)
            {
                tPacket.MyStatus = PacketStatus.finished;
            }
        }


        public void ProcessArrival(Packet tPacket)
        {
            Packet nPacket;
            Network myNet = NB.GetNetwork();
            if (tPacket.MyType == PacketType.tun_packet || tPacket.MyType == PacketType.vpn_packet)
            {
                tPacket.Tracking.AddMessage(DebugLevel.info,this,NB.Translate("ND_ProcessArrival_Arrived"));
                tPacket.Tracking.Status = NB.Translate("ND_ProcessArrival_Arrived");
                //If the encryption matches, we succeed.  Otherwise, we fail
              
                tPacket.MyStatus = PacketStatus.finished_ok; //It stops here
                nPacket = tPacket.payloadPacket;
                if (nPacket.TraversalInformation != null && tPacket.TraversalInformation != null)
                    nPacket.TraversalInformation.AddPath(tPacket.TraversalInformation);
                NetworkCard nc = LocalNic(nPacket.TsourceIP, true);
                nPacket.TsourceIP = null;
                if (nc != null)
                {
                    if (nPacket != null)
                    {
                        if (nPacket.destMAC != nc.MAC)
                        {
                            nPacket.Tracking.Status = NB.Translate("ND_ProssArr_Error1");
                            nPacket.Tracking.AddMessage(DebugLevel.info, this, NB.Translate("ND_ProssArr_Error"));
                            nPacket.MyStatus = PacketStatus.finished_failed;
                            myNet.addPacket(nPacket);  //so it gets pulled out apropriately
                            tPacket.payloadPacket = null;
                            return;
                        }
                        else
                        if (tPacket.EncryptionString == nc.EncryptionKey)
                        {
                            nPacket.destMAC = nc.MAC;  //This is already the case, but we need to set it again for some reason.
                            nPacket.InboundInterface = nc.InterfaceFromName(nc.NicName()) ;

                            nPacket.MyStatus = PacketStatus.processing;
                            nPacket.WhereAmI = this;
                            nPacket.Tracking.AddMessage(DebugLevel.info, this, NB.Translate("ND_ProcessArrival_CommingOut"));
                            myNet.addPacket(nPacket);
                            tPacket.payloadPacket = null;
                            if (ProcessTracertPacket(nPacket))
                            {
                                return; //the packet stops if it gets bounced.
                            }
                            return;
                        }
                        else
                        {
                            nPacket.Tracking.Status = NB.Translate("ND_ProcessArrival_EncryptErr1");
                            nPacket.Tracking.AddMessage(DebugLevel.info, this, NB.Translate("ND_ProcessArrival_EncryptErr2"));
                            nPacket.MyStatus = PacketStatus.finished_failed;
                            myNet.addPacket(nPacket);  //so it gets pulled out apropriately
                            tPacket.payloadPacket = null;
                            return;
                        }
                    }
                    else
                    {
                        //There is no nic that matches the incoming IP
                        nPacket.Tracking.Status = NB.Translate("ND_ProssArr_Error1");
                        nPacket.Tracking.AddMessage(DebugLevel.info, this, NB.Translate("ND_ProssArr_Error"));
                        nPacket.MyStatus = PacketStatus.finished_failed;
                        myNet.addPacket(nPacket);  //so it gets pulled out apropriately
                        return;
                    }
                }
            }
            if (tPacket.MyType == PacketType.ping_request)
            {
                myNet.RegisterTimeOfArrival();
                bool isbroadcast = HasBroadcastAddress(tPacket);
                if (!isbroadcast || (isbroadcast && HasLocalNic(tPacket.sourceIP)))
                {
                    //We would be responding to it.  We have an odd case for switches.
                    //Verify that the management IP can talk to the packet
                    
                    if(CanBeLockedOut())
                    {
                        //only a few devices have management ips
                        NetworkCard nic = HubManagementCard();
                        if(nic != null)
                        {
                            NetworkInterface nif = nic.GetInterface(0); //management interfaces only have one ip
                            if(nif != null)
                            {
                                VLANTagType VTT = nif.GetVLANTag(tPacket.VLANID);
                                if(VTT == VLANTagType.Forbidden)
                                {
                                    //we cannot ping!  The packet is blocked by vlan
                                    //Console.WriteLine("blocked by vlan");
                                    tPacket.AddMessage(DebugLevel.info, NB.Translate("ND_PrepPackVLANErr"));
                                    tPacket.Tracking.Status = NB.LeftPad(hostname) + " " + string.Format(NB.Translate("ND_PrepPackVLANErr")) + tPacket.sourceIP.GetIP.ToIpString() + " -> " + hostname;
                                    tPacket.MyStatus = PacketStatus.finished_failed;
                                    return;
                                }
                            }
                        }
                    }
                    tPacket.TraversalInformation.AddPath(hostname, TraversalTechnology.arrived,"");
                    nPacket = new Packet(this, tPacket.sourceIP, "", PacketType.ping_answer, tPacket.packetID);
                    nPacket.OriginalDestIP = tPacket.destIP;
                    nPacket.isFresh = true; //So it starts from here
                    nPacket.Tracking = new PacketMessage();
                    myNet.addPacket(nPacket);
                    tPacket.AddMessage(DebugLevel.info, NB.Translate("ND_ProcessArrival_PingReached1"));
                    tPacket.Tracking.Status = NB.LeftPad(hostname) + " Ping " + NB.Translate("ND_ProcessArrival_PingReached1") + tPacket.sourceIP.GetIP.ToIpString() + "-> " + tPacket.destIP.GetIP.ToIpString();
                    tPacket.MyStatus = PacketStatus.finished_ok;
                    NB_IPAddress tip = nPacket.sourceIP;
                    if (!HasBroadcastAddress(tPacket.destIP))
                    {
                        nPacket.sourceIP = tPacket.destIP;
                        nPacket.TsourceIP = tPacket.destIP;
                    }
                    else
                    {
                        nPacket.sourceIP = new NB_IPAddress(NB.ZeroIPString);
                        nPacket.TsourceIP = new NB_IPAddress(NB.ZeroIPString);
                    }
                    if (tip.GetIP.ToIpString() != NB.ZeroIPString)
                        nPacket.destIP = tip;
                    if (tPacket.isFresh)
                    {
                        //The packet reached itself.  At this moment, the packet does not yet have the source information set
                        //We just need to set the dest
                        //
                        nPacket.destIP = new NB_IPAddress(NB.LoopbackIPString);
                    }
                    if (myType == NetworkComponentType.net_hub || myType == NetworkComponentType.net_switch ||
                        myType == NetworkComponentType.wrouter)
                    {
                        //put mac of management interface on packet
                        //dmac is originating mac
                        nPacket.destMAC = tPacket.sourceMAC;
                        nPacket.OutboundDestMAC = tPacket.sourceMAC;
                        nPacket.sourceMAC = HubManagementMAC();
                    }
                    else
                    {
                        nPacket.destMAC = "";
                        nPacket.sourceMAC = "";
                    }
                    nPacket.MyType = PacketType.ping_answer;
                    nPacket.MyStatus = PacketStatus.processing;
                }
                else
                {
                    tPacket.AddMessage(DebugLevel.info, NB.Translate("ND_ProssArr_PingErr"));
                    tPacket.Tracking.Status = NB.LeftPad(hostname) + " " + string.Format(NB.Translate("ND_ProssArr_PingErr")) + tPacket.sourceIP.GetIP.ToIpString() + " -> " + hostname;
                    tPacket.MyStatus = PacketStatus.finished_ok;
                }
                return;
            }
            if (tPacket.MyType == PacketType.ping_answer)
            {
                ResponseToPacket response = HowToRespondToPacket(tPacket);
                if (response == ResponseToPacket.none) return; //We do not do anything with it here.
                if (response == ResponseToPacket.accept || (HasIPAddress(tPacket.destIP) && (tPacket.TsourceIP == null || tPacket.destIP.IsLocal(tPacket.TsourceIP))))
                {
                    if (tPacket.health < 100)
                    {
                        tPacket.AddMessage(DebugLevel.info, string.Format(NB.Translate("ND_ProssArrSomeLostStr"), tPacket.health.ToString()) );
                        int left = 100 - tPacket.health;
                        tPacket.Tracking.Status = NB.LeftPad(hostname) + " " + string.Format(NB.Translate("ND_ProssArrPartialStr"), left , tPacket.sourceIP.GetIP.ToIpString(),tPacket.destIP.GetIP.ToIpString());
                        tPacket.MyStatus = PacketStatus.finished_ok;
                    }
                    else
                    {
                        tPacket.TraversalInformation.AddPath(hostname, TraversalTechnology.arrived,"");
                        tPacket.AddMessage(DebugLevel.info, NB.Translate("ND_ProcessArrival_PingReturn1"));
                        tPacket.Tracking.Status = NB.LeftPad(hostname) + " " + string.Format(NB.Translate("ND_ProssArrSuccessStr"), tPacket.sourceIP.GetIP.ToIpString(), tPacket.destIP.GetIP.ToIpString());
                        tPacket.MyStatus = PacketStatus.finished_ok;
                        if (tPacket.sourceIP.GetIP != 0)
                        {
                            myNet.NotePacketArrived(tPacket.MyType, this, tPacket.destIP, tPacket.OriginalDestIP, tPacket.packetID);
                        }
                        else
                        {
                            myNet.NotePacketArrived(tPacket.MyType, this, tPacket.destIP, tPacket.sourceIP, tPacket.packetID);
                        }
                    }
                }
                else
                {
                    tPacket.AddMessage(DebugLevel.info, NB.Translate("ND_ProcessArrival_PackReturnErr1"));
                    tPacket.Tracking.Status = NB.LeftPad(hostname) + " " + string.Format(NB.Translate("ND_ProssArrPngFailStr"), tPacket.sourceIP.GetIP.ToIpString(), tPacket.destIP.GetIP.ToIpString());
                    tPacket.MyStatus = PacketStatus.finished_failed;
                }
                return;
            }
            //Tracert_request is processed on the link arrival
            if (tPacket.MyType == PacketType.tracert_reply)
            {
                ResponseToPacket response = HowToRespondToPacket(tPacket);
                if (response == ResponseToPacket.none || response == ResponseToPacket.masq) return; //We do not do anything with it here.
                //The reply got here.  This packet is done

                NB_IPAddress origStart = new NB_IPAddress(tPacket.payloadData);
                int ttl = tPacket.OrigTTL + 1;

                //Console.WriteLine("Tracert: " + tPacket.OrigTTL + " " + tPacket.sourceIP.GetIPString);
                //Console.WriteLine("Tracert: -- " + tPacket.sourceIP.GetIPString + " " + origStart.GetIPString);
                //If we had not landed on the actual dest...
                tPacket.TraversalInformation.AddPath(hostname, TraversalTechnology.arrived,"");

                tracertmessages.Add(NB.Translate("ND_ProcessArrival_TracertReply") + " " + tPacket.sourceIP.GetIPString);

                if (tPacket.sourceIP.GetIPString != origStart.GetIPString && ttl < 10)
                {
                    Packet trPacket = new Packet(this, origStart, origStart.GetIPString, PacketType.tracert_request, -1, ttl);
                    myNet.addPacket(trPacket);
                    myNet.ResetPacketTimeout();
                }
                if (tPacket.sourceIP.GetIPString == origStart.GetIPString)
                {
                    myNet.NotePacketArrived(tPacket.MyType, this, tPacket.destIP, tPacket.sourceIP, tPacket.packetID);
                    foreach(string message in tracertmessages)
                    {
                        tPacket.Tracking.AddMessage(DebugLevel.info, this, message);
                        Console.WriteLine(message);
                    }
                    tracertmessages.Clear();
                }
                tPacket.AddMessage(DebugLevel.info, NB.Translate("ND_ProcessArrival_TracertReply") + " " + tPacket.sourceIP.GetIPString);
                tPacket.Tracking.Status = NB.LeftPad(hostname) + " " + string.Format(NB.Translate("ND_ProcessArrival_TracertReply") + " " + tPacket.sourceIP.GetIPString);
                tPacket.MyStatus = PacketStatus.finished_ok;

                return;
            }
            if (tPacket.MyType == PacketType.arp_request)
            {
                //The arp request may not be asking for this IP.
                if(HasIPAddress(tPacket.destIP))
                {
                    nPacket = new Packet(tPacket);
                    nPacket.isFresh = true; //So it starts from here
                    nPacket.Tracking = new PacketMessage();
                    myNet.addPacket(nPacket);
                    NetworkCard nic = LocalNic(nPacket.sourceIP);
                    HostNicID theID = new HostNicID();
                    if (nic != null) theID = nic.myID;
                    if (nPacket.TsourceIP == null) nPacket.TsourceIP = nPacket.sourceIP;
                    StoreArp(nPacket.sourceMAC, nPacket.TsourceIP.GetIP.ToIpString(), theID);
                    //This is the IP we are looking for, send response back
                    NB_IPAddress tip = nPacket.sourceIP;
                    nPacket.sourceIP = nPacket.destIP;
                    nPacket.TsourceIP = nPacket.destIP;
                    nPacket.destIP = tip;
                    if (myType == NetworkComponentType.net_hub || myType == NetworkComponentType.net_switch || 
                        myType == NetworkComponentType.wrouter)
                    {
                        //put mac of management interface on packet
                        //dmac is originating mac
                        nPacket.destMAC = nPacket.sourceMAC;
                        nPacket.OutboundDestMAC = nPacket.sourceMAC;
                        List<string> tstrings = new List<string>();
                        foreach(NetworkCard tNic in NICs)
                        {
                            tstrings.Clear();
                            tstrings.AddRange(tNic.IPAddresses());
                            if (tstrings.Count > 0 && !Regex.IsMatch(tstrings[0], "127.0.0.1"))
                            {
                                nPacket.sourceMAC = tNic.MAC;
                                break;
                            }
                        }
                    }
                    else
                    {
                        nPacket.destMAC = "";
                        tPacket.sourceMAC = "";
                    }
                    nPacket.MyType = PacketType.arp_answer;
                    nPacket.MyStatus = PacketStatus.processing;

                    tPacket.AddMessage(DebugLevel.info, NB.Translate("ND_ProcessArrival_ArpReached1"));
                    tPacket.Tracking.Status = NB.LeftPad(hostname) + " " + string.Format(NB.Translate("ND_ProssArrArp")) +  "IP: " + tPacket.sourceIP.GetIPString + " MAC: "+ nPacket.sourceMAC;
                    tPacket.MyStatus = PacketStatus.finished_ok;
                }
                else
                {                
                    tPacket.MyStatus = PacketStatus.finished; //We just drop it
                }
                return;
            }
            if (tPacket.MyType == PacketType.arp_answer)
            {
                ResponseToPacket response = HowToRespondToPacket(tPacket);
                if (response == ResponseToPacket.accept)
                {

                    NetworkCard nic = LocalNic(tPacket.destIP);
                    HostNicID myid = nic.myID;
                    StoreArp(tPacket.sourceMAC, tPacket.TsourceIP.GetIP.ToIpString(), myid);
                    tPacket.Tracking.Status = NB.LeftPad(hostname) + " " + string.Format(NB.Translate("ND_ProssArrArpSuccessStr"), tPacket.sourceIP.GetIP.ToIpString(), tPacket.sourceIP.GetIP.ToIpString(), tPacket.sourceMAC);
                    tPacket.MyStatus = PacketStatus.finished_ok; //Yay!
                    myNet.NotePacketArrived(tPacket.MyType, this, tPacket.destIP, tPacket.sourceIP, tPacket.packetID);
                }
                else
                {
                    tPacket.AddMessage(DebugLevel.info, NB.Translate("ND_ProcessArrival_PackReturnErr1"));
                    tPacket.Tracking.Status = NB.LeftPad(hostname) + " " + string.Format(NB.Translate("ND_ProssArrArpFailStr"), tPacket.sourceIP.GetIP.ToIpString(), tPacket.destIP.GetIP.ToIpString());
                    tPacket.MyStatus = PacketStatus.finished_failed;
                }
                return;
            }
            if(tPacket.MyType == PacketType.dhcp_request && isDHCPServer)
            {
                nPacket = new Packet(tPacket);
                nPacket.isFresh = true; //So it starts from here
                nPacket.Tracking = new PacketMessage();
                myNet.addPacket(nPacket);
               //We need to find a dhcp IP for this.
                NB_IPAddress dst;
                if (tPacket.InboundInterface == null)
                {
                    dst = RequestDHCPLease(tPacket.sourceMAC, tPacket.OutboundIP);
                    nPacket.OutboundIP = tPacket.OutboundIP;
                }
                else
                {
                    dst = RequestDHCPLease(tPacket.sourceMAC, tPacket.InboundInterface.myIP);
                    nPacket.OutboundIP = tPacket.InboundInterface.myIP;
                }
                //if the packet came in on a port...
                if (tPacket.InboundNic != null && (tPacket.InboundNic.GetNicType == NicType.wport || tPacket.InboundNic.GetNicType == NicType.port))
                {
                    NB_IPAddress theIP = HubManagementIP();
                    if (theIP != null)
                        dst = RequestDHCPLease(tPacket.sourceMAC, theIP);
                }
                string tmac = nPacket.sourceMAC;
                nPacket.sourceMAC = tPacket.OutboundMAC;
                if (tPacket.InboundInterface != null)
                    nPacket.sourceIP = tPacket.InboundInterface.myIP;
                else
                    nPacket.sourceIP = tPacket.OutboundIP;
                nPacket.destMAC = tmac;
                nPacket.OutboundDestMAC = tmac;
                nPacket.payloadIP = dst;
                nPacket.MyType = PacketType.dhcp_answer;
                nPacket.OutboundMAC = "";
                nPacket.OutboundIP = null;
                nPacket.MyStatus = PacketStatus.processing;

                tPacket.AddMessage(DebugLevel.info, NB.Translate("ND_ProcessArrival_DHCPReach1"));
                string IP = "";
                if (nPacket.sourceIP != null) IP = nPacket.sourceIP.GetIPString;
                if(IP == "" && nPacket.WhereAmI != null) {
                    NB_IPAddress tIP = HubManagementIP();
                    if (tIP != null) IP = tIP.GetIPString; 
                }
                tPacket.Tracking.Status = NB.LeftPad(hostname) + " " + string.Format(NB.Translate("ND_ProssArrDHCPStr"), IP);
                //If we are a wireless router, we need to keep passing the broadcast request on
                if(!DoesForwarding())
                    tPacket.MyStatus = PacketStatus.finished_ok;
                return;
            }
            if (tPacket.MyType == PacketType.dhcp_answer)
            {
                ResponseToPacket response = HowToRespondToPacket(tPacket);
                if (response == ResponseToPacket.accept)
                {
                    NetworkCard tnic = tPacket.OutboundNic;
                    if (tnic == null || tnic.GetNicType == NicType.port || tnic.GetNicType == NicType.wport)
                        tnic = HubManagementCard();
                    if (tnic != null)
                    {
                        if (tPacket.payloadIP == null)
                            tPacket.payloadIP = new NB_IPAddress(NB.ZeroIPString);
                        tnic.SetIPForDHCP(tPacket.payloadIP);
                        IsDirty = true; //If we need to redraw the device IP
                        tPacket.Tracking.Status = NB.LeftPad(hostname) + " " + string.Format(NB.Translate("ND_ProssArrDHCPAnsStr"), tPacket.payloadIP.GetIP.ToIpString());
                        tPacket.MyStatus = PacketStatus.finished_ok; //Yay!
                        myNet.NotePacketArrived(tPacket.MyType, this, tPacket.payloadIP, tPacket.sourceIP, tPacket.packetID);
                        return;
                    }
                }
                else if(!tPacket.isFresh && !ForwardsPackets())
                {
                    tPacket.AddMessage(DebugLevel.info, NB.Translate("ND_ProcessArrival_PackReturnErr1"));
                    string sIP = "?.?.?.?";
                    if (tPacket.sourceIP != null) 
                        sIP = tPacket.sourceIP.GetIP.ToIpString();
                    tPacket.Tracking.Status = NB.LeftPad(hostname) + " " + string.Format(NB.Translate("ND_ProssArrDHCPFailStr"), sIP, tPacket.destIP.GetIP.ToIpString());
                    tPacket.MyStatus = PacketStatus.finished_failed;
                }
                return;
            }
            //Fall-through, if nothing else happens
            tPacket.MyStatus = PacketStatus.finished; //Different things may have different finished things.
        }

        public NB_IPAddress LocalDeviceIP(NetworkDevice FromWhat)
        {
            NetworkInterface nif;
            List<NB_IPAddress> myList = FromWhat.IPAddressList();
            foreach (NB_IPAddress ip in myList.ToList())
            {
                foreach (NetworkCard tNic in NICs)
                {
                    if (tNic.GetNicType == NicType.lo) continue; //Don't check loopback nics
                    if (tNic.GetNicType == NicType.port) continue; //Don't check ports
                    nif = tNic.LocalInterface(ip, null);
                    if(nif != null && nif.myIP.GetIPString != NB.ZeroIPString)
                    {
                        return nif.myIP;
                    }
                }
            }
            //If we get here, we do not have a local IP
            return null;
        }

        public NB_IPAddress HubManagementIP()
        {
            List<NB_IPAddress> IPAddresses = new List<NB_IPAddress>();
            foreach (NetworkCard tNic in NICs)
            {
                if(tNic.GetNicType == NicType.management_interface)
                {
                    IPAddresses.AddRange(tNic.IPAddressList());
                }
            }
            if (IPAddresses.Count > 0)
                return IPAddresses[0];
            return null;
        }

        public NetworkCard HubManagementCard()
        {
            foreach (NetworkCard tNic in NICs)
            {
                if (tNic.GetNicType == NicType.management_interface)
                {
                    return tNic;
                }
            }
            return null;
        }


        public string HubManagementMAC()
        {
            foreach(NetworkCard nic in NICs)
            {
                if (nic.GetNicType == NicType.management_interface)
                    return nic.MAC;
            }
            return null;
        }

        public bool DeviceIsLockedOutByVLANs()
        {
            if (!CanBeLockedOut())
                return false; //We can only be locked out of a few things.
            NetworkCard nic = HubManagementCard();
            if (nic == null) return false; //this should never happen.  Eject for now.
            NetworkInterface nif = nic.GetInterface(0);
            if (nif == null) return false;//this should never happen.  Eject for now.
            int managementID = nif.GetNonForbiddenVLANID();

            bool lockedOUT = true;
            
            foreach(NetworkCard tCard in NICs)
            {
                if (tCard.GetNicType == NicType.lo) continue;
                if (tCard.GetNicType == NicType.management_interface) continue;

                NetworkInterface tNIF = tCard.InterfaceFromVlanTag(managementID);
                if(tNIF != null)
                {
                    lockedOUT = false;
                    break;
                }
            }
            return lockedOUT;
        }

        public List<NB_IPAddress> IPAddressList()
        {
            List<NB_IPAddress> thelist = new List<NB_IPAddress>();
            foreach(NetworkCard nic in NICs)
            {
                thelist.AddRange(nic.IPAddressList());
            }
            return thelist;
        }

        public List<string> SubnetList()
        {
            List<string> thelist = new List<string>();
            foreach(NB_IPAddress taddr in IPAddressList())
            {
                if(!thelist.Contains(taddr.NetworkAddress.ToIpString()))
                {
                    thelist.Add(taddr.NetworkAddress.ToIpString());
                }
            }
            return thelist;
        }

        public List<string> BroadcastList()
        {
            List<string> thelist = new List<string>();
            foreach (NB_IPAddress taddr in IPAddressList())
            {
                if (!thelist.Contains(taddr.BroadcastAddress.ToIpString()))
                {
                    thelist.Add(taddr.BroadcastAddress.ToIpString());
                }
            }
            return thelist;
        }


        /// <summary>
        /// Return either the destination IP or the gateway IP
        /// </summary>
        /// <param name="dest">The target IP</param>
        /// <returns>The IP the packet should be going to</returns>
        public NB_IPAddress DestinationFromIP(NB_IPAddress dest, NetworkCard oNic = null)
        {
            NetworkInterface nIF = null;
            NetworkCard tCard = null;
            NB_IPAddress DestAddr;
            string DHCPGW = "";
            foreach( NB_IPAddress ip in RouteTable)
            {
                if (ip.IsLocal(dest))
                    return new NB_IPAddress(ip.GetGateway.ToIpString());//We return the gateway
            }
            foreach (NetworkCard nic in NICs)
            {
                tCard = nic;
                if(nic.UsesDHCP && nic.CanUseDHCP && DHCPGW == "")
                {
                    DHCPGW = nic.FirstIP().GetGateway.ToIpString();
                }
                nIF = nic.LocalInterface(dest,null);
                if (nIF != null && nIF.myIP.GetIPString != NB.ZeroIPString)
                {
                    DestAddr = dest; //We found it.  Send it to the destination
                    return DestAddr;
                }
            }
            if (oNic != null)
            {
                List<NB_IPAddress> tlist = oNic.IPAddressList();
                if(tlist.Count > 0 && tlist[0].GetGateway.ToIpString() != NB.ZeroIPString)
                {
                    return new NB_IPAddress(tlist[0].GetGateway.ToIpString());
                }
            }
            if (DHCPGW != "")
                return new NB_IPAddress(DHCPGW);
                //if we get here, we do not know where to send it.  Use the default gw.
            return DefaultGW;
        }

        public bool PrepPacketForSending(Packet tPacket, NB_IPAddress dest)
        {
            if((tPacket.OutboundMAC == null || tPacket.OutboundMAC == "") && 
                tPacket.MyType == PacketType.dhcp_request && 
                (tPacket.sourceMAC == "" || tPacket.sourceMAC == null))
            {
                //
                Network myNet = NB.GetNetwork();
                foreach(NetworkCard nic in NICs)
                {
                    //Make one DHCP request for every nic that is a DHCP nic
                    if(nic.UsesDHCP && CanUseDHCP)
                    {
                        nic.SetIPForDHCP();
                        Packet nPacket = new Packet(tPacket);
                        nPacket.OutboundIP = new NB_IPAddress(NB.ZeroIPString);
                        nPacket.OutboundMAC = nic.MAC;
                        nPacket.OutboundNic = nic;
                        nPacket.OutboundIF = nic.GetInterface(0);
                        nPacket.Tracking = new PacketMessage(); //we are starting.  Each one should have a different tracker
                        myNet.addPacket(nPacket);
                    }
                }

                tPacket.MyStatus = PacketStatus.finished; //we have replaced it with other ones
                return false;
            }

            if ((tPacket.OutboundMAC == null || tPacket.OutboundMAC == "") &&
                HasBroadcastAddress(tPacket.destIP) &&
                (tPacket.sourceMAC == "" || tPacket.sourceMAC == null))
            {
                //
                Network myNet = NB.GetNetwork();
                foreach (NetworkCard nic in NICs)
                {
                    if (!nic.HasIP(new NB_IPAddress("127.0.0.1").GetIP)) //don't bother pinging on the loopback
                    {
                        //Make one Broadcast ping for every nic that has an IP
                        Packet nPacket = new Packet(tPacket);
                        nPacket.OutboundIP = new NB_IPAddress(NB.ZeroIPString);
                        nPacket.OutboundMAC = nic.MAC;
                        nPacket.destMAC = NB.BroadcastMACString;
                        nPacket.OutboundNic = nic;
                        nPacket.OutboundIF = nic.GetInterface(0);
                        nPacket.Tracking = new PacketMessage(); //we are starting.  Each one should have a different tracker
                        myNet.addPacket(nPacket);
                    }
                }

                tPacket.MyStatus = PacketStatus.finished; //we have replaced it with other ones
                return false;
            }
            if (tPacket.OutboundIP == null || tPacket.OutboundIP.GetIP.ToIpString() == NB.ZeroIPString && tPacket.MyType != PacketType.dhcp_request)
            {
                tPacket.OutboundIP = DestinationFromIP(dest,tPacket.OutboundNic);
                if (tPacket.OutboundIP.GetIP.ToIpString() == NB.ZeroIPString)
                {
                    if (tPacket.MyType == PacketType.dhcp_answer)
                    {
                        tPacket.AddMessage(DebugLevel.info, NB.LeftPad(hostname) + " " +  string.Format(NB.Translate("ND_PrepPackGtewyErr")) + " " + tPacket.OutboundIP.GetIP.ToIpString());
                        tPacket.Tracking.Status = NB.LeftPad(hostname) + " " + string.Format(NB.Translate("ND_PrepPackGtewyErr"));
                        tPacket.MyStatus = PacketStatus.finished_failed;
                        return false;
                    }
                    else
                    {
                        tPacket.AddMessage(DebugLevel.info, NB.LeftPad(hostname) + " " + string.Format(NB.Translate("ND_PrepPackRoutErr")) +" "+ tPacket.OutboundIP.GetIP.ToIpString());
                        tPacket.Tracking.Status = NB.LeftPad(hostname) + " " + NB.Translate("ND_PrepPackRoutErr");
                        tPacket.MyStatus = PacketStatus.finished_failed;
                        return false;
                    }
                }
            }
            //If we get here, we have the local destination (dest or gateway) we are looking for.
            //Now we find the nic and interface
            if (tPacket.OutboundNic == null)
            {
                tPacket.OutboundNic = LocalNic(tPacket.OutboundIP);
                if (tPacket.OutboundNic == null)
                {
                    tPacket.AddMessage(DebugLevel.info, NB.LeftPad(hostname) + " " + string.Format(NB.Translate("ND_PrepPackNICErr"))  + "  :"+ tPacket.OutboundIP.GetIP.ToIpString());
                    tPacket.Tracking.Status = NB.LeftPad(hostname) + " " + NB.Translate("ND_PrepPackNICErr");
                    tPacket.MyStatus = PacketStatus.finished_failed;
                    return false;
                }
            }
            //If we get here, the nic is not null.  Find the IF corresponding to the outbound IP
            if (tPacket.OutboundIF == null)
            {
                tPacket.OutboundIF = tPacket.OutboundNic.LocalInterface(tPacket.OutboundIP, tPacket.Tracking);
                if (tPacket.OutboundIF == null)
                {
                    tPacket.AddMessage(DebugLevel.info, NB.LeftPad(hostname) + " " + string.Format(NB.Translate("ND_PrepPackRoutErr")) + "  :" + tPacket.OutboundIP.GetIP.ToIpString());
                    tPacket.Tracking.Status = NB.LeftPad(hostname) + " " + NB.Translate("ND_PrepPackRoutErr");
                    tPacket.MyStatus = PacketStatus.finished_failed;
                    return false;
                }
            }
            tPacket.TsourceIP = tPacket.OutboundIF.myIP;
            //
            if (tPacket.destMAC == "" || tPacket.destMAC == null) //was != broadcast-mac
            {
                tPacket.OutboundMAC = ArpFromIP(tPacket.OutboundIP);
            }
            else
            {
                tPacket.OutboundMAC = tPacket.destMAC;
            }
            if (tPacket.OutboundMAC == "")
            {
                bool todo = true;
                if (tPacket.OutboundNic != null && tPacket.OutboundNic.GetNicType == NicType.lo)
                    todo = false;
                if (HasBroadcastAddress(tPacket.destIP))
                {
                    tPacket.OutboundMAC = NB.BroadcastMACString;
                    todo = false;
                }
                if (todo)
                {
                    AskArpFromHere(tPacket.OutboundIP);
                    //we do not have a mac address for it.  Need to do an arp.
                    tPacket.TickTTL = 300;
                    tPacket.MyStatus = PacketStatus.waiting_for_arp;
                    return false;
                }
            }
            return true;
        }

        /// <summary>
        /// Return the network card that is considered "local" for the given IP
        /// </summary>
        /// <param name="toFind">The IP Address we are looking for</param>
        /// <returns>a network card, or null if nothing matches</returns>
        public NetworkCard LocalNic(NB_IPAddress toFind, bool skipZero= false)
        {
            NetworkInterface nIF;
            foreach (NetworkCard nic in NICs)
            {
                nIF = nic.LocalInterface(toFind, null);
                if (nIF != null) {
                    if (nIF.myIP.GetIPString == NB.ZeroIPString)
                        continue;
                    return nic;
                }
            }
            if(!skipZero)
            {
                foreach (NetworkCard nic in NICs)
                {
                    nIF = nic.LocalInterface(toFind, null);
                    if (nIF != null)
                    {
                        return nic;
                    }
                }
            }
            return null;
        }


        public List<string> NICRouteStrings()
        {
            List<string> answer = new List<string>();
            string GW = DefaultGW.GetIP.ToIpString();
            foreach(NetworkCard nic in NICs)
            {
                answer.AddRange(nic.NICRouteStrings(GW));
            }
            return answer;
        }
        public List<string> NICNames()
        {
            List<string> answer = new List<string>();
            string GW = DefaultGW.GetIP.ToIpString();
            foreach (NetworkCard nic in NICs)
            {
                answer.Add(nic.NicName());
            }
            return answer;
        }

        private NB_IPAddress IPFromTypeNic(NicType What)
        {
            foreach(NetworkCard nic in NB.Randomize(NICs).ToList())
            {
                if(nic.GetNicType == What)
                {
                    foreach(NB_IPAddress ip in nic.IPAddressList())
                    {
                        if (ip.GetIPString != NB.ZeroIPString && ip.GetIPString != NB.LoopbackIPString)
                            return ip;
                    }
                }
            }
            return null;
        }

        public NB_IPAddress BestIPForThis(NetworkDevice Source=null)
        {
            NB_IPAddress answer=null;
            if(Source != null)
            {
                answer = LocalDeviceIP(Source);
                if (answer != null && answer.GetIPString != NB.ZeroIPString)
                    return answer;
            }
            //If we have a WAN Nic, use that first
            answer = IPFromTypeNic(NicType.wan);
            if (answer != null)
                return answer;
            answer = IPFromTypeNic(NicType.management_interface);
            if (answer != null)
                return answer;
            //Otherwise, choose an eth nic
            answer = IPFromTypeNic(NicType.eth);
            if (answer != null)
                return answer;
            //Otherwise, choose an wireless nic
            answer = IPFromTypeNic(NicType.wlan);
            if (answer != null)
                return answer;
            return null;
        }

        public List<string> DeviceRouteStrings()
        {
            List<string> answer = new List<string>();
            foreach (NB_IPAddress ip in RouteTable)
            {
                answer.Add(ip.IPFormat());
            }
            return answer;
        }
        public void AddRoute(NB_IPAddress route)
        {
            RouteTable.Add(route);
        }
        public List<NB_IPAddress> ListRoutes()
        {
            return RouteTable;
        }

        public void EditRoute(int index, Form ParentForm)
        {
            if (index < 0) return;
            if (index >= RouteTable.Count) return;
            RouteTable[index].Edit(this, ParentForm);
        }
        public void DeleteRoute(int index)
        {
            if (index < 0) return;
            if (index >= RouteTable.Count) return;
            RouteTable.RemoveAt(index);
        }
        public override void DoInput(Packet tPacket)
        {

        }

        public void DoInputFromLink(Packet tPacket, HostNicID arrivalNic)
        {
            //We are entering into the computer
            NetworkCard nc = NicFromID(arrivalNic);
            //Say tell the packet that we are no longer on the link
            tPacket.WhereAmI = this;
            tPacket.MyStatus = PacketStatus.processing;
            //

            if(PowerOff)
            {
                //A packet came in, but the power was off on the device.
                tPacket.AddMessage(DebugLevel.info, NB.Translate("ND_DoInputFromLink_PowerOff"));
                tPacket.Tracking.Status = NB.LeftPad(hostname) + " " + string.Format(NB.Translate("ND_DoInputFromLink_PowerOff"));
                tPacket.MyStatus = PacketStatus.finished_failed;
                return;
            }

            tPacket.PacketDump(hostname, DebugPausePoint.packet_in);
            if(nc == null)
            {
                tPacket.AddMessage(DebugLevel.info, NB.Translate("ND_DoInputFromLink_CardFail1"));
                tPacket.Tracking.Status = NB.LeftPad(hostname) + " " + string.Format(NB.Translate("ND_DoInputFromLink_CardFail2"));
                tPacket.MyStatus = PacketStatus.finished_failed;
                return;
            }
            if(tPacket.MyType == PacketType.dhcp_answer)
                if(tPacket.destMAC == nc.MAC )
                {
                    //We have arrived back
                    tPacket.OutboundNic = nc;
                    ProcessArrival(tPacket);
                    return;
                }
            NetworkInterface nf = nc.LocalInterface(tPacket.sourceIP, tPacket.Tracking);

            if(nf == null)
            {
                nf = nc.LocalInterface(tPacket.TsourceIP, tPacket.Tracking);
            }
            if(nf == null)
            {
                nf = nc.PrimaryInterface();
            }

            if (nf == null && tPacket.MyType == PacketType.dhcp_request && isDHCPServer )
            {
                //It is a broadcast.  We need to figure out which nic it came in on
                //  And then, figure out which interface, so we know which IP to dole out
                NetworkInterface inif = nc.InterfaceFromVlanTag(tPacket);
                tPacket.InboundInterface = inif;

                List<NB_IPAddress> addresses = nc.IPAddressList();
                if (addresses.Count > 0)
                {
                    if (tPacket.TsourceIP == null) tPacket.TsourceIP = tPacket.sourceIP;                    
                    tPacket.OutboundIP = addresses[0];
                    tPacket.OutboundNic = nc;
                    tPacket.OutboundMAC = nc.MAC;
                    tPacket.WhereAmI = this;
                    ProcessArrival(tPacket);
                    return;
                }
            }

            if (!ForwardsPackets())
            {
                //Traceroute bounce-back
                if(tPacket.MyType == PacketType.tracert_request)
                {
                    if (ProcessTracertPacket(tPacket)) return; //the packet stops if it gets bounced.
                }

                if (tPacket.MyType == PacketType.dhcp_request && !isDHCPServer)
                {
                    tPacket.AddMessage(DebugLevel.debug, NB.LeftPad(hostname) + " " +string.Format(NB.Translate("ND_DoInFromLnkDeaf")));
                    tPacket.Tracking.Status = NB.LeftPad(hostname) + " " + string.Format(NB.Translate("ND_DoInFromLnkNoDHCP"));
                    tPacket.MyStatus = PacketStatus.finished_failed;
                    return;
                }
                if ((tPacket.MyType == PacketType.ping_answer || tPacket.MyType== PacketType.ping_request) && 
                    !RoutesPackets() && (!HasIPAddress(tPacket.destIP) && !HasBroadcastAddress(tPacket.destIP)))
                {
                    tPacket.AddMessage(DebugLevel.debug, NB.LeftPad(hostname) + " " +string.Format(NB.Translate("ND_NotRouter")));
                    tPacket.Tracking.Status = NB.LeftPad(hostname) + " " + string.Format(NB.Translate("ND_NotRouter2"));
                    tPacket.MyStatus = PacketStatus.finished_failed;
                    return;
                }
            }
            if(nf == null && myType != NetworkComponentType.net_switch && myType != NetworkComponentType.net_hub && 
                myType != NetworkComponentType.wbridge && myType != NetworkComponentType.wrepeater &&
                myType != NetworkComponentType.wrouter)
            {
                tPacket.AddMessage(DebugLevel.debug, NB.LeftPad(hostname) + string.Format(NB.Translate("ND_NoLocIP")));
                tPacket.Tracking.Status = NB.LeftPad(hostname) + " " + string.Format(NB.Translate("ND_NoLocIP2"));
                tPacket.MyStatus = PacketStatus.finished_failed;
                return;
            }

            //Now we pass it to the interface
            if (nf != null)
                nf.ProcessInboundPacket(tPacket);

            //Now we pass it to the nic
            if (nc != null)
                nc.ProcessInboundPacket(tPacket);
            //if (hostname != null)
            //    Console.WriteLine("Starting on device: " + hostname + "  VLANID = " + tPacket.VLANID.ToString());
            if(!tPacket.ready_to_delete)
               tPacket.StartOnDevice(this);
        }

        public bool ProcessTracertPacket(Packet tPacket)
        {
            tPacket.TTL--;
            //If it is a router, or this is the destination
            if (tPacket.TTL < 1 && (RoutesPackets() || HasMac(tPacket.destMAC)))
            {
                //The packet reached the end of its ttl.  Bounce back.
                //this packet ends, another begins.

                Network myNet = NB.GetNetwork();

                //There is a fringe case.  Do not bounce back if the target device is on the same LAN that this packet came in on
                //  Otherwise, the traceroute gets an odd reply.
                //  Do not do a tracert reply if the src and dest are local to each-other, and if this is not the device that is the endpoint
                bool LocalToEachOther = tPacket.sourceIP.IsLocal(new NB_IPAddress(tPacket.payloadData));
                if (LocalToEachOther && RoutesPackets() && !HasMac(tPacket.destMAC)) return false;

                //We create a new packet
                Packet nPacket = new Packet(this, tPacket.sourceIP, tPacket.payloadData, PacketType.tracert_reply, tPacket.packetID);
                nPacket.OrigTTL = tPacket.OrigTTL;
                nPacket.OriginalDestIP = tPacket.destIP;
                nPacket.isFresh = true; //So it starts from here
                nPacket.Tracking = new PacketMessage();

                //The original packet stops here
                tPacket.AddMessage(DebugLevel.info, NB.Translate("ND_ProcessArrival_TracerouteArrived") + " " + hostname);
                tPacket.Tracking.Status = NB.LeftPad(hostname) + " Traceroute: " + NB.Translate("ND_ProcessArrival_TracerouteArrived") + " " + hostname;
                tPacket.MyStatus = PacketStatus.finished_ok;
                //Console.WriteLine("  Tracert bounce: " + tPacket.OrigTTL + " " + hostname + " " + tPacket.payloadData);

                //Finish setting up the new packet - sending it back
                nPacket.sourceIP = new NB_IPAddress(NB.ZeroIPString);
                nPacket.TsourceIP = new NB_IPAddress(NB.ZeroIPString);
                myNet.addPacket(nPacket);
                //Console.WriteLine("  Tracert bounce pkt:" + nPacket.OrigTTL + nPacket.payloadData);
                return true;
            }
            return false;
        }

        /// <summary>
        /// Return true if this is a switch/hub/wap
        /// </summary>
        /// <returns></returns>
        public bool ForwardsPackets()
        {
            if (myType == NetworkComponentType.net_hub) return true;
            if (myType == NetworkComponentType.net_switch) return true;
            if (myType == NetworkComponentType.wap) return true;
            if (myType == NetworkComponentType.wrouter) return true;
            if (myType == NetworkComponentType.wrepeater) return true;
            if (myType == NetworkComponentType.wbridge) return true;
            return false;
        }
        /// <summary>
        /// Return true if this device routes packets.  Router, firewall, etc.
        /// </summary>
        /// <returns></returns>
        public bool RoutesPackets()
        {
            if (myType == NetworkComponentType.router) return true;
            if (myType == NetworkComponentType.firewall) return true;
            if (myType == NetworkComponentType.wrouter) return true;
            return false;
        }
        public bool IsNotNetDevice()
        {
            if (GetNetType() == NetworkComponentType.fluorescent)
                return false;
            if (GetNetType() == NetworkComponentType.microwave)
                return false;
            return true;
        }

        public override void DoOutput(Packet tPacket)
        {

        }

        public string ArpFromIP(string IPAddress)
        {
            foreach(ArpEntry arp in ArpTable)
            {
                if (arp.IPAddr == IPAddress)
                    return arp.MACAddress;
            }
            return "";
        }

        public string IPFromArp(string MAC)
        {
            foreach (ArpEntry arp in ArpTable)
            {
                if (arp.MACAddress == MAC)
                    return arp.IPAddr;
            }
            return "";
        }

        public HostNicID NicIDFromArp(string MAC)
        {
            foreach (ArpEntry arp in ArpTable)
            {
                if (arp.MACAddress == MAC)
                    return arp.NicOnWhichItIsFound;
            }
            return new HostNicID(-1,-1,"","");
        }
        public HostNicID NicIDFromIP(string IP)
        {
            foreach (ArpEntry arp in ArpTable)
            {
                if (arp.IPAddr == IP)
                    return arp.NicOnWhichItIsFound;
            }
            return new HostNicID(-1, -1, "", "");
        }


        public string LookupArpFromIP(string IPAddress)
        {
            string arp = ArpFromIP(IPAddress);
            if (arp == "")
            {
                Network mynet = NB.GetNetwork();
                if (mynet != null)
                {
                    List<string> arps = mynet.arp(IPAddress.ParseIp());
                    if (arps.Count > 0)
                    {
                        return arps[0];
                    }
                }
            }

            return arp;
        }

        public string ArpFromIP(NB_IPAddress IPAddress)
        {
            return ArpFromIP(IPAddress.GetIP.ToIpString());
        }

        public void StoreArp(string mac, string ip, HostNicID NicID)
        {
            ArpEntry AE = new ArpEntry(mac, ip, NicID);
            string found = ArpFromIP(ip);
            if (found == "")
            {
                ArpTable.Add(AE);
            }
            if(IPFromArp(mac) != ip && ip != NB.ZeroIPString)
            {
                foreach (ArpEntry arp in ArpTable.ToList())
                {
                    if (arp.MACAddress == mac)
                    {
                        ArpTable.Remove(arp);
                    }
                }
                ArpTable.Add(AE);
            }
        }

        public void ChangeColor(Color ColorTo)
        {
            MorphColor = ColorTo;
        }

        public List<ArpEntry> GetArps()
        {
            return ArpTable;
        }
        public void ClearArps()
        {
            ArpTable.Clear();
        }

        /// <summary>
        /// Clear out all the IP addresses and VLANs on the device
        /// </summary>
        public void ClearIPs()
        {
            ClearArps();
            RouteTable.Clear();
            DefaultGW = new NB_IPAddress(NB.ZeroIPString);
            foreach(NetworkCard nic in NICs)
            {
                nic.ClearIPs(); //Clear IPs and reset all vlans.
            }
        }

        /********************************************
         *      DHCP Stuff
         ********************************************/
        public void CheckDHCPRangesAgainstInterfaces()
        {
            bool found = false;
            List<NB_IPAddress> theInterfaces = IPAddressList();
            foreach(NB_IPAddress dhcpIP in DHCPRanges.ToList())
            {
                found = false;
                foreach (NB_IPAddress interfaceIP in theInterfaces)
                {
                    if(interfaceIP.GetIP == dhcpIP.GetIP)
                    {
                        found = true;
                        break;
                    }
                }
                if(!found)
                {
                    DHCPRanges.Remove(dhcpIP);
                }
            }
            foreach (NB_IPAddress interfaceIP in theInterfaces)
            {
                found = false;
                foreach (NB_IPAddress dhcpIP in DHCPRanges)
                {
                    if (interfaceIP.GetIP == dhcpIP.GetIP)
                    {
                        found = true;
                        break;
                    }
                }
                if (!found)
                {
                    DHCPRanges.Add(new NB_IPAddress(interfaceIP.GetIP.ToIpString(),NB.ZeroIPString,NB.ZeroIPString));
                }
            }
        }

        public List<string> DHCPStrings(bool WithAdditionalInfo=true)
        {
            List<string> theStrings = new List<string>();
            foreach(NB_IPAddress ip in DHCPRanges)
            {
                if (ip.GetIP.ToIpString() != "127.0.0.1")
                {
                    if (WithAdditionalInfo)
                    {
                        theStrings.Add(string.Format(NB.Translate("ND_DHCPStrIFStr"), ip.GetIP.ToIpString().PadLeft(15),
                            ip.GetMask.ToIpString(),ip.GetGateway.ToIpString()));
                    }
                    else
                    {
                        theStrings.Add(ip.GetIP.ToIpString());
                    }
                }
            }
            return theStrings;
        }

        public NB_IPAddress DHCPRangeMatchingInterface(NB_IPAddress InterfaceIP)
        {
            if (InterfaceIP == null) return null;
            foreach (NB_IPAddress ip in DHCPRanges)
            {
                if (ip.GetIP.ToIpString() != "127.0.0.1" && InterfaceIP.IsLocal(ip))
                    return ip;
            }
            return null;
        }
        public void EditDHCP(int index, Form ParentForm)
        {
            if (index > DHCPRanges.Count) return;
            if (index < 0) return;
            bool found = false;
            NB_IPAddress ifIP = null;
            List<NB_IPAddress> theInterfaces = IPAddressList();
            foreach (NB_IPAddress interfaceIP in theInterfaces)
            {
                if(interfaceIP.GetIP == DHCPRanges[index].GetIP)
                {
                    ifIP = interfaceIP;
                    found = true;
                }
            }
            if (!found) return;
            DHCPRanges[index].Edit(this, ifIP, ParentForm); //We need to pass the interface that is local to this
            DHCPLeases.Clear();
        }

        public NB_IPAddress LookupDHCPLease(string MAC, NB_IPAddress NIC_IP)
        {
            NB_IPAddress gateway;
            NetworkComponentType NCT = myType;
            if(myType == NetworkComponentType.wrouter)
            {
                //If we are a wireless router, we could be set up as an access point, or as a router/firewall
                //If the default gateway is on the LAN, we use the gateway.  If the default gateway is on the WAN,
                //We use the IP of the firewall IP. (NIC_IP)
                NB_IPAddress tGateway = GetGateway();
                NetworkCard lNic = LocalNic(tGateway);
                if(lNic != null && lNic.GetNicType == NicType.wan)
                {
                    //The gateway is on the WAN.  We will give it our own IP as if we are a firewall
                    NCT = NetworkComponentType.firewall;
                }
                else
                {
                    //The gateway is on the LAN.  We pretend we are an Access Point.
                    NCT = NetworkComponentType.wap;
                }
            }
            if (NCT != NetworkComponentType.firewall)
            {
                gateway = GetGateway();
            }
            else
            {
                gateway = NIC_IP; //Return the firewall IP that it came in on
            }
            foreach(ArpEntry dhcp in DHCPLeases)
            {

                if (dhcp.MACAddress == MAC && dhcp.IPAddr != NB.ZeroIPString && NIC_IP != null && gateway != null)
                {
                    NB_IPAddress addr = new NB_IPAddress(dhcp.IPAddr, NIC_IP.GetMask.ToIpString(), gateway.GetIP.ToIpString());
                    if (addr.IsLocal(NIC_IP))
                        return addr;
                }
            }
            return null;
        }

        public bool IPAlreadyUsed(string IP)
        {
            foreach (ArpEntry dhcp in DHCPLeases)
            {
                if (dhcp.IPAddr == IP)
                    return true;
            }
            return false;
        }

        public void MakeDHCPLease(string IP, string MAC)
        {
            ArpEntry me = new ArpEntry(MAC, IP, new HostNicID());
            DHCPLeases.Add(me);
        }

        /// <summary>
        /// Look up the MAC address and return the appropriate IP, or make a new IP.  Uses the interface IP of the server to know what range to use.
        /// </summary>
        /// <param name="MAC">The mac of the requesting machine</param>
        /// <param name="NIC_IP">the IP of the server nic</param>
        /// <returns>an IPAddress IP/Mask/GW</returns>
        public NB_IPAddress RequestDHCPLease(string MAC, NB_IPAddress NIC_IP)
        {
            if (NIC_IP == null)
                NIC_IP = HubManagementIP();
            NB_IPAddress tAddress = LookupDHCPLease(MAC, NIC_IP);
            if (tAddress != null && NIC_IP.IsLocal(tAddress))
                return tAddress;

            //if we are here, we need to find an address to give.
            bool stillOK = true;
            NB_IPAddress startaddress = DHCPRangeMatchingInterface(NIC_IP);
            if (startaddress == null) return null;
            UInt32 sIPNum = startaddress.GetMask;
            UInt32 eIPNum = startaddress.GetGateway;
            string ipstring;
            while(stillOK)
            {
                ipstring = sIPNum.ToIpString();
                tAddress = new NB_IPAddress(ipstring, NIC_IP.GetMask.ToIpString(),NB.ZeroIPString);
                if (!IPAlreadyUsed(ipstring))
                {
                    MakeDHCPLease(ipstring, MAC);
                    NB_IPAddress gateway = GetGateway();
                    //If the gateway is not local to the IP address we are giving out, give the IP of this device
                    if(!tAddress.IsLocal(gateway))
                    {
                        gateway = NIC_IP; //Return the firewall IP that it came in on
                    }
                    return new NB_IPAddress(ipstring,NIC_IP.GetMask.ToIpString(),gateway.GetIP.ToIpString());
                }
                sIPNum++;
                if(sIPNum > eIPNum)
                {
                    //We have used up all the range
                    stillOK = false;
                    break;
                }
            }
            return null; //If we get here, we are done for.  Nothing to give out
        }

        /// <summary>
        /// Return true if this device has at least one nic that can be configured from DHCP
        /// </summary>
        /// <returns>True if the device has a nic that can be configured with DHCP</returns>
        public bool HasDHCPNic()
        {
            foreach(NetworkCard card in NICs)
            {
                if (card.UsesDHCP)
                    return true;
            }
            return false;
        }

        /// <summary>
        /// Return true if this device has at least one nic that can be configured from DHCP
        /// </summary>
        /// <returns>True if the device has a nic that can be configured with DHCP</returns>
        public bool HasNonDHCPConnected()
        {
            foreach (NetworkCard card in NICs)
            {
                if (!card.UsesDHCP && card.ConnectedTo() != null)
                    return true;
            }
            return false;
        }

        public bool HasLocalNic(NB_IPAddress dest)
        {
            foreach(NetworkCard nic in NICs)
            {
                if (nic.HasLocalInterface(dest)) return true;
            }
            return false;
        }

        public bool FirewallAllows(string inIF, string outIF)
        {
            if (!HasAdvFirewall) return true;
            foreach(FirewallRule fwr in FirewallRules)
            {
                if(fwr.Source == inIF && fwr.Destination == outIF)
                {
                    if (fwr.Action == FirewallRuleType.Allow)
                        return true;
                    if (fwr.Action == FirewallRuleType.Drop)
                        return false;
                }
            }
            return true;
        }

        #region Break Things
        public bool BreakSSID(string nicname)
        {
            List<string> choices = new List<string>() { "FBI_Surveillance_Van", "EduNetworkBuilderSSID","Bad_SSID",
                "FreeWifi","HackMe","default","linksys",};
            //find the nic. Change the ssid on it
            choices.AddRange(new string[]{hostname+"_ssid", hostname+"FreeWireless", hostname+"AddHoc" });

            choices = NB.Randomize<string>(choices);
            string choice = choices[0]; //grab the first one

            NetworkCard nic = NicFromName(nicname);
            if (nic == null) return false; //we could not do it.
            if (nic.SSID == choice) return false;
            nic.SSID = choice; //change it
            return true;
        }

        public bool BreakWirelessKey(string nicname)
        {
            //find the nic. 
            NetworkCard nic = NicFromName(nicname);
            if (nic == null) return false; //we could not do it.

            List<string> choices = new List<string>() { "Key", "Llave","ChangeMe",
                "Password","key","default","admin",};
            choices.Add(nic.WirelessKey.ToUpper());
            choices.Add(nic.WirelessKey.ToLower());
            if (nic.WirelessKey.Length > 4)
                choices.Add(nic.WirelessKey.Substring(0, 2) + nic.WirelessKey.Substring(2, 1).ToUpper() + nic.WirelessKey.Substring(3));

            choices = NB.Randomize<string>(choices);
            string choice = choices[0]; //grab the first one

            if (nic.WirelessKey == choice) return false;
            nic.WirelessKey = choice; //change it
            return true;
        }

        public bool BreakVPNKey(string nicname)
        {
            //find the nic. 
            NetworkCard nic = NicFromName(nicname);
            if (nic == null) return false; //we could not do it.

            List<string> choices = new List<string>() { "Key", "Llave","ChangeMe",
                "Password","key","default","admin",};
            choices.Add(nic.EncryptionKey.ToUpper());
            choices.Add(nic.EncryptionKey.ToLower());
            if (nic.EncryptionKey.Length > 4)
                choices.Add(nic.EncryptionKey.Substring(0, 2) + nic.EncryptionKey.Substring(2, 1).ToUpper() + nic.EncryptionKey.Substring(3));

            choices = NB.Randomize<string>(choices);
            string choice = choices[0]; //grab the first one

            if (nic.WirelessKey == choice) return false;
            nic.WirelessKey = choice; //change it
            return true;
        }

        public bool BreakIPAddress(string nicname)
        {
            NetworkCard nic = NicFromName(nicname);
            if (nic == null) return false;
            NetworkInterface nif = nic.InterfaceFromName(nicname);
            if (nif == null) return false;
            NB_IPAddress newaddress = new NB_IPAddress("0.0.0.0");
            Random rnd = NB.GetRandom();

            switch(rnd.Next(8))
            {
                case 0:
                    newaddress = nif.myIP.BreakIPAddress32();
                    break;
                case 1:
                    newaddress = nif.myIP.BreakIPAddressMangle();
                    break;
                case 2:
                    newaddress = nif.myIP.BreakIPAddressRandom();
                    break;
                case 3:
                    newaddress = nif.myIP.BreakIPAddressZero();
                    break;
                case 4:
                    newaddress = nif.myIP.BreakIPNetmask32();
                    break;
                case 5:
                    newaddress = nif.myIP.BreakIPNetmaskMangle();
                    break;
                case 6:
                    newaddress = nif.myIP.BreakIPNetmaskRandom();
                    break;
                case 7:
                    newaddress = nif.myIP.BreakIPNetmaskZero();
                    break;
            }
            if(nif.myIP != newaddress)
            {
                nif.myIP = newaddress;
                return true;
            }
            return false;
        }

        public bool BreakGateway()
        {
            NB_IPAddress newaddress = new NB_IPAddress("0.0.0.0");
            Random rnd = NB.GetRandom();

            switch (rnd.Next(8))
            {
                case 0:
                    newaddress = DefaultGW.BreakIPAddress32();
                    break;
                case 1:
                    newaddress = DefaultGW.BreakIPAddressMangle();
                    break;
                case 2:
                    newaddress = DefaultGW.BreakIPAddressRandom();
                    break;
                case 3:
                    newaddress = DefaultGW.BreakIPAddressZero();
                    break;
            }
            if (DefaultGW != newaddress)
            {
                DefaultGW = newaddress;
                return true;
            }
            return false;
        }

        #endregion
    }
}
