using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Xml;
using System.Text.RegularExpressions;
using System.Globalization;
using System.Resources;
using System.Threading;

namespace EduNetworkBuilder
{
    public partial class BuilderWindow : Form
    {
        public Random GameRandomGen = new Random();
        public NBSettings OurSettings = new NBSettings(NB.IsRunningOnMono()); //This will auto-load the settings

        private int LastPacketID = 1;
        public DebugPausePoint DebugSetting = DebugPausePoint.none;
        //        public DebugPausePoint DebugSetting = DebugPausePoint.all | DebugPausePoint.dump;
        public Network myNetwork = new Network("");
        private Network InvisibleNetwork = null;
        private Network OrigNetworkAfterLoad = null;
        private List<Control> Buttons = new List<Control>();
        private string selectedButton = "";
        ToolTip myTooltip = new ToolTip();
        private NetworkDevice MouseHoverOver = null;
        private Point ClickedLocation;
        private Point ClickedImageLocation;
        DateTime LastClick = DateTime.Now;
        DateTime LastMouseDown = DateTime.Now;
        private string LastPath = "";
        private bool processing = false;
        private List<PuzzleInfo> PuzzleList = new List<PuzzleInfo>();
        private ResourceManager LanguageResources = null;
        private CultureInfo LanguageCulture = null;
        public string ChosenLanguage = "en";  //The language to try to load  
        private List<Control> HelpTopicButtons = new List<Control>();
        private System.Windows.Forms.Timer myTimer = new System.Windows.Forms.Timer();
        public bool NeedsUpdate = false; //Do we do an update next tick

        //For mouse-move / dragging
        public DateTime LastMoveTime = DateTime.UtcNow;
        public bool MouseIsDown = false; //For tracking if we are dragging something
        public Image LastBackgroundImage = null;
        public Point LastMouseMovePos = new Point(-1, -1);
        private NetworkDevice ItemClickedOn = null;
        private List<NetworkDevice> ItemsSelected = new List<NetworkDevice>();
        private Point OrigClickPoint = new Point(-1, -1);

        private NetShapeType CurrentShape = NetShapeType.none;
        private NetShape ShapeForEditing = null;

        private string InitialFileLoad = "";

        public PersonClass CurrentUser;

        private List<HelpURL> HelpURLs = new List<HelpURL>();
        private List<Network> storedNetworkStates = new List<Network>(); //for ctrl-z going back in time to past state
        private List<Network> ForwardstoredNetworkStates = new List<Network>(); //for ctrl-y going forward to a ctrl-y state

        public BuilderWindow(string FirstArg = "")
        {
            InitializeComponent();

            InitialFileLoad = FirstArg;

            LastPath = OurSettings.LastPath;

            HelpURLs = NB.LoadObjectFromXmlFile<List<HelpURL>>("URLs");

            if (!OurSettings.LanguageHasBeenChosen)
                NB.ChangeLanguage(OurSettings);
            LanguagifyComponents();
            //I never implimented cut/copy/paste/undo.  So we will remove them since they do nothing anyway
            cutToolStripMenuItem.Visible = false;
            copyToolStripMenuItem.Visible = false;
            pasteToolStripMenuItem.Visible = false;
            undoToolStripMenuItem.Visible = false;
            forgetReplayStatusesToolStripMenuItem.Visible = false;

            myTooltip.AutoPopDelay = 5000;
            myTooltip.InitialDelay = 1000;
            myTooltip.ReshowDelay = 500;
            // Force the ToolTip text to be displayed whether or not the form is active.
            myTooltip.ShowAlways = true;

            myTooltip.SetToolTip(rbHelp1, NB.Translate("NB_BuildWindNone", OurSettings));
            myTooltip.SetToolTip(rbHelp2, NB.Translate("NB_BuildWindColor", OurSettings));
            myTooltip.SetToolTip(rbHelp3, NB.Translate("NB_BuildWindMinor", OurSettings));
            myTooltip.SetToolTip(rbHelp4, NB.Translate("NB_BuildWindDecent", OurSettings));
            myTooltip.SetToolTip(btnHelp, NB.Translate("NB_BuildWindMsg", OurSettings));
            myTooltip.SetToolTip(btnCaptions, NB.Translate("NB_btnCaptions", OurSettings));
            myTooltip.SetToolTip(cbFillColor, NB.Translate("NB_cbFillColor", OurSettings));
            myTooltip.SetToolTip(cbLineColor, NB.Translate("NB_cbLineColor", OurSettings));
            myTooltip.Popup += myTooltip_Popup;
            lblStatus.Text = "";

            myNetwork.RegisterDisplayArea(pbNetworkView);


            List<String> ColorNames = myNetwork.ColorNames;
            ColorNames.Sort();
            cbFillColor.Items.Clear();
            cbLineColor.Items.Clear();
            foreach (string ColorName in ColorNames)
            {
                cbFillColor.Items.Add(ColorName);
                cbLineColor.Items.Add(ColorName);
            }
            cbFillColor.Text = "Empty";
            cbLineColor.Text = "Empty";

            BuildButtons();
            LayoutButtons();
            UpdateForm();
            this.KeyPreview = true;
            this.KeyUp += GenericKeyDown;

            myTimer.Interval = 15;
            myTimer.Tick += Tick;
            myTimer.Start();

            //Set this so we can intercept the esc key.  We want to un-set the selected items if esc is pressed
            KeyPreview = true;
            CreateSolvedUnsolvedToolstripItems();

            LoadPuzzleInfo();
        }

        private void Tick(object sender, EventArgs e)
        {
            if (NeedsUpdate)
            {
                UpdateVisuals();
                NeedsUpdate = false;
            }
            myNetwork.Tick(false);
        }

        private void LanguagifyComponents()
        {
            msMainMenuStrip.Text = NB.Translate("NB_msMainMenuStrip", OurSettings);
            fileToolStripMenuItem.Text = NB.Translate("NB_fileToolStripMenuItem", OurSettings);
            newToolStripMenuItem.Text = NB.Translate("LBW_btnAdd", OurSettings);
            loadToolStripMenuItem.Text = NB.Translate("_Load", OurSettings);
            reloadToolStripMenuItem.Text = NB.Translate("NB_reloadToolStripMenuItem", OurSettings);
            saveToolStripMenuItem.Text = NB.Translate("NB_saveToolStripMenuItem", OurSettings);
            exitToolStripMenuItem.Text = NB.Translate("NB_exitToolStripMenuItem", OurSettings);
            editToolStripMenuItem.Text = NB.Translate("_Edit", OurSettings);
            cutToolStripMenuItem.Text = NB.Translate("NB_cutToolStripMenuItem", OurSettings);
            copyToolStripMenuItem.Text = NB.Translate("NB_copyToolStripMenuItem", OurSettings);
            pasteToolStripMenuItem.Text = NB.Translate("NB_pasteToolStripMenuItem", OurSettings);
            undoToolStripMenuItem.Text = NB.Translate("NB_undoToolStripMenuItem", OurSettings);
            optionsToolStripMenuItem.Text = NB.Translate("NB_optionsToolStripMenuItem", OurSettings);
            classSetupToolStripMenuItem.Text = NB.Translate("NB_ClassSetup", OurSettings);
            allToolStripMenuItem.Text = NB.Translate("_All", OurSettings);
            dHCPRequestToolStripMenuItem.Text = NB.Translate("NB_NetViewDHCP", OurSettings);
            clearArpTableToolStripMenuItem.Text = NB.Translate("NB_NetViewClr", OurSettings);
            clearIPsToolStripMenuItem.Text = NB.Translate("NB_clearIPsToolStripMenuItem", OurSettings);
            pingToolStripMenuItem.Text = NB.Translate("_Ping", OurSettings);
            helpToolStripMenuItem.Text = NB.Translate("_Help", OurSettings);
            helpToolStripMenuItem1.Text = NB.Translate("_Help", OurSettings);
            aboutToolStripMenuItem.Text = NB.Translate("NB_aboutToolStripMenuItem", OurSettings);
            releaseNotesToolStripMenuItem.Text = NB.Translate("NB_releaseNotesToolStripMenuItem", OurSettings);
            checkForUpdatesToolStripMenuItem.Text = NB.Translate("NB_checkForUpdatesToolStripMenuItem", OurSettings);
            samplesToolStripMenuItem.Text = NB.Translate("NB_samplesToolStripMenuItem", OurSettings);
            puzzlesToolStripMenuItem.Text = NB.Translate("NB_puzzlesToolStripMenuItem", OurSettings);
            solvedToolStripMenuItem.Text = NB.Translate("_Solved", OurSettings);
            toSolveToolStripMenuItem.Text = NB.Translate("NB_toSolveToolStripMenuItem", OurSettings);
            lblStatus.Text = NB.Translate("NB_lblStatus", OurSettings);
            btnHelp.Text = NB.Translate("NB_btnHelp", OurSettings);
            addToClassworkToolStripMenuItem.Text = NB.Translate("NB_AddToClasswork");
            changeLanguageToolStripMenuItem.Text = NB.Translate("NB_changeLanguageToolStripMenuItem", OurSettings);
            submitHomeworkToolStripMenuItem.Text = NB.Translate("NB_SubmitClasswork");
            updateClassworkToolStripMenuItem.Text = NB.Translate("NB_UpdateClasswork");
            markAsGradedToolStripMenuItem.Text = NB.Translate("NB_MarkGraded");

            Text = NB.Translate("NB_Form", OurSettings);
        }

        public ResourceManager GetResource()
        {
            if (LanguageResources == null)
            {
                System.Reflection.Assembly MyAssembly;
                MyAssembly = this.GetType().Assembly;
                LanguageResources = new ResourceManager("EduNetworkBuilder.Resources.languages.edustrings", MyAssembly);
            }
            return LanguageResources;
        }

        public CultureInfo GetCulture()
        {
            if (LanguageCulture == null)
            {
                string CL = OurSettings.ChosenLanguage;
                if (CL != ChosenLanguage) ChosenLanguage = CL;
                LanguageCulture = CultureInfo.CreateSpecificCulture(ChosenLanguage);
            }
            return LanguageCulture;
        }

        /// <summary>
        /// Look up a translate key from the resx file.
        /// </summary>
        /// <param name="Key">The string to look up</param>
        /// <returns>The translated string</returns>
        public string Translate(string Key)
        {
            ResourceManager RM = GetResource();
            CultureInfo CI = GetCulture();
            string answer;
            answer = RM.GetString(Key, CI);
            if (answer == null) return "";
            return answer;
        }

        private void GenericKeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Delete)
            {
                pbNetworkView_Delete_Click(sender, e);
                ItemClickedOn = null;
            }
            if (e.KeyCode == Keys.S && e.Modifiers == Keys.Control)
            {
                doSave(true);
            }
            if (e.KeyCode == Keys.Z && e.Modifiers == Keys.Control)
            {
                if (storedNetworkStates.Count > 0)
                {
                    ForwardstoredNetworkStates.Insert(0, myNetwork);//So we can ctrl-y to this state.  Undo the undo
                    ChangeToPastState(storedNetworkStates[0]);
                    storedNetworkStates.RemoveAt(0);
                }
            }
            if (e.KeyCode == Keys.Y && e.Modifiers == Keys.Control)
            {
                if (ForwardstoredNetworkStates.Count > 0)
                {
                    storedNetworkStates.Insert(0, myNetwork);
                    ChangeToPastState(ForwardstoredNetworkStates[0]);
                    ForwardstoredNetworkStates.RemoveAt(0);
                }
            }
            //MessageBox.Show(e.KeyCode.ToString());
        }

        public void StoreNetworkState(Network toStore)
        {
            if (storedNetworkStates.Count > 0 && toStore.Equals(storedNetworkStates[0]))
                return; //The states are identical.  Do not store this state.
            storedNetworkStates.Insert(0, Network.DeepClone(toStore));
            ForwardstoredNetworkStates.Clear();
            int maxCount = 30;
            if (storedNetworkStates.Count > maxCount)
            {
                storedNetworkStates.RemoveRange(maxCount, storedNetworkStates.Count - maxCount);
            }
        }

        /// <summary>
        /// We do this every time we load a new network or create a network from scratch
        /// </summary>
        public void ClearStoredNetworkStates()
        {
            storedNetworkStates.Clear();
            ForwardstoredNetworkStates.Clear();
        }

        /// <summary>
        /// Store the new state after a change has been made.
        /// Do this before every change (add, delete, move)
        /// </summary>
        public void ProcessChange()
        {
            StoreNetworkState(myNetwork);
        }

        public void ChangeToPastState(Network OldNet)
        {
            if (OldNet != null)
            {
                myNetwork = OldNet;
                myNetwork.RegisterDisplayArea(pbNetworkView);
                UpdateMenu();
                UpdateForm();
            }
        }


        /// <summary>
        /// Return the control with the given name.  Used primarily to color help buttons
        /// </summary>
        /// <param name="Name">The name of the control to search for</param>
        /// <returns>The control, or null if no control is found</returns>
        public Control GetControlNamed(string Name)
        {
            Control[] tList = Controls.Find(Name, true);
            if (tList.Count() > 0) return tList[0]; //return the first one
            return null; //return nothing
        }

        private void UpdateHelpTopicButtons()
        {
            Button tButton;
            this.SuspendLayout();
            foreach (Control tCont in HelpTopicButtons)
            {
                tCont.Click -= btnRead_Click;
                Controls.Remove(tCont); //remove them all
                HelpPanel.Controls.Remove(tCont); //Remove from the panel
                tCont.Dispose();
            }
            HelpTopicButtons.Clear(); //They are all gone.

            //Make a bunch of new buttons.
            int count = 0;
            int offset = btnHelp.Height + 3;
            if (myNetwork.NetURL.GetText() != "")
            {
                tButton = new Button();
                tButton.Location = new Point(btnHelp.Location.X, rbHelp1.Location.Y + rbHelp1.Height + 5 + (offset * count));
                //tButton.Text = (count + 1).ToString();
                tButton.BackgroundImage = Properties.Resources.VidImage;
                tButton.BackgroundImageLayout = ImageLayout.Stretch;
                tButton.Width = btnHelp.Width;
                tButton.Height = btnHelp.Height;
                tButton.Click += btnRead_Click;
                tButton.Name = myNetwork.PuzzleName + "_URL";
                tButton.Tag = myNetwork.NetURL.GetText();
                HelpPanel.Controls.Add(tButton);
                myTooltip.SetToolTip(tButton, NB.Translate("_OpenURL") + " " + myNetwork.PuzzleName);
                HelpTopicButtons.Add(tButton);
                count++;
            }
            foreach (HelpTopics HT in myNetwork.SuggestedReadings)
            {
                tButton = new Button();
                string URL = URLFromHelpTopic(HT);
                tButton.Location = new Point(btnHelp.Location.X, rbHelp1.Location.Y + rbHelp1.Height + 5 + (offset * count));
                tButton.Text = (count + 1).ToString();
                tButton.Width = btnHelp.Width;
                tButton.Height = btnHelp.Height;
                tButton.Click += btnRead_Click;
                tButton.Name = HT.ToString();
                if (URL != "")
                {
                    //We have a URL for this.
                    tButton.BackgroundImage = Properties.Resources.VidImage;
                    tButton.BackgroundImageLayout = ImageLayout.Stretch;
                    tButton.Tag = URL;
                    tButton.ForeColor = Color.White;
                }
                HelpPanel.Controls.Add(tButton);
                string ttip = NB.Translate("_ReadContext") + " " + NB.Translate(NB.GetHelpTopicTitle(HT));
                if (URL != "")
                    ttip += "\n" + NB.Translate("_HasURL");
                myTooltip.SetToolTip(tButton, ttip);
                HelpTopicButtons.Add(tButton);
                count++;
            }
            foreach (NetTest nt in myNetwork.NetTests)
            {
                if (nt.TheTest == NetTestType.ReadContextHelp)
                {
                    nt.ColorItemsIfNeeded(true);
                }
            }
            this.ResumeLayout();
        }

        string URLFromHelpTopic(HelpTopics what, string lang = "")
        {
            string topic = what.ToString();
            if (lang == "") lang = ChosenLanguage;
            foreach (HelpURL one in HelpURLs)
            {
                if (one.HelpTopicString == topic && one.LangTag == lang)
                {
                    return one.URL;
                }
            }
            return "";
        }

        /// <summary>
        /// Called by the context_read clicks
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnRead_Click(object sender, EventArgs e)
        {
            Button me = (Button)sender;
            bool isURL = false;
            isURL = Regex.IsMatch(me.Name, "_URL$");
            if (!isURL)
            {
                HelpTopics HT = NB.TryParseEnum<HelpTopics>(me.Name, HelpTopics.None);
                if (HT != HelpTopics.None)
                {
                    if (ModifierKeys == Keys.Control && me.Tag != null)
                    {
                        //It should be a video URL
                        string URL = (string)me.Tag;
                        NB.OpenURLInExternalBrowser(URL);
                    }
                    else
                    {
                        myNetwork.NoteActionDone(NetTestType.ReadContextHelp, me.Name, NB.Translate("_Read"));
                        NB.ReadContextHelp(HT);
                    }
                }
                UpdateHelpTopicButtons();
                UpdateForm();
                UpdateMenu();
                myNetwork.TestForCompletion(true);
            }
            else
            {
                if (me.Tag != null)
                {
                    //It should be a video URL
                    string URL = (string)me.Tag;
                    NB.OpenURLInExternalBrowser(URL);
                }
            }
        }



        private void myTooltip_Popup(Object sender, PopupEventArgs e)
        {
            //In case we have a puzzle we are trying to solve
            if (MouseHoverOver == null) return;
            bool didsomething = myNetwork.NoteActionDone(NetTestType.HelpRequest, MouseHoverOver.hostname, myNetwork.HintsToDisplay.ToString());
            if (didsomething)
            {
                UpdateVisuals();
                myNetwork.TestForCompletion(true);
            }
        }
        private void BuildButton(string btnName, Image btnImage, string tooltipString)
        {
            int size = panelChoices.Width / 2;

            Button tButton;
            tButton = new Button();
            tButton.Name = btnName;
            tButton.BackgroundImage = new Bitmap(btnImage);
            tButton.BackgroundImageLayout = ImageLayout.Zoom;
            tButton.Click += btnClick;
            tButton.Height = size;
            tButton.Width = size;
            tButton.Location = new Point(0, 0);
            Buttons.Add(tButton);
            panelChoices.Controls.Add(tButton);
            myTooltip.SetToolTip(tButton, tooltipString);
        }

        private void BuildButtons()
        {
            BuildButton("btnSwitch", Properties.Resources.Switch, NB.Translate("NB_BuildBtnSwitch"));
            BuildButton("btnHub", Properties.Resources.Hub, NB.Translate("NB_BuildBtnHub"));
            BuildButton("btnServer", Properties.Resources.Server, NB.Translate("NB_BuildBtnServer"));
            BuildButton("btnLaptop", Properties.Resources.Laptop, NB.Translate("NB_BuildBtnLaptop"));
            BuildButton("btnPC", Properties.Resources.PC, NB.Translate("NB_BuildBtnPC"));
            BuildButton("btnRouter", Properties.Resources.Router, NB.Translate("NB_BuildBtnRouter"));
            BuildButton("btnIPPhone", Properties.Resources.ip_phone, NB.Translate("NB_BuildBtnPhone"));
            BuildButton("btnFirewall", Properties.Resources.firewall, NB.Translate("NB_BuildBtnFirewall"));
            BuildButton("btnPrinter", Properties.Resources.Printer, NB.Translate("NB_BuildBtnPrinter"));
            BuildButton("btnCopier", Properties.Resources.Copier, NB.Translate("NB_BuildBtnCopier"));
            BuildButton("btnMicrowave", Properties.Resources.microwave, NB.Translate("NB_BuildBtnMicrowave"));
            BuildButton("btnFluorescent", Properties.Resources.fluorescent, NB.Translate("NB_BuildBtnLight"));
            BuildButton("btnWAP", Properties.Resources.wap, NB.Translate("NB_BuildBtnWAP"));
            BuildButton("btnWRouter", Properties.Resources.WRouter, NB.Translate("NB_BuildBtnWRouter"));
            BuildButton("btnWBridge", Properties.Resources.WBridge, NB.Translate("NB_BuildBtnBridge"));
            BuildButton("btnWRepeater", Properties.Resources.WRepeater, NB.Translate("NB_BuildBtnRepeat"));
            BuildButton("btnCellphone", Properties.Resources.cellphone, NB.Translate("NB_BuildBtnCell"));
            BuildButton("btnTablet", Properties.Resources.tablet, NB.Translate("NB_BuildBtnTablet"));
            BuildButton("btnLink", Properties.Resources.link, NB.Translate("NB_BuildBtnCable"));
            BuildButton("btnTree", Properties.Resources.tree, NB.Translate("NB_BuildBtnTree"));
            BuildButton("btnShapes", Properties.Resources.Shapes, NB.Translate("NB_BuildBtnShapes"));
            BuildButton("btnSelect", Properties.Resources.select, NB.Translate("NB_BuildBtnSelect"));
        }

        private void LayoutButtons(List<string> what)
        {
            foreach (Button btn in Buttons)
            {
                btn.Visible = false; //Hide them all
            }
            //now we place them.
            int count = 0;
            int size = panelChoices.Width / 2;
            int x, y;
            foreach (Button btn in Buttons)
            {
                if (what.Contains(btn.Name))
                {
                    x = (count % 2) * size;
                    y = (count / 2) * size;
                    btn.Location = new Point(x, y);
                    btn.Visible = true;
                    count++;
                }

            }
        }

        public void UpdateMessages()
        {
            //redo this later
            lbMessages.Items.Clear();
            List<string> messages = myNetwork.GetMessageStrings();
            foreach (string msg in messages)
            {
                lbMessages.Items.Add(msg);
            }

            if (lbMessages.Items.Count > 0)
                lbMessages.SelectedIndex = lbMessages.Items.Count - 1;

        }

        public void UpdateMenu()
        {
            if (myNetwork.NetworkFilename != "" || OrigNetworkAfterLoad != null)
            {
                reloadToolStripMenuItem.Enabled = true;
            }
            else
            {
                reloadToolStripMenuItem.Enabled = false;
            }

            //If we already have a class setup
            if (CurrentUser == null)
            {
                classSetupToolStripMenuItem.Visible = true;
                profileToolStripMenuItem.Visible = false;
                logoutToolStripMenuItem.Visible = false;
                this.Text = NB.Translate("NB_Form", OurSettings); //From up above
            }
            else
            {
                logoutToolStripMenuItem.Visible = true;
                profileToolStripMenuItem.Visible = true;
                classSetupToolStripMenuItem.Visible = false;
                this.Text = NB.Translate("NB_Form", OurSettings) + " : " + CurrentUser.FullName;
            }
            if (CurrentUser == null || !CurrentUser.isAdmin)
            {
                addToClassworkToolStripMenuItem.Visible = false;
                submitHomeworkToolStripMenuItem.Visible = false;
                updateClassworkToolStripMenuItem.Visible = false;
            }
            markAsGradedToolStripMenuItem.Visible = false;
            if (CurrentUser != null)
            {
                if (CurrentUser.isAdmin)
                {
                    submitHomeworkToolStripMenuItem.Visible = false;
                    if (myNetwork.WhatFrom == null)
                    {
                        //If this is not part of homework yet, we can add it
                        addToClassworkToolStripMenuItem.Visible = true;
                        updateClassworkToolStripMenuItem.Visible = false;
                    }
                    else
                    {
                        if (!myNetwork.WhatFrom.IsSumbitted)
                        {
                            //If this is homework, we can update it
                            addToClassworkToolStripMenuItem.Visible = true;  //We can create a new homework if we have changed it
                            updateClassworkToolStripMenuItem.Visible = true;
                        }
                        else
                        {
                            markAsGradedToolStripMenuItem.Visible = true;
                        }
                    }
                }
                else if (myNetwork.WhatFrom != null) //we are a student doing homework
                    submitHomeworkToolStripMenuItem.Visible = true;
            }

            List<string> tLoadList = new List<string>();
            loadToolStripMenuItem.DropDownItems.Clear();
            if (OurSettings != null)
            {
                foreach (string one in OurSettings.GetRecentFiles())
                {
                    if (tLoadList.Contains(one)) continue;
                    string JustFile = Path.GetFileName(one);
                    int i = loadToolStripMenuItem.DropDownItems.Count;
                    loadToolStripMenuItem.DropDownItems.Add(JustFile, null, loadRecentFilename);
                    loadToolStripMenuItem.DropDownItems[i].Name = one;
                    tLoadList.Add(one);
                }
            }
        }

        public void UpdateLinks()
        {
            bool didanything = false;
            //Remove links if needed
            didanything = didanything || myNetwork.DoAllVerifyLinks();

            //now, update wireless links if we can.
            didanything = myNetwork.DoAllAutoJoin() || didanything;

            //If we have done anything, check for tests being completed
            if (didanything)
                myNetwork.TestForCompletion(true);
        }

        /// <summary>
        /// Basically updae everything.  Does UpdateMenu, UpdateMessages, UpdateVisuals and a few other things.
        /// </summary>
        public void UpdateForm()
        {
            UpdateMenu();
            UpdateMessages();
            UpdateVisuals();
            btnUpdateShape();
            if (selectedButton == "btnShapes")
            {
                cbFillColor.Visible = true;
                cbLineColor.Visible = true;
            }
            else
            {
                cbFillColor.Visible = false;
                cbLineColor.Visible = false;
            }
            if (myNetwork != null && myNetwork.LoadedFromResource)
                optionsToolStripMenuItem.Visible = false;
            else
                optionsToolStripMenuItem.Visible = true;
            processing = true;
            Text = NB.Translate("NB_UpdteFrmName", OurSettings);
            if (myNetwork.NetTitle.GetText() != "")
                Text += ": " + myNetwork.NetTitle.GetText();
            if (myNetwork.NetMessage.GetText() != "")
            {
                btnHelp.Visible = true;
            }
            else
            {
                btnHelp.Visible = false;
            }
            if (myNetwork.NetTests.Count > 0)
            {
                rbHelp1.Visible = true;
                rbHelp2.Visible = true;
                rbHelp3.Visible = true;
                rbHelp4.Visible = true;
            }
            else
            {
                rbHelp1.Visible = false;
                rbHelp2.Visible = false;
                rbHelp3.Visible = false;
                rbHelp4.Visible = false;
            }
            switch (myNetwork.HintsToDisplay)
            {
                case NetTestVerbosity.full:
                    rbHelp4.Checked = true;
                    break;
                case NetTestVerbosity.hints:
                    rbHelp3.Checked = true;
                    break;
                case NetTestVerbosity.basic:
                    rbHelp2.Checked = true;
                    break;
                case NetTestVerbosity.none:
                    rbHelp1.Checked = true;
                    break;
            }
            UpdateHelpTopicButtons();
            processing = false;
        }

        private void LayoutButtons()
        {
            List<string> what = new List<string>();
            foreach (Button btn in Buttons)
            {
                what.Add(btn.Name);
            }
            LayoutButtons(what);
        }


        private void LoadPuzzleInfo()
        {
            XmlDocument xmlDoc = new XmlDocument();
            System.Reflection.Assembly MyAssembly;
            System.String myString;
            MyAssembly = this.GetType().Assembly;
            PuzzleInfo newPuzzle;

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

            foreach (string str in Enum.GetNames(typeof(PuzzleNames)))
            {
                byte[] item = (byte[])myManager.GetObject(str);
                if (item == null)
                {
                    MessageBox.Show(String.Format(NB.Translate("NB_LoadPuzInfo"), str));
                    continue;
                }
                myString = new StreamReader(new MemoryStream(item), true).ReadToEnd();
                //myString = System.Text.Encoding.Default.GetString(item);
                xmlDoc.LoadXml(myString);
                newPuzzle = new PuzzleInfo();
                newPuzzle.Load(xmlDoc, str);
                PuzzleList.Add(newPuzzle);
                //Console.WriteLine("Puzzle: " + str + " " + newPuzzle.PuzzleTitle);
            }
            PuzzleList = PuzzleList.OrderBy(c => c.Level).ThenBy(c => c.SortOrder).ThenBy(c => c.PuzzleName).ToList();
        }

        public PuzzleInfo PuzzleInfoFromName(string PuzzleName)
        {
            foreach (PuzzleInfo pi in PuzzleList)
            {
                if (pi.PuzzleName == PuzzleName)
                    return pi;
            }
            return null;
        }

        public bool PuzzleLevelHasUnsolved(string LevelName)
        {

            foreach (PuzzleInfo pi in PuzzleList)
            {
                if ("Level_" + pi.Level.ToString() == LevelName)
                {
                    if (!OurSettings.CheckIfDone(pi.PuzzleName))
                    {
                        return true; //We have one puzzle in the level which has not been solved
                    }
                }
            }
            return false;
        }

        public int nextPacketID()
        {
            return LastPacketID++;
        }

        public List<string> GetPuzzleTags()
        {
            List<string> PuzzleTags = new List<string>();
            List<string> LevelTags = new List<string>();
            foreach (PuzzleInfo pi in PuzzleList)
            {
                foreach (string str in pi.PuzzleTags)
                {
                    //string What = NB.Translate("NB_Level");
                    string What = "^Level";
                    if (Regex.IsMatch(str, What))
                    {
                        if (!LevelTags.Contains(str, StringComparer.OrdinalIgnoreCase))
                            LevelTags.Add(str);
                    }
                    else
                    {
                        //if (!PuzzleTags.Contains(str, StringComparer.OrdinalIgnoreCase))
                        //    PuzzleTags.Add(str);
                    }
                }
            }
            PuzzleTags.Sort();
            LevelTags.Sort();
            LevelTags.AddRange(PuzzleTags);
            return LevelTags;
        }

        public List<string> GetPuzzleNames()
        {
            List<string> PuzzleNames = new List<string>();
            foreach (PuzzleInfo pi in PuzzleList)
            {
                PuzzleNames.Add(pi.PuzzleName);
            }
            return PuzzleNames;
        }

        private void btnClick(object sender, EventArgs e)
        {
            bool doupdate = false;
            if (selectedButton == "btnShapes") doupdate = true;
            foreach (Control btn in Buttons)
            {
                if (btn == sender)
                {
                    //This is the selected item
                    btn.BackColor = Color.LightGreen;
                    selectedButton = btn.Name;
                    lblStatus.Text = myTooltip.GetToolTip(btn);
                    myNetwork.InShapeEditMode = true;
                    if (selectedButton == "btnShapes")
                    {
                        myNetwork.InShapeEditMode = true;
                        if (CurrentShape == NetShapeType.none) CurrentShape = NetShapeType.rectangle;
                        if (doupdate)
                        {
                            //The shape was already selected.  Toggle it
                            if (CurrentShape == NetShapeType.rectangle) CurrentShape = NetShapeType.circle;
                            else CurrentShape = NetShapeType.rectangle;
                        }
                        if (CurrentShape == NetShapeType.rectangle) btn.BackgroundImage = Properties.Resources.Square;
                        if (CurrentShape == NetShapeType.circle) btn.BackgroundImage = Properties.Resources.Circle;
                        doupdate = true;
                    }
                    else
                    {
                        myNetwork.InShapeEditMode = false;
                        CurrentShape = NetShapeType.none;
                    }
                }
                else
                {
                    btn.BackColor = Button.DefaultBackColor;
                }
            }
            if (doupdate)
            {
                UpdateForm();
            }
        }

        private void btnReset()
        {
            foreach (Control btn in Buttons)
            {
                lblStatus.Text = "";
                selectedButton = "";
                CurrentShape = NetShapeType.none;
                btn.BackColor = Button.DefaultBackColor;
                if (btn.Name == "btnShapes")
                {
                    if (CurrentShape == NetShapeType.rectangle) btn.BackgroundImage = Properties.Resources.Square;
                    if (CurrentShape == NetShapeType.circle) btn.BackgroundImage = Properties.Resources.Circle;
                    if (CurrentShape == NetShapeType.none) btn.BackgroundImage = Properties.Resources.Shapes;
                }
            }
        }
        private void btnUpdateShape()
        {
            foreach (Control btn in Buttons)
            {
                if (btn.Name == "btnShapes")
                {
                    if (CurrentShape == NetShapeType.rectangle) btn.BackgroundImage = Properties.Resources.Square;
                    if (CurrentShape == NetShapeType.circle) btn.BackgroundImage = Properties.Resources.Circle;
                    if (CurrentShape == NetShapeType.none) btn.BackgroundImage = Properties.Resources.Shapes;
                }
            }
        }

        private void pbNetworkView_DoubleClick(object sender, EventArgs e)
        {

        }

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

        private void pbNetworkView_RightMouseUp(NetworkDevice ReleasedOn, MouseEventArgs e)
        {
            int index = 0;
            bool LockedOut = false;
            bool PoweredOff = false;
            if (pbNetworkView.ContextMenuStrip == null)
            {
                pbNetworkView.ContextMenuStrip = new ContextMenuStrip();
            }
            if (ReleasedOn != null) LockedOut = ReleasedOn.DeviceIsLockedOutByVLANs();
            if (ReleasedOn != null) PoweredOff = ReleasedOn.PowerOff;
            pbNetworkView.ContextMenuStrip.Items.Clear();

            if (myNetwork.InShapeEditMode && ShapeForEditing != null)
            {
                //context menu for shape
                pbNetworkView.ContextMenuStrip.Items.Add(NB.Translate("_Delete"));
                pbNetworkView.ContextMenuStrip.Items[index++].Click += pbNetworkView_DeleteShape_Click;

                pbNetworkView.ContextMenuStrip.Items.Add(NB.Translate("_Edit"));
                pbNetworkView.ContextMenuStrip.Items[index++].Click += pbNetworkView_EditShape_Click;
            }

            if (ItemsSelected.Count > 0)
            {
                //We do not want to do the normal menu...
                LockedOut = false;
                ReleasedOn = null;

                //We need to make sure the item is not critical before we delete it.
                pbNetworkView.ContextMenuStrip.Items.Add(NB.Translate("_Delete"));
                pbNetworkView.ContextMenuStrip.Items[index++].Click += pbNetworkView_Delete_Click;

                //We can color-code multiple items
                if (myNetwork.VLANsEnabled)
                {
                    int MenuIndex = pbNetworkView.ContextMenuStrip.Items.Count;
                    pbNetworkView.ContextMenuStrip.Items.Add(NB.Translate("NB_ColorStr"));
                    (pbNetworkView.ContextMenuStrip.Items[MenuIndex] as ToolStripMenuItem).DropDownItems.Add(NB.Translate("NB_Blue"), null, pbNetworkView_Color_Click);
                    (pbNetworkView.ContextMenuStrip.Items[MenuIndex] as ToolStripMenuItem).DropDownItems.Add(NB.Translate("NB_Purple"), null, pbNetworkView_Color_Click);
                    (pbNetworkView.ContextMenuStrip.Items[MenuIndex] as ToolStripMenuItem).DropDownItems.Add(NB.Translate("NB_Yellow"), null, pbNetworkView_Color_Click);
                    (pbNetworkView.ContextMenuStrip.Items[MenuIndex] as ToolStripMenuItem).DropDownItems.Add(NB.Translate("NB_Green"), null, pbNetworkView_Color_Click);
                    (pbNetworkView.ContextMenuStrip.Items[MenuIndex] as ToolStripMenuItem).DropDownItems.Add(NB.Translate("NB_Orange"), null, pbNetworkView_Color_Click);
                    (pbNetworkView.ContextMenuStrip.Items[MenuIndex] as ToolStripMenuItem).DropDownItems.Add(NB.Translate("NB_Cyan"), null, pbNetworkView_Color_Click);
                }
            }

            if (!LockedOut)
            {
                if (ReleasedOn != null && ReleasedOn.IsNotNetDevice() && !ReleasedOn.IsBurned)
                {
                    List<string> DoneList = new List<string>();
                    if (!PoweredOff && !ReleasedOn.isFrozen())
                    {
                        foreach (string tStr in myNetwork.GetIncompleteTestDestinations(ReleasedOn.hostname, ContextTest.ping))
                        {
                            if (!DoneList.Contains(tStr))
                            {
                                pbNetworkView.ContextMenuStrip.Items.Add(string.Format(NB.Translate("_PingStr"), tStr));
                                pbNetworkView.ContextMenuStrip.Items[index].Click += pbNetworkView_Ping_Name_Click;
                                pbNetworkView.ContextMenuStrip.Items[index++].Tag = tStr;
                                DoneList.Add(tStr);
                            }
                        }

                        DoneList.Clear();

                        foreach (string tStr in myNetwork.GetIncompleteTestDestinations(ReleasedOn.hostname, ContextTest.traceroute))
                        {
                            if (!DoneList.Contains(tStr))
                            {
                                pbNetworkView.ContextMenuStrip.Items.Add(string.Format(NB.Translate("_Traceroute") + " " + tStr));
                                pbNetworkView.ContextMenuStrip.Items[index].Click += pbNetworkView_Traceroute_Name_Click;
                                pbNetworkView.ContextMenuStrip.Items[index++].Tag = tStr;
                                DoneList.Add(tStr);
                            }
                        }
                        DoneList.Clear();
                        foreach (string tStr in myNetwork.GetIncompleteTestDestinations(ReleasedOn.hostname, ContextTest.arp))
                        {
                            if (!DoneList.Contains(tStr))
                            {
                                pbNetworkView.ContextMenuStrip.Items.Add(string.Format(NB.Translate("H_ARP_TitleStr"), tStr));
                                pbNetworkView.ContextMenuStrip.Items[index].Click += pbNetworkView_Arp_Name_Click;
                                pbNetworkView.ContextMenuStrip.Items[index++].Tag = tStr;
                                DoneList.Add(tStr);
                            }
                        }
                    }
                }
                if (ReleasedOn != null && ReleasedOn.IsNotNetDevice() && !ReleasedOn.IsBurned && !ReleasedOn.isFrozen())
                {
                    if (!PoweredOff)
                    {
                        pbNetworkView.ContextMenuStrip.Items.Add(NB.Translate("_Ping1"));
                        pbNetworkView.ContextMenuStrip.Items[index++].Click += pbNetworkView_Ping_Click;
                        pbNetworkView.ContextMenuStrip.Items.Add(NB.Translate("_Traceroute"));
                        pbNetworkView.ContextMenuStrip.Items[index++].Click += pbNetworkView_Traceroute_Click;
                        pbNetworkView.ContextMenuStrip.Items.Add(NB.Translate("H_ARP_Title"));
                        pbNetworkView.ContextMenuStrip.Items[index++].Click += pbNetworkView_Arp_Click;
                        pbNetworkView.ContextMenuStrip.Items.Add(NB.Translate("NB_NetViewClr"));
                        pbNetworkView.ContextMenuStrip.Items[index++].Click += pbNetworkView_ArpClear_Click;
                    }
                }
                if (ReleasedOn != null && !ReleasedOn.isFrozen())
                {
                    if (!myNetwork.ItemIsCritical(ReleasedOn.hostname))
                    {
                        pbNetworkView.ContextMenuStrip.Items.Add(NB.Translate("_Delete"));
                        pbNetworkView.ContextMenuStrip.Items[index++].Click += pbNetworkView_Delete_Click;
                    }
                }
                if (ReleasedOn != null && ReleasedOn.IsNotNetDevice() && !PoweredOff && !ReleasedOn.IsBurned && !ReleasedOn.isFrozen())
                {
                    pbNetworkView.ContextMenuStrip.Items.Add(NB.Translate("_Edit"));
                    pbNetworkView.ContextMenuStrip.Items[index++].Click += pbNetworkView_Edit_Click;
                }

                if (ReleasedOn != null)
                {
                    ItemClickedOn = ReleasedOn;
                    if (!PoweredOff && !ReleasedOn.IsBurned && !ReleasedOn.isFrozen())
                    {
                        if (ReleasedOn.HasDHCPNic())
                        {
                            pbNetworkView.ContextMenuStrip.Items.Add(NB.Translate("NB_NetViewDHCP"));
                            pbNetworkView.ContextMenuStrip.Items[index++].Click += pbNetworkView_DHCPRequest_Click;
                        }
                    }
                    foreach (string host in ReleasedOn.ListOfConnectedHosts())
                    {
                        pbNetworkView.ContextMenuStrip.Items.Add(string.Format(NB.Translate("NB_NetViewRmLnkStr"), host));
                        pbNetworkView.ContextMenuStrip.Items[index++].Click += pbNetworkView_RemoveLink_Click;
                    }
                    if (ReleasedOn.PowerOff)
                    {
                        pbNetworkView.ContextMenuStrip.Items.Add(NB.Translate("NB_PowerOn"));
                        pbNetworkView.ContextMenuStrip.Items[index++].Click += pbNetworkView_PowerOn_Click;
                    }
                    else if (ReleasedOn.ForwardsPackets() || ReleasedOn.RoutesPackets())
                    {
                        pbNetworkView.ContextMenuStrip.Items.Add(NB.Translate("NB_PowerOff"));
                        pbNetworkView.ContextMenuStrip.Items[index++].Click += pbNetworkView_PowerOff_Click;
                    }
                    if (myNetwork.ItemHasTest(ReleasedOn.hostname, NetTestType.DeviceBlowsUpWithPower) ||
                        myNetwork.ItemHasTest(ReleasedOn.hostname, NetTestType.DeviceNICSprays) ||
                        ReleasedOn.IsBurned)
                    {
                        bool toDo = false;
                        if (ReleasedOn.IsBurned) toDo = true;
                        if (myNetwork.ItemHasTest(ReleasedOn.hostname, NetTestType.DeviceBlowsUpWithPower))
                            toDo = !myNetwork.ItemTestIsComplete(ReleasedOn.hostname, NetTestType.DeviceBlowsUpWithPower);
                        if (myNetwork.ItemHasTest(ReleasedOn.hostname, NetTestType.DeviceNICSprays))
                        {
                            if (ReleasedOn.ForwardsPackets() && !myNetwork.ItemTestIsComplete(ReleasedOn.hostname, NetTestType.DeviceNICSprays))
                                toDo = true;  //with PCs and the like, we replace the individual nic
                        }
                        if (toDo)
                        {
                            //If the item is bad and has not been replaced, then add a context menu to replace it
                            pbNetworkView.ContextMenuStrip.Items.Add(NB.Translate("NB_Replace"));
                            pbNetworkView.ContextMenuStrip.Items[index++].Click += pbNetworkView_Replace_Click;
                        }
                    }
                    if (myNetwork.ItemHasTest(ReleasedOn.hostname, NetTestType.DeviceNeedsUPS))
                    {
                        if (!myNetwork.ItemTestIsComplete(ReleasedOn.hostname, NetTestType.DeviceNeedsUPS))
                        {
                            //If the item is bad and has not been replaced, then add a context menu to replace it
                            pbNetworkView.ContextMenuStrip.Items.Add(NB.Translate("NB_AddUPS"));
                            pbNetworkView.ContextMenuStrip.Items[index++].Click += pbNetworkView_AddUPS_Click;
                        }
                    }

                }
            }
            else //we are locked out.
            {
                pbNetworkView.ContextMenuStrip.Items.Add(string.Format(NB.Translate("NB_Reset")));
                pbNetworkView.ContextMenuStrip.Items[index++].Click += pbNetworkView_Reset_Click;
            }
            if (ReleasedOn != null && (Form.ModifierKeys & Keys.Control) == Keys.Control) //We control-click on it
            {
                int MenuIndex = pbNetworkView.ContextMenuStrip.Items.Count;
                pbNetworkView.ContextMenuStrip.Items.Add(NB.Translate("NB_Hide"));
                pbNetworkView.ContextMenuStrip.Items[index++].Click += pbNetworkView_Hide_Click;
            }
            if (ReleasedOn != null && myNetwork.VLANsEnabled)
            {
                int MenuIndex = pbNetworkView.ContextMenuStrip.Items.Count;
                pbNetworkView.ContextMenuStrip.Items.Add(NB.Translate("NB_ColorStr"));
                (pbNetworkView.ContextMenuStrip.Items[MenuIndex] as ToolStripMenuItem).DropDownItems.Add(NB.Translate("NB_Blue"), null, pbNetworkView_Color_Click);
                (pbNetworkView.ContextMenuStrip.Items[MenuIndex] as ToolStripMenuItem).DropDownItems.Add(NB.Translate("NB_Purple"), null, pbNetworkView_Color_Click);
                (pbNetworkView.ContextMenuStrip.Items[MenuIndex] as ToolStripMenuItem).DropDownItems.Add(NB.Translate("NB_Yellow"), null, pbNetworkView_Color_Click);
                (pbNetworkView.ContextMenuStrip.Items[MenuIndex] as ToolStripMenuItem).DropDownItems.Add(NB.Translate("NB_Green"), null, pbNetworkView_Color_Click);
                (pbNetworkView.ContextMenuStrip.Items[MenuIndex] as ToolStripMenuItem).DropDownItems.Add(NB.Translate("NB_Orange"), null, pbNetworkView_Color_Click);
                (pbNetworkView.ContextMenuStrip.Items[MenuIndex] as ToolStripMenuItem).DropDownItems.Add(NB.Translate("NB_Cyan"), null, pbNetworkView_Color_Click);
            }
            if ((!myNetwork.InShapeEditMode && ReleasedOn == null && ItemsSelected.Count == 0) || (myNetwork.InShapeEditMode && ShapeForEditing == null))
            {
                pbNetworkView.ContextMenuStrip.Visible = false;
            }
            else
            {
                pbNetworkView.ContextMenuStrip.Visible = true;
                pbNetworkView.ContextMenuStrip.Show(Cursor.Position);
            }
        }

        private void pbNetworkView_RightMouseUponLink(NetworkLink LinkReleasedOn, MouseEventArgs e)
        {
            if (LinkReleasedOn == null) return;
            if (pbNetworkView.ContextMenuStrip == null)
            {
                pbNetworkView.ContextMenuStrip = new ContextMenuStrip();
            }
            pbNetworkView.ContextMenuStrip.Items.Clear();

            int index = 0;

            //We need to make sure the item is not critical before we delete it.
            pbNetworkView.ContextMenuStrip.Items.Add(NB.Translate("_Delete"));
            pbNetworkView.ContextMenuStrip.Items[index].Tag = LinkReleasedOn;
            pbNetworkView.ContextMenuStrip.Items[index++].Click += pbNetworkView_RemoveNetLink_Click;

            if (LinkReleasedOn.theLinkType != LinkType.wireless)
            {
                pbNetworkView.ContextMenuStrip.Items.Add(NB.Translate("_Edit"));
                pbNetworkView.ContextMenuStrip.Items[index].Tag = LinkReleasedOn;
                pbNetworkView.ContextMenuStrip.Items[index++].Click += pbNetworkView_EditNetLink_Click;

                if (LinkReleasedOn.theLinkType == LinkType.broken)
                {
                    pbNetworkView.ContextMenuStrip.Items.Add(NB.Translate("NB_Replace"));
                    pbNetworkView.ContextMenuStrip.Items[index].Tag = LinkReleasedOn;
                    pbNetworkView.ContextMenuStrip.Items[index++].Click += pbNetworkView_ReplaceNetLink_Click;
                }
            }
            pbNetworkView.ContextMenuStrip.Visible = true;
            pbNetworkView.ContextMenuStrip.Show(Cursor.Position);

        }

        private void pbNetworkView_Hide_Click(object sender, EventArgs e)
        {
            if (ItemClickedOn != null)
            {
                ItemClickedOn.Hide();
                UpdateLinks();
                UpdateVisuals();
            }
        }

        private void pbNetworkView_PowerOn_Click(object sender, EventArgs e)
        {
            if (ItemClickedOn != null)
            {
                NB.DoActionPowerOn(ItemClickedOn.GetUniqueIdentifier);

                //ItemClickedOn.PowerOff = false;
                bool BlowUpOnce = myNetwork.ItemHasTest(ItemClickedOn.hostname, NetTestType.DeviceBlowsUpWithPower) && !myNetwork.ItemTestIsComplete(ItemClickedOn.hostname, NetTestType.DeviceBlowsUpWithPower);
                bool BlowUpMultiple = myNetwork.ItemHasTest(ItemClickedOn.hostname, NetTestType.DeviceNeedsUPS) && !myNetwork.ItemTestIsComplete(ItemClickedOn.hostname, NetTestType.DeviceNeedsUPS);
                if (BlowUpOnce || BlowUpMultiple)
                {
                    Rectangle Where = new Rectangle(ItemClickedOn.myLocation().X,
                        ItemClickedOn.myLocation().Y - ((ItemClickedOn.Size * 2) / 3), ItemClickedOn.Size, ItemClickedOn.Size);
                    if (ItemClickedOn.IsBurned)
                    {
                        int which = GameRandomGen.Next(3);
                        if (which == 0)
                            myNetwork.AddAnimation(AnimationName.Spark1, Where);
                        else if (which == 1)
                            myNetwork.AddAnimation(AnimationName.Lightning1, Where);
                        else
                            myNetwork.AddAnimation(AnimationName.Smoke1, Where);
                    }
                    else
                    {
                        int which = GameRandomGen.Next(3);
                        if (which == 0)
                            myNetwork.AddAnimation(AnimationName.Explo1, Where);
                        else
                            myNetwork.AddAnimation(AnimationName.Fire1, Where);
                    }
                    ItemClickedOn.IsBurned = true;
                    ItemClickedOn.PowerOff = true;  //It remains off.
                }
                NB.DoActionChangeComponent(ItemClickedOn);

                UpdateLinks();
                UpdateVisuals();
            }
        }

        private void pbNetworkView_PowerOff_Click(object sender, EventArgs e)
        {
            if (ItemClickedOn != null)
            {
                ItemClickedOn.PowerOff = true;
                //Mark the replace test as "done"
                NB.DoActionPowerOff(ItemClickedOn.GetUniqueIdentifier);
                //myNetwork.RegisterDeviceReset(ItemClickedOn.hostname);
                UpdateLinks();
                UpdateVisuals();
            }
        }

        //We will still do this for devices that are spraying the network
        private void pbNetworkView_Replace_Click(object sender, EventArgs e)
        {
            if (ItemClickedOn != null)
            {

                //ItemClickedOn.ClearIPs(); //reset the device
                //ItemClickedOn.IsBurned = false; //If it had been burned before, it is no longer burned
                //ItemClickedOn.PowerOff = true;
                //ItemClickedOn.BadSprayCount = 0;
                //NB.DoActionChangeComponent(ItemClickedOn);
                ////Mark the replace test as "done"
                //myNetwork.RegisterDeviceReset(ItemClickedOn.hostname); //replacing something powers it off

                //myNetwork.RegisterDeviceReplaced(ItemClickedOn.hostname); //replace it.
                NB.DoActionReplaceDevice(ItemClickedOn.GetUniqueIdentifier);

                UpdateVisuals();
            }
        }
        //We will still do this for devices that are spraying the network
        private void pbNetworkView_AddUPS_Click(object sender, EventArgs e)
        {
            if (ItemClickedOn != null)
            {
                if (ItemClickedOn == null) return;
                //Changing a UPS makes sure the power is off when done.
                //ItemClickedOn.PowerOff = true;
                NB.DoActionPowerOff(ItemClickedOn.GetUniqueIdentifier);
                //Mark the replace test as "done"
                //myNetwork.RegisterDeviceReset(ItemClickedOn.hostname); //replacing something powers it off
                NB.DoActionReplaceDeviceUPS(ItemClickedOn.GetUniqueIdentifier);
                //myNetwork.RegisterUPSAdded(ItemClickedOn.hostname); //Add the UPS.
                UpdateVisuals();
            }
        }

        private void ColorizeDevice(NetworkDevice Item, string Text)
        {
            if (ItemClickedOn != null)
            {
                if (Text == NB.Translate("NB_Blue"))
                    Item.ChangeColor(Color.Empty);
                if (Text == NB.Translate("NB_Purple"))
                    Item.ChangeColor(Color.Purple);
                if (Text == NB.Translate("NB_Yellow"))
                    Item.ChangeColor(Color.Yellow);
                if (Text == NB.Translate("NB_Green"))
                    Item.ChangeColor(Color.Green);
                if (Text == NB.Translate("NB_Orange"))
                    Item.ChangeColor(Color.Orange);
                if (Text == NB.Translate("NB_Cyan"))
                    Item.ChangeColor(Color.Cyan);
            }
        }

        private void pbNetworkView_Color_Click(object sender, EventArgs e)
        {
            ToolStripMenuItem TSMI = (ToolStripMenuItem)sender;
            if (ItemsSelected.Count > 0)
            {
                foreach (NetworkDevice nd in ItemsSelected)
                {
                    ColorizeDevice(nd, TSMI.Text);
                }
            }
            else
                ColorizeDevice(ItemClickedOn, TSMI.Text);
            UpdateVisuals();
        }

        private void pbNetworkView_RemoveLink_Click(object sender, EventArgs e)
        {
            ToolStripItem thing = (ToolStripItem)sender;
            string released = thing.Text;
            released = Regex.Replace(released, ".* ", "");
            if (ItemClickedOn != null)
            {
                //ItemClickedOn.RemoveLinkTo(released);
                NB.DoActionDeleteComponent(ItemClickedOn.GetUniqueIdentifier);
            }
            myNetwork.TestForCompletion(true);
            pbNetworkView.Update();
            UpdateVisuals();

        }

        private void pbNetworkView_EditNetLink_Click(object sender, EventArgs e)
        {
            ToolStripItem thing = (ToolStripItem)sender;
            if (thing.Tag != null)
            {
                NetworkLink NL = (NetworkLink)thing.Tag;
                NetworkLink oldLink = NetworkLink.Clone(NL);
                //This may delete the old link and make a new one
                LinkEditor LE = new LinkEditor(NL);
                LE.ShowDialog();
                if (!NL.Equals(oldLink))
                    NB.DoActionChangeComponent(NL);
            }
            myNetwork.TestForCompletion(true);
            pbNetworkView.Update();
            UpdateVisuals();
        }

        private void pbNetworkView_ReplaceNetLink_Click(object sender, EventArgs e)
        {
            ToolStripItem thing = (ToolStripItem)sender;
            if (thing.Tag != null)
            {
                NetworkLink NL = (NetworkLink)thing.Tag;
                ////This may delete the old link and make a new one
                //if (NL.theLinkType != LinkType.wireless)
                //{
                //    HostNicID source = NL.Src;
                //    HostNicID dest = NL.Dst;
                //    myNetwork.RemoveComponent(NL);
                //    NetworkLink nNL = new NetworkLink(source, dest, LinkType.normal);
                //    myNetwork.AddItem(nNL);
                //}
                NB.DoActionReplaceDevice(NL.GetUniqueIdentifier);
            }
            myNetwork.TestForCompletion(true);
            pbNetworkView.Update();
            UpdateVisuals();
        }


        private void pbNetworkView_RemoveNetLink_Click(object sender, EventArgs e)
        {
            ToolStripItem thing = (ToolStripItem)sender;
            if (thing.Tag != null)
            {
                NetworkLink NL = (NetworkLink)thing.Tag;
                //myNetwork.RemoveComponent(NL);
                NB.DoActionDeleteComponent(NL.GetUniqueIdentifier);
            }
            myNetwork.TestForCompletion(true);
            pbNetworkView.Update();
            UpdateVisuals();

        }


        private void pbNetworkView_DHCPRequest_Click(object sender, EventArgs e)
        {
            //ItemClickedOn.DHCPRequestFromHere();
            NB.DoActionDHCP(ItemClickedOn.GetUniqueIdentifier);
            myNetwork.ProcessPackets();
            UpdateMessages();
            pbNetworkView.Update();
            UpdateVisuals();
            myNetwork.TestForCompletion(true);
        }

        private void pbNetworkView_Reset_Click(object sender, EventArgs e)
        {
            if (ItemClickedOn == null) return;
            //ItemClickedOn.ClearIPs(); //reset the device
            NB.DoActionResetDevice(ItemClickedOn.GetUniqueIdentifier);
            UpdateVisuals();
        }

        private void pbNetworkView_Edit_Click(object sender, EventArgs e)
        {
            if (ItemClickedOn == null) return;
            if (ItemClickedOn.DeviceIsLockedOutByVLANs()) return; //we cannot edit this
            if (ItemClickedOn.GetNetType() == NetworkComponentType.microwave || ItemClickedOn.GetNetType() == NetworkComponentType.fluorescent)
                return;
            if (ItemClickedOn != null)
            {
                NetworkDevice oldND = NetworkDevice.Clone(ItemClickedOn);
                DeviceConfig editwindow = new DeviceConfig(ItemClickedOn);
                editwindow.ShowDialog();
                if (!ItemClickedOn.Equals(oldND))
                    NB.DoActionChangeComponent(ItemClickedOn);
            }
            UpdateLinks();
            myNetwork.TestForCompletion(true);
            UpdateVisuals();
        }

        private void TryDeleteOneItem(NetworkDevice Item)
        {
            //Deleting the item is easy, but we also need to delete any links to that item
            //List<HostNicID> NicIDs = new List<HostNicID>();
            //if (Item != null)
            //{
            //    if (myNetwork.ItemIsCritical(Item.hostname))
            //        return; //we cannot delete this
            //    NicIDs = Item.GetHostNicIDs();
            //    foreach (HostNicID nicID in NicIDs)
            //    {
            //        myNetwork.RemoveLinksToNic(nicID);
            //    }
            //    myNetwork.RemoveComponent(Item);
            //}
            NB.DoActionDeleteComponent(Item.GetUniqueIdentifier);
        }

        private void pbNetworkView_DeleteShape_Click(object sender, EventArgs e)
        {
            if (ShapeForEditing != null)
            {
                myNetwork.RemoveShape(ShapeForEditing);
                ShapeForEditing = null;
                UpdateForm();
            }
        }
        private void pbNetworkView_EditShape_Click(object sender, EventArgs e)
        {
            if (ShapeForEditing != null)
            {
                ShapeEditor SE = new ShapeEditor(ShapeForEditing);
                SE.ShowDialog();

                ShapeForEditing = null;
                UpdateForm();
            }
        }


        private void pbNetworkView_Delete_Click(object sender, EventArgs e)
        {
            if (ItemsSelected.Count == 0)
            {
                TryDeleteOneItem(ItemClickedOn);
            }
            else
            {
                for (int i = ItemsSelected.Count - 1; i >= 0; i--)
                {
                    TryDeleteOneItem(ItemsSelected[i]);
                }
            }
            pbNetworkView.Image = null;
            ItemsSelected.Clear();
            UpdateLinks();
            myNetwork.TestForCompletion(true);
            UpdateVisuals();
        }

        private void pbNetworkView_Ping_Click(object sender, EventArgs e)
        {
            bool todo = true;
            if (ItemClickedOn == null) return; //we do not have something chosen to ping from
            NB_IPAddress destination = new NB_IPAddress(NB.ZeroIPString, NB.ZeroIPString, IPAddressType.ip_only);
            todo = destination.Edit(ItemClickedOn, this, NB.Translate("_Ping"), true);
            if (todo)
            {
                //ItemClickedOn.PingFromHere(destination);
                NB.DoActionPingDevice(ItemClickedOn.GetUniqueIdentifier, destination);
                myNetwork.ProcessPackets();
                UpdateMessages();
            }
        }

        private void pbNetworkView_Traceroute_Click(object sender, EventArgs e)
        {
            bool todo = true;
            if (ItemClickedOn == null) return; //we do not have something chosen to traceroute from
            NB_IPAddress destination = new NB_IPAddress(NB.ZeroIPString, NB.ZeroIPString, IPAddressType.ip_only);
            todo = destination.Edit(ItemClickedOn, this, NB.Translate("_Traceroute"), true);
            if (todo)
            {
                //ItemClickedOn.TracerouteFromHere(destination);
                NB.DoActionTracertDevice(ItemClickedOn.GetUniqueIdentifier, destination);
                myNetwork.ProcessPackets();
                UpdateMessages();
            }
        }

        private void pbNetworkView_Ping_Name_Click(object sender, EventArgs e)
        {
            if (ItemClickedOn == null) return; //we do not have something chosen to ping from
            ToolStripMenuItem Pressed = (ToolStripMenuItem)sender;

            string itemname = Pressed.Text;
            string dest = (string)Pressed.Tag;
            NB_IPAddress destination;
            destination = myNetwork.DNSLookup(ItemClickedOn, dest);
            if (destination == null || destination.GetIPString == NB.ZeroIPString)
                destination = new NB_IPAddress(dest);
            //ItemClickedOn.PingFromHere(destination);
            NB.DoActionPingDevice(ItemClickedOn.GetUniqueIdentifier, destination);
            myNetwork.ProcessPackets();
            UpdateMessages();
        }

        private void pbNetworkView_Traceroute_Name_Click(object sender, EventArgs e)
        {
            if (ItemClickedOn == null) return; //we do not have something chosen to ping from
            ToolStripMenuItem Pressed = (ToolStripMenuItem)sender;
            string itemname = Pressed.Text;
            string dest = (string)Pressed.Tag;
            NB_IPAddress destination;
            destination = myNetwork.DNSLookup(ItemClickedOn, dest);
            if (destination == null || destination.GetIPString == NB.ZeroIPString)
                destination = new NB_IPAddress(dest);
            //ItemClickedOn.TracerouteFromHere(destination);
            NB.DoActionTracertDevice(ItemClickedOn.GetUniqueIdentifier, destination);
            myNetwork.ProcessPackets();
            UpdateMessages();
        }

        private void pbNetworkView_Arp_Name_Click(object sender, EventArgs e)
        {
            if (ItemClickedOn == null) return; //we do not have something chosen to ping from
            ToolStripMenuItem Pressed = (ToolStripMenuItem)sender;
            string itemname = Pressed.Text;
            string dest = (string)Pressed.Tag;
            NB_IPAddress destination;
            destination = myNetwork.DNSLookup(ItemClickedOn, dest);
            if (destination == null || destination.GetIPString == NB.ZeroIPString)
                destination = new NB_IPAddress(dest);
            NB.DoActionArpDevice(ItemClickedOn.GetUniqueIdentifier, destination);
            //ItemClickedOn.AskArpFromHere(destination);
            myNetwork.ProcessPackets();
            UpdateMessages();
        }

        private void pbNetworkView_Arp_Click(object sender, EventArgs e)
        {
            bool todo = true;
            if (ItemClickedOn == null) return; //we do not have something chosen to arp request from
            NB_IPAddress destination = new NB_IPAddress(NB.ZeroIPString, "255.255.255.255", IPAddressType.ip_only);
            todo = destination.Edit(ItemClickedOn, this, NB.Translate("H_ARP_Title2"));
            if (todo)
            {
                //ItemClickedOn.AskArpFromHere(destination);
                NB.DoActionArpDevice(ItemClickedOn.GetUniqueIdentifier, destination);
                myNetwork.ProcessPackets();
                UpdateMessages();
            }
        }

        private void pbNetworkView_ArpClear_Click(object sender, EventArgs e)
        {
            if (ItemClickedOn == null) return; //we do not have something chosen to arp request from
            //ItemClickedOn.ClearArps();
            NB.DoActionClearArpDevice(ItemClickedOn.GetUniqueIdentifier);
        }

        private void pbNetworkView_MouseUp(object sender, MouseEventArgs e)
        {
            lblStatus.Text = "";
            //find where we were clicked
            Point CenteredLocation = myNetwork.clickedPosCentered(e.Location);
            Point ClickLocation = myNetwork.clickedPos(e.Location);
            NetworkDevice ReleasedOn = myNetwork.ItemAtPosition(ClickLocation);
            NetworkLink ReleasedOnLink = null;
            if (ReleasedOn == null && !myNetwork.InShapeEditMode)
                ReleasedOnLink = myNetwork.LinkAtPosition(ClickLocation);

            LastBackgroundImage = null;
            pbNetworkView.Image = null; //erase old highlight area
            LastMouseMovePos = new Point(-1, -1);

            //Do we have something selected that we should add?
            TimeSpan duration;
            duration = DateTime.Now - LastClick;

            if (ReleasedOnLink != null && e.Button == MouseButtons.Right)
            {
                //Right-click on a line.  Make a special context menu for that.
                //  delete
                //  edit
                pbNetworkView_RightMouseUponLink(ReleasedOnLink, e);
                return; //We do not do the rest of this...
            }

            //Track size of area for the click/drag
            int sx;
            int sy;
            int swidth;
            int sheight;
            if (ClickedImageLocation.X > e.Location.X)
            {
                sx = e.Location.X;
                swidth = ClickedImageLocation.X - sx;
            }
            else
            {
                sx = ClickedImageLocation.X;
                swidth = e.Location.X - sx;
            }
            if (ClickedImageLocation.Y > e.Location.Y)
            {
                sy = e.Location.Y;
                sheight = ClickedImageLocation.Y - sy;
            }
            else
            {
                sy = ClickedImageLocation.Y;
                sheight = e.Location.Y - sy;
            }

            if (e.Button == System.Windows.Forms.MouseButtons.Right)
            {
                pbNetworkView_RightMouseUp(ReleasedOn, e);
                return;
            }
            if (duration.TotalMilliseconds < 250)
            {
                bool PoweredOff = false;
                //This mouse-up is part of a double-click operation. Do an edit.  But only if we are powered on
                if (ItemClickedOn != null) PoweredOff = ItemClickedOn.PowerOff;
                if (!PoweredOff)
                {
                    pbNetworkView_Edit_Click(sender, e);
                }
            }
            else
            {
                if (MouseIsDown && ItemsSelected.Count > 0)
                {
                    //We were dragging stuff.  All done now
                    MouseIsDown = false;
                    foreach (NetworkDevice nd in ItemsSelected)
                    {
                        //Do an action move to the new location.
                        NB.DoActionMoveDevice(nd.GetUniqueIdentifier, nd.myLocation());
                    }
                    ItemsSelected.Clear(); //clear it so we stop moving these ones
                    UpdateLinks();
                    UpdateVisuals();
                    return;
                }
                if (MouseIsDown && ItemClickedOn == null && (swidth > 4 || sheight > 4))
                {
                    //We just finished dragging a select box
                    //Put them all into the drag box.
                    ItemsSelected.Clear();

                    //Now we have a rectangle, but need to exchange numbers for numbers on the image
                    Point topCorner = myNetwork.clickedPos(new Point(sx, sy));
                    Point botCorner = myNetwork.clickedPos(new Point(sx + swidth, sy + sheight));

                    Rectangle selectbox = new Rectangle(topCorner.X, topCorner.Y, botCorner.X - topCorner.X, botCorner.Y - topCorner.Y);

                    if (!myNetwork.InShapeEditMode)
                    {
                        ItemsSelected.AddRange(myNetwork.DevicesInRectangle(selectbox));
                        //Console.WriteLine("Selected " + ItemsSelected.Count + " items");
                        MouseIsDown = false;
                        DrawHighlightBoxes();
                        pbNetworkView.Invalidate();
                        return;
                    }
                    else
                    {
                        //We just made a shape.
                        try
                        {
                            string fColor = cbFillColor.Text;
                            string lColor = cbLineColor.Text;
                            if (fColor == "") fColor = "Empty";
                            if (lColor == "") lColor = "Empty";
                            Color FillColor = Color.FromName(fColor);
                            Color LineColor = Color.FromName(lColor);
                            if (LineColor.Name != "Empty" || FillColor.Name != "Empty")
                            {
                                if (ShapeForEditing == null)
                                {
                                    NetShape NS = new NetShape(CurrentShape, selectbox, FillColor, LineColor);

                                    myNetwork.AddShape(NS);
                                    UpdateForm();
                                }
                                else
                                {
                                    ShapeForEditing.MyShape = CurrentShape;
                                    ShapeForEditing.InArea = selectbox;
                                    ShapeForEditing.FillColor = FillColor;
                                    ShapeForEditing.LineColor = LineColor;
                                    UpdateForm();

                                }
                            }
                        }
                        catch
                        {
                            //Nothing to do.  Something is wrong with the colors.
                        }
                    }
                }
                MouseIsDown = false;
                if (selectedButton == "btnLink")
                {
                    //We are making a link
                    LinkEditor myEditor = new LinkEditor(ItemClickedOn, ReleasedOn);
                    myEditor.ShowDialog();
                    UpdateLinks();
                    UpdateVisuals(); //In case any changes have been made
                }
                else if (ItemClickedOn == null)
                {
                    NetworkComponent NC = null;
                    NetworkComponentType NCType = NetworkComponentType.none;
                    switch (selectedButton)
                    {
                        case "btnSwitch":
                            //NC = myNetwork.AddItem(NetworkComponentType.net_switch, CenteredLocation);
                            NCType = NetworkComponentType.net_switch;
                            break;
                        case "btnHub":
                            //NC = myNetwork.AddItem(NetworkComponentType.net_hub, CenteredLocation);
                            NCType = NetworkComponentType.net_hub;
                            break;
                        case "btnLaptop":
                            //NC = myNetwork.AddItem(NetworkComponentType.laptop, CenteredLocation);
                            NCType = NetworkComponentType.laptop;
                            break;
                        case "btnServer":
                            //NC = myNetwork.AddItem(NetworkComponentType.server, CenteredLocation);
                            NCType = NetworkComponentType.server;
                            break;
                        case "btnPC":
                            //NC = myNetwork.AddItem(NetworkComponentType.pc, CenteredLocation);
                            NCType = NetworkComponentType.pc;
                            break;
                        case "btnRouter":
                            //NC = myNetwork.AddItem(NetworkComponentType.router, CenteredLocation);
                            NCType = NetworkComponentType.router;
                            break;
                        case "btnIPPhone":
                            //NC = myNetwork.AddItem(NetworkComponentType.ip_phone, CenteredLocation);
                            NCType = NetworkComponentType.ip_phone;
                            break;
                        case "btnFirewall":
                            //NC = myNetwork.AddItem(NetworkComponentType.firewall, CenteredLocation);
                            NCType = NetworkComponentType.firewall;
                            break;
                        case "btnPrinter":
                            //NC = myNetwork.AddItem(NetworkComponentType.printer, CenteredLocation);
                            NCType = NetworkComponentType.printer;
                            break;
                        case "btnCopier":
                            //NC = myNetwork.AddItem(NetworkComponentType.copier, CenteredLocation);
                            NCType = NetworkComponentType.copier;
                            break;
                        case "btnMicrowave":
                            //NC = myNetwork.AddItem(NetworkComponentType.microwave, CenteredLocation);
                            NCType = NetworkComponentType.microwave;
                            break;
                        case "btnFluorescent":
                            //NC = myNetwork.AddItem(NetworkComponentType.fluorescent, CenteredLocation);
                            NCType = NetworkComponentType.fluorescent;
                            break;
                        case "btnWAP":
                            //NC = myNetwork.AddItem(NetworkComponentType.wap, CenteredLocation);
                            NCType = NetworkComponentType.wap;
                            break;
                        case "btnWRouter":
                            //NC = myNetwork.AddItem(NetworkComponentType.wrouter, CenteredLocation);
                            NCType = NetworkComponentType.wrouter;
                            break;
                        case "btnCellphone":
                            //NC = myNetwork.AddItem(NetworkComponentType.cellphone, CenteredLocation);
                            NCType = NetworkComponentType.cellphone;
                            break;
                        case "btnTablet":
                            //NC = myNetwork.AddItem(NetworkComponentType.tablet, CenteredLocation);
                            NCType = NetworkComponentType.tablet;
                            break;
                        case "btnWBridge":
                            //NC = myNetwork.AddItem(NetworkComponentType.wbridge, CenteredLocation);
                            NCType = NetworkComponentType.wbridge;
                            break;
                        case "btnWRepeater":
                            //NC = myNetwork.AddItem(NetworkComponentType.wrepeater, CenteredLocation);
                            NCType = NetworkComponentType.wrepeater;
                            break;
                        case "btnTree":
                            //NC = myNetwork.AddItem(NetworkComponentType.tree, CenteredLocation);
                            NCType = NetworkComponentType.tree;
                            break;
                    }
                    NC = NB.DoActionAddDevice(NCType, CenteredLocation);
                    if (NC != null && NB.GetComponentType(NC) == GeneralComponentType.device)
                    {
                        ItemClickedOn = (NetworkDevice)NC;
                    }
                    UpdateVisuals();
                }
                else //Drag the item
                {
                    if (Math.Abs(ClickedLocation.X - ClickLocation.X) > 5 || Math.Abs(ClickedLocation.Y - ClickLocation.Y) > 5)
                    {
                        if (!ItemClickedOn.IsLockedInLocation())
                        {
                            //ItemClickedOn.ChangeLocation(CenteredLocation);
                            //ItemClickedOn.UnHide(); //If it was hidden, unhide it
                            NB.DoActionMoveDevice(ItemClickedOn.GetUniqueIdentifier, CenteredLocation);
                            UpdateLinks();
                            UpdateVisuals();
                        }
                    }
                }
            }
            LastClick = DateTime.Now;
        }

        public void ChangeStatusText(string text)
        {
            lblStatus.Text = text;
        }

        private void UpdateVisuals()
        {
            myNetwork.Print();
            pbNetworkView.Invalidate();
        }

        private void pbNetworkView_MouseDown(object sender, MouseEventArgs e)
        {
            ProcessChange(); //Before anything happens, store this state if we need to.
            Point location = myNetwork.clickedPos(e.Location);
            ClickedLocation = location;
            OrigClickPoint = myNetwork.clickedPosCentered(e.Location);
            ClickedImageLocation = e.Location;
            //See if we have clicked on something
            if (!myNetwork.InShapeEditMode)
            {
                ItemClickedOn = myNetwork.ItemAtPosition(location);
                ShapeForEditing = null;
            }
            else
            {
                ItemClickedOn = null;
                ShapeForEditing = myNetwork.ShapeAtPoint(location);
                if (ShapeForEditing != null && e.Button == MouseButtons.Left)
                {
                    //we set the drag-point for the opposite corner
                    ClickedLocation = ShapeForEditing.OppositePoint(location);
                    ClickedImageLocation = myNetwork.PictureBoxPoint(ClickedLocation);
                    CurrentShape = ShapeForEditing.MyShape;
                    cbFillColor.Text = ShapeForEditing.FillColor.Name;
                    cbLineColor.Text = ShapeForEditing.LineColor.Name;
                    btnUpdateShape(); //Change the shape to what we are editing
                }
                else if (ShapeForEditing != null && e.Button == MouseButtons.Right)
                {
                    //Right-clicking the shape.  Context menu to come at button release!
                }
            }
            if (e.Button == MouseButtons.Left)
                MouseIsDown = true;
            LastMouseDown = DateTime.UtcNow;
            //Make a duplicate of the old background image.
            LastBackgroundImage = new Bitmap(pbNetworkView.BackgroundImage);
        }

        private void DragItemToNewLocation(NetworkDevice toMove, Point NewPosition)
        {
            if (toMove == null) return;
            if (LastBackgroundImage == null) return;

            Size itemsize = new Size(toMove.Size, toMove.Size);
            Rectangle newrec = new Rectangle(NewPosition, itemsize);

            Point oldpoint = toMove.myLocation();
            Rectangle oldrec = new Rectangle(oldpoint.X, oldpoint.Y, toMove.Size, toMove.Size);
            Graphics.FromImage(pbNetworkView.BackgroundImage).DrawImage(LastBackgroundImage, oldrec, oldrec, GraphicsUnit.Pixel);
            myNetwork.Invalidate(oldrec);

            //set it to the new pos
            toMove.ChangeLocationUnsnapped(NewPosition);
            //tell it to draw
            toMove.Print(pbNetworkView.BackgroundImage, CaptionType.none);
            //invalidate
            myNetwork.Invalidate(newrec);
        }

        private void DrawHighlightBoxes()
        {
            Image tImage = new Bitmap(pbNetworkView.BackgroundImage.Width, pbNetworkView.BackgroundImage.Height);
            Graphics tGraphics = Graphics.FromImage(tImage);
            tGraphics.Clear(Color.Transparent); //erase the whole thing

            Color tColor = Color.LightGreen;
            SolidBrush semiTransBrush = new SolidBrush(Color.FromArgb(128, tColor.R, tColor.G, tColor.B));
            foreach (NetworkDevice nd in ItemsSelected)
            {
                tGraphics.FillRectangle(semiTransBrush, nd.GetMyRectangle());
            }
            pbNetworkView.Image = tImage;
            pbNetworkView.Invalidate();

        }

        private void pbNetworkView_MouseMove(object sender, MouseEventArgs e)
        {
            Image tImage;
            //Only do this 10 times a second
            if (DateTime.UtcNow - LastMoveTime < TimeSpan.FromMilliseconds(100)) return;

            Point CenteredLocation = myNetwork.clickedPosCentered(e.Location);
            Point MouseLocation = myNetwork.clickedPos(e.Location);
            //If we are dragging lines, do that first.
            if (selectedButton == "btnLink")
            {
                if (MouseIsDown)
                {
                    //We are trying to do a link.  Drag a line...
                    if (ItemClickedOn != null)
                    {
                        Point OrigCenter = ItemClickedOn.GetCenter();
                        //Draw a line from the item-clicked on to the mouse
                        tImage = new Bitmap(pbNetworkView.BackgroundImage.Width, pbNetworkView.BackgroundImage.Height);
                        Graphics tGraphics = Graphics.FromImage(tImage);
                        tGraphics.Clear(Color.Transparent); //erase the whole thing

                        //draw the line
                        //tGraphics.FillRectangle(semiTransBrush, selectbox);
                        tGraphics.DrawLine(Pens.Black, OrigCenter, MouseLocation);
                        pbNetworkView.Image = tImage;
                        pbNetworkView.Invalidate();

                    }
                }
            }
            else if (MouseIsDown && LastBackgroundImage != null && ItemClickedOn != null && ItemsSelected.Count == 0) //We are trying to drag something
            {
                //find where we are
                TimeSpan HowLong = DateTime.UtcNow - LastMouseDown;
                if (HowLong.TotalMilliseconds > 100 && !ItemClickedOn.IsLockedInLocation())
                    DragItemToNewLocation(ItemClickedOn, CenteredLocation);
            }
            else if (MouseIsDown && ItemsSelected.Count > 0) //dragging multiple items around
            {
                //Track the difference between the last redraw and this re-draw
                //Move every item by that amount.
                int xdif = CenteredLocation.X - OrigClickPoint.X;
                int ydif = CenteredLocation.Y - OrigClickPoint.Y;
                if (xdif != 0 || ydif != 0)
                {
                    foreach (NetworkDevice nd in ItemsSelected)
                    {
                        Point oPoint = nd.myLocation();
                        Point nPoint = new Point(oPoint.X + xdif, oPoint.Y + ydif);
                        DragItemToNewLocation(nd, nPoint);
                    }
                }
                //Now set the location so we do it from here next time
                OrigClickPoint = CenteredLocation;
            }
            else if (MouseIsDown && ItemClickedOn == null) //Dragging an empty area
            {
                //make a rectangle
                tImage = new Bitmap(pbNetworkView.BackgroundImage.Width, pbNetworkView.BackgroundImage.Height);
                Graphics tGraphics = Graphics.FromImage(tImage);
                tGraphics.Clear(Color.Transparent); //erase the whole thing
                int sx;
                int sy;
                int swidth;
                int sheight;
                if (ClickedLocation.X > MouseLocation.X)
                {
                    sx = MouseLocation.X;
                    swidth = ClickedLocation.X - sx;
                }
                else
                {
                    sx = ClickedLocation.X;
                    swidth = MouseLocation.X - sx;
                }
                if (ClickedLocation.Y > MouseLocation.Y)
                {
                    sy = MouseLocation.Y;
                    sheight = ClickedLocation.Y - sy;
                }
                else
                {
                    sy = ClickedLocation.Y;
                    sheight = MouseLocation.Y - sy;
                }
                Rectangle selectbox = new Rectangle(sx, sy, swidth, sheight);

                Color tColor = Color.LightGreen;
                SolidBrush semiTransBrush = new SolidBrush(Color.FromArgb(128, tColor.R, tColor.G, tColor.B));
                tGraphics.FillRectangle(semiTransBrush, selectbox);
                pbNetworkView.Image = tImage;
                pbNetworkView.Invalidate();
            }

            Point location = myNetwork.clickedPos(e.Location);
            NetworkDevice MouseOver = myNetwork.ItemAtPosition(location);
            MouseHoverOver = MouseOver;
            string oldtooltip = myTooltip.GetToolTip(pbNetworkView);
            string newtooltip = "";
            if (MouseOver != null)
            {
                if (!MouseOver.DeviceIsLockedOutByVLANs())
                    newtooltip = MouseOver.TooltipString();
                else
                    newtooltip = NB.Translate("NB_LockedOut");
            }
            if (oldtooltip != newtooltip)
            {
                myTooltip.SetToolTip(pbNetworkView, newtooltip);
            }
        }

        private void PrepForLoad()
        {
            processing = true;
            ClearStoredNetworkStates();
            myNetwork = new Network("");
            myNetwork.RegisterDisplayArea(pbNetworkView);
            GC.Collect();
            RTFWindow myWin = (RTFWindow)Application.OpenForms["RTFWindow"];
            if (myWin != null)
            {
                myWin.Close();
            }

            myNetwork.Print();
            UpdateMessages();
            btnReset();
            myNetwork.HintsToDisplay = NetTestVerbosity.none;
            rbHelp1.Checked = true;
            processing = false;
        }

        private void loadToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenFileDialog mydialog = new OpenFileDialog();
            mydialog.AddExtension = true;
            //If we have a user loaded, we can open homework files
            string filter = "EduNet File (*.enbx, *enbu)|*.enbx; *.enbu";
            if (NB.GetUser() != null)
                filter = "EduNet File (*.enbx, *enbu, *enbh)|*.enbx; *.enbu; *.enbh";
            mydialog.Filter = filter;
            mydialog.Multiselect = false;
            mydialog.ShowHelp = true;
            if (LastPath != null && LastPath != "") mydialog.FileName = LastPath;
            DialogResult result = mydialog.ShowDialog();
            if (result == System.Windows.Forms.DialogResult.Cancel) return;
            string extension = Path.GetExtension(mydialog.FileName).ToString();
            if (extension != ".enbx" && extension != ".enbu" && extension != ".enbh")
            {
                MessageBox.Show(NB.Translate("_LoadErr"));
                return;
            }
            LastPath = mydialog.FileName;
            if (!File.Exists(mydialog.FileName)) return;

            LoadInitialFile(mydialog.FileName);
            fileToolStripMenuItem.HideDropDown();
        }

        private void reloadToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string oldfile = myNetwork.NetworkFilename;
            if (oldfile != null && oldfile != "" && File.Exists(oldfile))
            {
                PrepForLoad();
                myNetwork.Load(oldfile);
            }
            else
            {
                if(OrigNetworkAfterLoad != null)
                {                    
                    PrepForLoad();
                    LoadNetworkFromNetwork(OrigNetworkAfterLoad);
                }
            }
            if(OurSettings.ReplayMode)
            {
                //clear out the replay actions for this network
                ActionCollection AC = OurSettings.GetUserActionCollection();
                if (AC != null)
                {
                    NetworkAction NA = AC.GetCurrentNetAction();
                    if (NA != null)
                        NA.Actions.Clear();
                }
            }
            UpdateMenu();
            UpdateForm();
        }

        public void doSave(bool TrySkipPrompt = false)
        {
            if (TrySkipPrompt && myNetwork.NetworkFilename != null && File.Exists(myNetwork.NetworkFilename))
            {
                //Just save over it
                myNetwork.Save(myNetwork.NetworkFilename);
                NB.PlaySound(NBSoundType.saved_ok);
            }
            else
            {
                SaveFileDialog mydialog = new SaveFileDialog();
                mydialog.AddExtension = true;
                mydialog.Filter = "EduNet File (*.enbx)|*.enbx";
                mydialog.FileName = myNetwork.NetworkFilename;
                string initialfolder = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
                if (myNetwork.NetworkFilename != "")
                    initialfolder = Path.GetDirectoryName(myNetwork.NetworkFilename);
                mydialog.CreatePrompt = true;
                mydialog.OverwritePrompt = true;
                mydialog.InitialDirectory = initialfolder;
                DialogResult result = mydialog.ShowDialog();

                if (result == System.Windows.Forms.DialogResult.Cancel)
                {
                    NB.PlaySound(NBSoundType.saved_failed);
                    lblStatus.Text = NB.Translate("_Canceled");
                    return;
                }
                LastPath = mydialog.FileName;
                myNetwork.Save(mydialog.FileName);
                NB.PlaySound(NBSoundType.saved_ok);
            }
            lblStatus.Text = NB.Translate("_Saved");
        }

        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            doSave(false);
        }

        private void BuilderWindow_Resize(object sender, EventArgs e)
        {
            if (WindowState == FormWindowState.Normal)
            {
                //size limits go here
                int smallestX = 400;
                int smallestY = 300;
                if (Width < smallestX) Width = smallestX;
                if (Height < smallestY) Height = smallestY;
            }
        }

        private void BuilderWindow_ResizeEnd(object sender, EventArgs e)
        {
            UpdateVisuals();
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            RTFWindow mywindow = new RTFWindow(RTFWindowContents.about);
            mywindow.ShowDialog();

        }

        private void helpToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            NB.ReadContextHelp(HelpTopics.None);
        }

        private void releaseNotesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            RTFWindow mywindow = new RTFWindow(RTFWindowContents.release_notes);
            mywindow.ShowDialog();
        }

        private void lbMessages_DoubleClick(object sender, EventArgs e)
        {
            if (lbMessages.SelectedIndex < 0) return; //nothing to do
            if (lbMessages.SelectedIndex > myNetwork.CountMessages()) return; //invalid.  Do nothing
            PacketMessage newMessage = myNetwork.GetMessageAtIndex(lbMessages.SelectedIndex);
            if (newMessage == null) return; //Not sure how we could get to this, but break out just in case
            ListBoxWindow newwindow = new ListBoxWindow(newMessage);
            newwindow.ShowDialog();
        }

        private void BuilderWindow_FormClosing(object sender, FormClosingEventArgs e)
        {
            //The values in the settings are all up-to-date.  Just tell them to save.
            if (WindowState == FormWindowState.Normal)
            {
                OurSettings.MainWindowHeight = Height;
                OurSettings.MainWindowWidth = Width;
                OurSettings.MainWindowX = Location.X;
                OurSettings.MainWindowY = Location.Y;
            }

            OurSettings.Save(NB.IsRunningOnMono());
            if (CurrentUser != null)
                CurrentUser.Save(true); //Save the person, making a backup of the person file
        }

        private void dHCPRequestToolStripMenuItem_Click(object sender, EventArgs e)
        {
            myNetwork.DoAllDHCP();
            myNetwork.ProcessPackets();
            UpdateMessages();
        }

        private void clearArpTableToolStripMenuItem_Click(object sender, EventArgs e)
        {
            myNetwork.DoAllClearArp();
            UpdateMessages();
        }

        private void clearIPsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            myNetwork.DoAllClearIPs();
            UpdateMessages();
        }

        private void pingToolStripMenuItem_Click(object sender, EventArgs e)
        {
            bool todo = true;
            NB_IPAddress destination = new NB_IPAddress(NB.ZeroIPString, NB.ZeroIPString, IPAddressType.ip_only);
            todo = destination.Edit(null, this, NB.Translate("NB_NetViewPng"));
            if (todo)
            {
                myNetwork.DoAllPing(destination);
                myNetwork.ProcessPackets();
                UpdateMessages();
            }
        }

        public void LoadNetworkFromResource(string resource, bool SkipOpeningWindows = false)
        {
            XmlDocument xmlDoc = new XmlDocument();
            //Load(SavePath);
            System.Reflection.Assembly MyAssembly;
            MyAssembly = this.GetType().Assembly;

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

            // Retrieves String and Image resources.
            System.String myString;
            byte[] item = (byte[])myManager.GetObject(resource);
            myString = new StreamReader(new MemoryStream(item), true).ReadToEnd();
            //myString = System.Text.Encoding.Default.GetString(item);
            xmlDoc.LoadXml(myString);
            PrepForLoad();
            myNetwork.Load(xmlDoc, resource, true, SkipOpeningWindows);//Load it from resource.  Set the bool saying it was from resource
            RegisterRecentlyLoadedNet(myNetwork);
            StoreNetworkState(myNetwork); //Store a clean state
            UpdateMenu();
            UpdateForm();
        }

        public void LoadNetworkFromNetwork(Network NewNet)
        {
            if (NewNet != null)
            {
                PrepForLoad();
                Network.Clone(NewNet, myNetwork); //Push the settings
                myNetwork.OpenHelpIfNeeded(false); //Open it up, not skipping the help file (open help if the puzzle wants it)
                RegisterRecentlyLoadedNet(myNetwork);
                myNetwork.DoAllMarkAsLinked();
                UpdateMenu();
                UpdateLinks();
                UpdateForm();
                NBSettings ns = NB.GetSettings();
                StoreNetworkState(myNetwork); //Store a clean state
                if (ns != null && ns.AutoDHCPAllMachinesAtNetworkLoad)
                    myNetwork.DoAllDHCP();
            }
        }

        private void LoadSolvedResource(string what)
        {
            PrepForLoad();
            LoadNetworkFromResource(what);
            StoreNetworkState(myNetwork); //Store a clean state
            myNetwork.OverrideFromResources();
            RegisterRecentlyLoadedNet(myNetwork);
            UpdateForm();
            UpdateMessages();
        }

        public void RegisterRecentlyLoadedNet(Network ToRegister)
        {
            OrigNetworkAfterLoad = Network.DeepClone(ToRegister);
        }

        private void LoadUnsolvedResource(string what)
        {
            //Load the puzzle & everything we need to do with it
            LoadSolvedResource(what);
            //Then "unsolve" it
            myNetwork.DoAllClearIPs();
            myNetwork.OverrideFromResources();
            StoreNetworkState(myNetwork); //Store a clean state
            RegisterRecentlyLoadedNet(myNetwork);
            UpdateForm();
            UpdateMessages();
        }

        private void CreateSolvedUnsolvedToolstripItems()
        {
            foreach (SolvedNetworkNames one in Enum.GetValues(typeof(SolvedNetworkNames)))
            {
                //add a solved one
                ToolStripMenuItem tsmi = new ToolStripMenuItem(NB.Translate("NB_" + one.ToString()));
                tsmi.Name = one.ToString();
                tsmi.Click += MenuItemLoadSolved;
                solvedToolStripMenuItem.DropDownItems.Add(tsmi);
                //Add one for the unsolved
                tsmi = new ToolStripMenuItem(NB.Translate("NB_" + one.ToString()));
                tsmi.Name = one.ToString();
                tsmi.Click += MenuItemLoadUnsolved;
                toSolveToolStripMenuItem.DropDownItems.Add(tsmi);
            }
        }

        private void MenuItemLoadSolved(object sender, EventArgs e)
        {
            ToolStripMenuItem tsmi = (ToolStripMenuItem)sender;
            LoadSolvedResource(tsmi.Name);
        }
        private void MenuItemLoadUnsolved(object sender, EventArgs e)
        {
            ToolStripMenuItem tsmi = (ToolStripMenuItem)sender;
            LoadUnsolvedResource(tsmi.Name);
        }

        private void newToolStripMenuItem_Click(object sender, EventArgs e)
        {
            PrepForLoad();
            UpdateForm();
        }

        private void optionsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ProcessChange(); //make sure we make an undo-point in case a change is made.
            OptionsWindow tWindow = new OptionsWindow(myNetwork);
            tWindow.ShowDialog();
            myNetwork.UpdateDeviceSizes();

            UpdateForm();
        }

        private void LoadInitialFile(string filename)
        {
            if (filename == "")
            {
                MessageBox.Show(NB.Translate("NB_InvalidFile"));
                //Close();
                return;
            }
            if (!File.Exists(filename))
            {
                MessageBox.Show(string.Format(NB.Translate("NB_NoSuchFile"), filename));
                //Close();
                return;
            }
            //If it is a network file
            string extension = Path.GetExtension(filename).ToLower();
            //MessageBox.Show(filename + "  " +extension);
            try
            {
                if (extension == ".enbx")
                {
                    PrepForLoad();
                    myNetwork.Load(filename);
                    UpdateMenu();
                    UpdateForm();
                }
                else if (extension == ".enbu")
                {
                    if (CurrentUser != null && !CurrentUser.isAdmin)
                    {
                        MessageBox.Show(NB.Translate("NB_LogOutFirst"));
                        return;
                    }
                    if (CurrentUser == null)
                    { //Load a starting, or a new user
                        int counter = 0;
                        PersonClass tUser = null;
                        while (counter < 4)
                        {
                            string tPass = "";
                            if (counter > 0) //First try an empty password
                                tPass = NB.TextPromptBox("Enter a password", Properties.Resources.NBIco, true);
                            string tUserName = Path.GetFileNameWithoutExtension(filename);
                            string PasToUse = tUserName + tPass;
                            tUser = PersonClass.TryLoad(filename, PasToUse);
                            if (tUser != null) break;
                            counter++;
                        }
                        if (tUser == null)
                        {
                            //failed to load.
                            MessageBox.Show("Too many password failures.  Exiting.");
                            return;
                        }
                        CurrentUser = tUser;
                        CurrentUser.filepath = Path.GetDirectoryName(filename); //store the directory
                        OurSettings = NB.GetSettings(); //Grab the new settings from the user
                        if (CurrentUser.ChangePassAtFirstLogin)
                            CurrentUser.ChangePassword(); //change the password
                        UpdateMenu();

                        //Now, open a new window to edit them.
                        PersonProfileForm PPF = new PersonProfileForm(CurrentUser);
                        CurrentUser = PPF.Edit(); //This does the form as dialog.  When we come back, update the menu.
                        UpdateMenu();
                    }
                    else if (CurrentUser != null && CurrentUser.isAdmin)
                    {
                        //We want to import the student information for this one student
                        string user = Path.GetFileNameWithoutExtension(filename);
                        //Dig up the corresponding user.
                        PersonClass CurrentStudentUser = CurrentUser.StudentWithTheUserName(user);
                        if (CurrentStudentUser == null)
                        {
                            //This means we do not have a user with that name in this class.
                            //More importantly, we do not have an alt-password set up so we can import them.
                            MessageBox.Show(string.Format(NB.Translate("NB_TeacherUnableToLoadUserNoAcct"), user));
                            return;
                        }
                        //Use the alt password for that user to load the file
                        PersonClass LoadedStudent = PersonClass.TryLoad(filename, CurrentStudentUser.AltPassword);
                        if (LoadedStudent == null)
                        {
                            //This means our password did not work
                            MessageBox.Show(string.Format(NB.Translate("NB_TeacherUnableToLoadUserInvalidPW"), user));
                            return;
                        }
                        //import their settings
                        int HomeworkImported = CurrentUser.TeacherImportStudentHomework(LoadedStudent);
                        //messagebox to show what we are doing
                        MessageBox.Show(string.Format(NB.Translate("NB_TeacherSuccessImport"), HomeworkImported));
                    }
                }
                else if (extension == ".enbh")
                {
                    if (NB.GetUser() == null || CurrentUser == null)
                    {
                        MessageBox.Show(NB.Translate("NB_LoadUserFirst"));
                        return;
                    }
                    //Here we would load a homework file
                    CurrentUser.LoadHomeworkFile(filename);
                }
                else
                {
                    MessageBox.Show(NB.Translate("NB_InvalidFile"));
                    Close();
                    return; //We return here so we do not register the filename...
                }
                if (OurSettings != null) OurSettings.RegisterFileAsLoaded(filename);
            }
            catch (Exception e)
            {
                MessageBox.Show("Error: " + e.ToString());
            }
        }

        private void loadRecentFilename(object sender, EventArgs e)
        {
            //find the full filename & load that.
            ToolStripDropDownItem TSDDI = (ToolStripDropDownItem)sender;
            LoadInitialFile(TSDDI.Name);
            UpdateMenu();
        }

        private void BuilderWindow_Load(object sender, EventArgs e)
        {
            if (OurSettings.MainWindowX != -1 && OurSettings.MainWindowY != -1)
            {
                Location = new Point(OurSettings.MainWindowX, OurSettings.MainWindowY);
            }
            if (OurSettings.MainWindowHeight != -1 && OurSettings.MainWindowWidth != -1)
            {
                Height = OurSettings.MainWindowHeight;
                Width = OurSettings.MainWindowWidth;
            }

            //If we started by clicking on a using a one_click installer, load that file
            if (AppDomain.CurrentDomain.SetupInformation.ActivationArguments != null &&
                AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData != null &&
                AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData.Any())
            {
                string[] activationData = AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData;
                var uri = new Uri(activationData[0]);
                //MessageBox.Show("Trying Localpath: " + uri.LocalPath);
                //MessageBox.Show("isUNC: " + uri.IsUnc.ToString());
                //MessageBox.Show("isFile: " + uri.IsFile.ToString());

                if (uri.IsFile)
                {
                    LoadInitialFile(uri.LocalPath);
                }
            }
            if (InitialFileLoad != "") //This is set when we are installed by msi and we click a file
            {
                if (File.Exists(InitialFileLoad))
                {
                    LoadInitialFile(InitialFileLoad);
                }
            }
            else
            {
                if (OurSettings.AutoStartPuzzles)
                {
                    //We are supposed to start the puzzle-selection box
                    puzzlesToolStripMenuItem_Click(null, null);
                }
            }
        }

        private void btnHelp_Click(object sender, EventArgs e)
        {
            OpenNetHelpWindow();
            bool didsomething = myNetwork.NoteActionDone(NetTestType.HelpRequest, "", "?Button");
            if (didsomething)
            {
                UpdateForm();
                myNetwork.TestForCompletion(true);
            }
        }

        public Font GetFont()
        {
            return Font;
        }

        public void OpenNetHelpWindow()
        {
            RTFWindow rtwin = (RTFWindow)Application.OpenForms["RTFWindow"];
            if (rtwin == null)
            {
                rtwin = new RTFWindow(NB.Translate("H_Help_Key ") + myNetwork.NetTitle.GetText(), myNetwork.NetMessage.GetText(), myNetwork.NetTests);
                rtwin.Show();
                Activate();
            }
        }

        private void rbHelp1_CheckedChanged(object sender, EventArgs e)
        {
            if (processing) return;
            if (rbHelp1.Checked)
            {
                myNetwork.HintsToDisplay = NetTestVerbosity.none;
                UpdateForm();
            }
        }

        private void rbHelp2_CheckedChanged(object sender, EventArgs e)
        {
            if (processing) return;
            if (rbHelp2.Checked)
            {
                myNetwork.HintsToDisplay = NetTestVerbosity.basic;
                UpdateForm();
            }
        }

        private void rbHelp3_CheckedChanged(object sender, EventArgs e)
        {
            if (processing) return;
            if (rbHelp3.Checked)
            {
                myNetwork.HintsToDisplay = NetTestVerbosity.hints;
                UpdateForm();
            }
        }

        private void rbHelp4_CheckedChanged(object sender, EventArgs e)
        {
            if (processing) return;
            if (rbHelp4.Checked)
            {
                myNetwork.HintsToDisplay = NetTestVerbosity.full;
                UpdateForm();
            }
        }


        private void puzzlesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ListBoxWindow LBW = new ListBoxWindow();
            LBW.ShowDialog();
        }

        private void firewallsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            LoadNetworkFromResource("firewalls");
            UpdateMessages();
        }

        private void firewallsToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            LoadNetworkFromResource("firewalls");
            myNetwork.DoAllClearIPs();
            UpdateMessages();
        }

        public void SetProgress(double HowFar, double total)
        {
            int max = (int)(total * 100);
            myProgressBar.Maximum = max;
            int distance = (int)(HowFar * 100);
            if (distance > max) distance = max;
            myProgressBar.Value = distance;
        }

        private void changeLanguageToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DialogResult answer = MessageBox.Show(NB.Translate("NB_ChngLngClose"), NB.Translate("NB_ChngLngSure"), MessageBoxButtons.YesNoCancel);
            if (answer == System.Windows.Forms.DialogResult.Yes)
            {
                OurSettings.LanguageHasBeenChosen = false; //So we choose the language on restart
                                                           //System.Diagnostics.Process.Start(Application.ExecutablePath); // to start new instance of application
                this.Close(); //to turn off current app
            }
        }

        private void cbViewTitles_CheckedChanged(object sender, EventArgs e)
        {
            if (!processing)
            {
                //myNetwork.ShowLabelsHere = cbViewTitles.Checked;
                bool didsomething = myNetwork.NoteActionDone(NetTestType.HelpRequest, "", "ViewButton");
                if (didsomething)
                {
                    UpdateForm();
                    myNetwork.TestForCompletion(true);
                }
                UpdateVisuals();
            }
        }

        private void BuilderWindow_Shown(object sender, EventArgs e)
        {
            //Console.WriteLine(this.DesktopLocation.X);
            //Console.WriteLine(Screen.FromControl(this).WorkingArea.ToString());
            int x = this.DesktopLocation.X;
            int y = this.DesktopLocation.Y;

            if (x + this.Width > Screen.FromControl(this).WorkingArea.X)
                x = Screen.FromControl(this).WorkingArea.X - this.Width;
            if (x < 0) x = 0;
            if (x - 30 > Screen.FromControl(this).WorkingArea.Width)
                x = 100;

            if (y + this.Height > Screen.FromControl(this).WorkingArea.Y)
                y = Screen.FromControl(this).WorkingArea.Y - this.Height;
            if (y < 0) y = 0;
            if (y - 30 > Screen.FromControl(this).WorkingArea.Height)
                y = 100;

            this.DesktopLocation = new Point(x, y);
        }

        private void BuilderWindow_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Escape)
            {
                ItemsSelected.Clear();
                pbNetworkView.Image = null;
                UpdateVisuals();
            }
        }

        private void classSetupToolStripMenuItem_Click(object sender, EventArgs e)
        {
            PersonProfileForm PPF = new PersonProfileForm();
            CurrentUser = PPF.Edit();
            UpdateMenu();
        }

        private void profileToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (CurrentUser == null) return;
            PersonProfileForm PPF = new PersonProfileForm(CurrentUser);
            CurrentUser = PPF.Edit();
            UpdateMenu();
        }

        private void addToClassworkToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (CurrentUser == null) return;
            if (!CurrentUser.isAdmin) return;

            PersonProfileForm PPF = new PersonProfileForm(CurrentUser);
            CurrentUser = PPF.AddSchoolwork(myNetwork);
            UpdateMenu();

        }

        private void updateClassworkToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (CurrentUser == null) return;
            if (!CurrentUser.isAdmin) return;

            SchoolworkClass SC = myNetwork.WhatFrom;
            if (SC == null) return;

            SC.theProject = myNetwork.Clone();

            PersonProfileForm PPF = new PersonProfileForm(CurrentUser);
            CurrentUser = PPF.Edit();
            UpdateMenu();
        }

        public void SubmitHomework()
        {
            if (myNetwork.WhatFrom == null) return; //We cannot submit it

            if (CurrentUser == null) return;  //We need to have a user or we will blow up
            if (CurrentUser.isAdmin) return;  //Admins should not submit

            PersonProfileForm PPF = new PersonProfileForm(CurrentUser);
            CurrentUser = PPF.SubmitSchoolwork(myNetwork);
            UpdateMenu();
        }

        private void submitHomeworkToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SubmitHomework();
        }


        public void MarkAsGraded()
        {
            if (myNetwork.WhatFrom == null) return; //We cannot submit it

            if (CurrentUser == null) return;  //We need to have a user or we will blow up
            if (!CurrentUser.isAdmin) return;  //Only Admin can grade it

            myNetwork.WhatFrom.IsGraded = true;

            ReturnToProfile();
        }

        private void markAsGradedToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MarkAsGraded();
        }

        public void ReturnToProfile()
        {
            if (CurrentUser == null) return;  //We need to have a user or we will blow up
            PersonProfileForm PPF = new PersonProfileForm(CurrentUser);
            PPF.Edit();
            UpdateMenu();
        }

        private void logoutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (CurrentUser == null) return; //Nobody to logout

            DialogResult answer = MessageBox.Show(NB.Translate("NB_Logout"), NB.Translate("NB_Logout"), MessageBoxButtons.YesNoCancel);
            if (answer != DialogResult.Yes) return;

            //Save current user
            CurrentUser.Save(true); //Save it and rotate it

            //Get rid of the current project.  This way we keep them from logging out, and then exporting the homework
            PrepForLoad();

            //set current user to null
            CurrentUser = null;

            //rebuild menu
            UpdateMenu();
        }

        public Network GetNetwork()
        {
            if (InvisibleNetwork != null) return InvisibleNetwork;
            return myNetwork;
        }

        public void RegisterInvisibleNet(Network toRegister)
        {
            InvisibleNetwork = toRegister;
        }

        public void UnregisterInvisibleNet()
        {
            InvisibleNetwork = null;
        }
        public bool ProcessingInvisibleNet()
        {
            if (InvisibleNetwork == null) return false;
            return true;
        }

        //change how we view captions
        private void btnCaptions_Click(object sender, EventArgs e)
        {
            //we toggle the next
            int tmp = (int)myNetwork.ShowLabelsHere;
            tmp++;
            if (tmp >= Enum.GetNames(typeof(CaptionType)).Length)
                tmp = 0;
            myNetwork.ShowLabelsHere = (CaptionType)tmp;

            //For help
            bool didsomething = myNetwork.NoteActionDone(NetTestType.HelpRequest, "", "ViewButton");
            if (didsomething)
            {
                UpdateForm();
                myNetwork.TestForCompletion(true);
            }

            UpdateVisuals();
        }

        #region Random Map Stuff
        private void randomToolStripMenuItem_Click(object sender, EventArgs e)
        {
            GenerateARandomMap();
        }

        private void GenerateARandomMap()
        {
            RandomPuzzleChooser RPC = new RandomPuzzleChooser(OurSettings);
            RPC.ShowDialog();
            if (RPC.Canceled) return;
            LoadSolvedRandomMap(RPC.Filename, RPC.IsResource, RPC.Difficulty);
        }

        private void LoadSolvedRandomMap(string what, bool FromResource, int difficulty)
        {
            if (FromResource)
                LoadSolvedResource(what);
            else
                LoadInitialFile(what);

            myNetwork.StartingHelpLevel = NetTestVerbosity.full;
            myNetwork.HintsToDisplay = NetTestVerbosity.full;
            myNetwork.IsRandomNetwork = true;
            myNetwork.PuzzleIsSolved = false;
            myNetwork.NonVisualDoDHCPOnAll();
            List<TraversalClass> TraversalCollection = new List<TraversalClass>();

            //Choose five sets of items from the network
            List<string> Devices = NB.Randomize<string>(myNetwork.GetHostnames());
            int count = 0;
            while (Devices.Count > 2 && count < 5)
            {
                TraversalClass tc = myNetwork.NonVisualPingOneHost(Devices[0], Devices[1]);
                if (tc != null)
                    TraversalCollection.Add(tc);
                Devices.RemoveAt(1);
                Devices.RemoveAt(0);
                count++;
            }

            TraversalCollection.Sort((a, b) => b.Count.CompareTo(a.Count));

            List<HowToBreak> BreakList = new List<HowToBreak>() { };
            foreach (HowToBreak one in Enum.GetValues(typeof(HowToBreak)))
                BreakList.Add(one);
            count = 0;
            int HowHard = 0;
            int TraversalIndex = 0;
            while (HowHard < difficulty && count < 10)
            {
                //loop through the traversalinfos
                //randomly choose a way to break it
                BreakList = NB.Randomize<HowToBreak>(BreakList);
                HowHard += myNetwork.BreakNetworkPath(TraversalCollection[TraversalIndex], BreakList[0]);
                count++;
                TraversalIndex++;
                if (TraversalIndex >= TraversalCollection.Count)
                    TraversalIndex = 0; //loop back to the beginning
            }

            //for (int i = 0; i < TraversalCollection.Count; i++)
            //{
            //    Console.WriteLine(i + " " + TraversalCollection[i].Source());
            //    Console.WriteLine(i + " " + TraversalCollection[i].Destination());
            //}
            //if (TraversalCollection.Count > 0)
            //{
            //    TraversalCollection[0].DumpPath();
            //}

            myNetwork.OptionShowLabels = CaptionType.host;
            myNetwork.ShowLabelsHere = CaptionType.host;
            //If we broke the wireless, show as disconnected.
            myNetwork.DoAllVerifyLinks();
            myNetwork.DoAllAutoJoin();

            myNetwork.ClearMessages();
            myNetwork.DoAllClearDHCP();

            UpdateForm();
            UpdateMessages();
        }


        #endregion Random Map Stuff

#region network replay stuff
        public void replayNetwork(string NetworkName, int delay_between, int Countdown=-1)
        {
            //Prepare for replay
            //  reset to original map
            //  Go through each step and do the actions again in order
            NBSettings ourSettings = NB.GetSettings();
            if (OurSettings == null) return; //nothing to do
            if (OurSettings.ReplayMode == false) return; //We should never be here if we are false.

            ActionCollection actions = OurSettings.GetUserActionCollection();
            if (actions == null) return; //nothing to do

            //Find the replay
            NetworkAction replay = actions.FindAction(NetworkName);
            if (replay == null) return; //No replay for this network

            //Loading the network automatically registers it as the current replay
            LoadNetworkFromResource(NetworkName, true);

            if(Countdown >=0)
            {
                Text = "(" + Countdown + ")  " + Text; //How many more to do
            }
                        
            //Make a boolean that says we are in a replaying state
            //make an index that shows the index we are to replay
            //make a time for when the next replay happens (.5 sec from now or after all packets are gone)
            //  On tick.  If we are in replay mode.
            //  Check to see if we need to replay an action
            //  If so, do it.
            //  If not, keep ticking
            //Disable menuitems & right-click if in replay mode
            myNetwork.ReplayInProgress = true;
            myNetwork.NextReplayIndex = 0;
            myNetwork.NextReplayAction = DateTime.UtcNow.AddMilliseconds(delay_between);

            //Now we need to process it.
            NB.RegisterInvisibleNetwork(myNetwork);
            //while we have actions to do.
            while (myNetwork.ReplayInProgress)
            {
                myNetwork.Tick(true);
                myNetwork.NonVisualProcessPacketsMultipleTimes();
                myNetwork.TestForCompletion(false); //Just in case it needs to be tested
            }
            NB.UnregisterInvisibleNetwork();
        }

        private void replayToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //Prepare for replay
            //  reset to original map
            //  Go through each step and do the actions again in order
            NBSettings ourSettings = NB.GetSettings();
            if (OurSettings == null) return; //nothing to do
            if (OurSettings.ReplayMode == false) return; //We should never be here if we are false.

            ActionCollection actions = OurSettings.GetUserActionCollection();
            if (actions == null) return; //nothing to do

            if (actions.GetNet == null) return; //Nothing to do
            //If we get here, we have a valid network in the current state.

            ChangeToPastState(actions.GetNet);
            //Make a boolean that says we are in a replaying state
            //make an index that shows the index we are to replay
            //make a time for when the next replay happens (.5 sec from now or after all packets are gone)
            //  On tick.  If we are in replay mode.
            //  Check to see if we need to replay an action
            //  If so, do it.
            //  If not, keep ticking
            //Disable menuitems & right-click if in replay mode
            myNetwork.ReplayInProgress = true;
            myNetwork.NextReplayIndex = 0;
            myNetwork.NextReplayAction = DateTime.UtcNow.AddMilliseconds(NB.MillisecondsBetweenReplays);
        }

        private void fileToolStripMenuItem_DropDownOpening(object sender, EventArgs e)
        {
            NBSettings ourSettings = NB.GetSettings();
            replayToolStripMenuItem.Visible = false;
            storeReplayToolStripMenuItem.Visible = false;
            saveReplayToolStripMenuItem.Visible = false;
            if (OurSettings.ReplayMode == false && ModifierKeys == Keys.Control)
            {
                if(CurrentUser == null || CurrentUser.isAdmin)
                    OurSettings.LoadReplays(); //Only do this if we are an admin
            }

            if (OurSettings != null && OurSettings.ReplayMode)
            {
                forgetReplayStatusesToolStripMenuItem.Visible = true;
                ActionCollection AC = OurSettings.GetUserActionCollection();
                if (AC != null)
                {
                    if (AC.GetActionCount > 0)
                        replayToolStripMenuItem.Visible = true; //Only visible if we have something to replay
                    if (AC.CurrentNeedsStoring && AC.GetActionCount > 0)
                        storeReplayToolStripMenuItem.Visible = true;
                    if (AC.HasUnsavedChanges)
                        saveReplayToolStripMenuItem.Visible = true;
                }
            }
        }

        void StoreReplay()
        {
            NBSettings ourSettings = NB.GetSettings();
            if (OurSettings != null && OurSettings.ReplayMode)
            {
                ActionCollection AC = OurSettings.GetUserActionCollection();
                if (AC.CurrentNeedsStoring)
                {
                    AC.PushActionToList();
                }
            }
        }

        private void storeReplayToolStripMenuItem_Click(object sender, EventArgs e)
        {
            StoreReplay();
        }

        void SaveReplayFile()
        {
            NBSettings ourSettings = NB.GetSettings();
            if (OurSettings != null && OurSettings.ReplayMode)
            {
                ActionCollection AC = OurSettings.GetUserActionCollection();
                if (AC.HasUnsavedChanges)
                {
                    ourSettings.SaveActions();
                }
            }
        }


        private void saveReplayToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveReplayFile();
        }

        private void regressionTestingToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ListBoxWindow LBW = new ListBoxWindow(null, LBContents.regressiontest);
            //We want to show dialog, but it needs to go to the background.  After that,
            //It returns from the show dialog.  So we need to loop continuously until
            //It is completed.
            DialogResult WhatHappened = DialogResult.Retry;
            while (!LBW.ClosingRegression)
            {
                WhatHappened = LBW.ShowDialog();
            }
        }

        #endregion

        private void samplesToolStripMenuItem_DropDownOpening(object sender, EventArgs e)
        {
            if (OurSettings != null && OurSettings.ReplayMode)
            {
                regressionTestingToolStripMenuItem.Visible = true;
            }
            else
            {
                regressionTestingToolStripMenuItem.Visible = false;
            }
        }

        private void forgetReplayStatusesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OurSettings.ClearReplayStatus();
        }
    }
}