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


namespace EduNetworkBuilder
{
    public partial class ListBoxWindow : Form
    {
        protected LBContents MyMode = LBContents.messages;
        protected DebugLevel WhatToDisplay = DebugLevel.info; //used when viewing packet-messages
        NetworkDevice myNetDevice;
        PacketMessage myPacketMessage;
        int EditableCount = -1;
        bool processing = false;
        string FilterString = "";

        /// <summary>
        /// Instantiate a ListBoxWindow for use in choosing a network to load
        /// </summary>
        public ListBoxWindow()
        {
            InitializeComponent();
            LanguagifyComponents();
            MyMode = LBContents.puzzles;

            UpdateForm();
            CheckBox newCB;
            btnAdd.Visible = false;
            int count = 0;
            lblInstructions.Text = NB.Translate("LBW_LBWFilter");
            panelCheckboxes.SuspendLayout();
            string SelectedTag = GetSelectedTag();
            tbSearchBox.Visible = true;
            if (SelectedTag == NB.Translate("_All"))
                Text = Text + NB.Translate("_AllS");
            foreach (string str in NB.GetPuzzleTags())
            {
                newCB = AddCheckBox(count, str);
                if (str == SelectedTag || (SelectedTag == "ALL" && Regex.IsMatch(str,"Level")))
                {
                    newCB.Checked = true; //The first level with an unsolved puzzle starts checked
                }
                else
                {
                    newCB.Checked = false;
                }
                count++;
            }
            panelCheckboxes.ResumeLayout();
            btnOK.Text = NB.Translate("_Load");
            btnAdd.Text = NB.Translate("_Cancel");
            btnAdd.Visible = true;
            cbLoadPuzzlesAtStart.Checked = Properties.Settings.Default.AutoStartPuzzles;            
            UpdateForm();
        }

        /// <summary>
        /// We are doing a routing table or dhcp.  We pass it the device and pull the data from that
        /// </summary>
        /// <param name="MasterDevice">The master device to edit/view the routing table of</param>
        public ListBoxWindow(NetworkDevice MasterDevice, LBContents mode)
        {
            InitializeComponent();
            LanguagifyComponents();
            tbSearchBox.Visible = false;
            if (mode == LBContents.routes)
            {
                MyMode = LBContents.routes;
                myNetDevice = MasterDevice;
                lblInstructions.Text = NB.Translate("LBW_LBWDblClckRout");
                lbWindowData.Font = new System.Drawing.Font("Courier New", 8);
                btnAdd.Visible = true;
            }
            if (mode == LBContents.dhcp)
            {
                MyMode = LBContents.dhcp;
                myNetDevice = MasterDevice;
                lblInstructions.Text = NB.Translate("LBW_LBWDblClckIf");
                lbWindowData.Font = new System.Drawing.Font("Courier New", 8);
                btnAdd.Visible = false;
            }
            UpdateForm();
        }

        /// <summary>
        /// We are doing a packet message detail look.   
        /// </summary>
        /// <param name="Messages">The packet message to look at</param>
        public ListBoxWindow(PacketMessage Messages)
        {
            InitializeComponent();
            LanguagifyComponents();
            MyMode = LBContents.messages;
            myPacketMessage = Messages;
            UpdateForm();
            btnAdd.Visible = false;
            int count=0;
            lblInstructions.Text = NB.Translate("LBW_LBWDetail");
            panelCheckboxes.SuspendLayout();
            foreach (string str in Enum.GetNames(typeof(DebugLevel)))
            {
                AddCheckBox(count, str);
                count++;
            }
            panelCheckboxes.ResumeLayout();
            UpdateChecked();
        }

        private void LanguagifyComponents()
        {
            Text = NB.Translate("_OK");
            Text = NB.Translate("LBW_lblInstructions");
            Text = NB.Translate("LBW_btnAdd");
            Text = NB.Translate("LBW_cbLoadPuzzlesAtStart");
            Text = NB.Translate("LBW_btnReset");
            Text = NB.Translate("LBW_Form");
        }

        private CheckBox AddCheckBox(int count, string name)
        {
            int myY = 1;
            int myX = 1;
            int cdwidth = 70;
            int cdHeight = 20;
            int divisor = panelCheckboxes.Width / cdwidth;
            myX = (cdwidth * count) % (divisor * cdwidth);
            myY = ((cdwidth * count) / (divisor * cdwidth)) * cdHeight;
            CheckBox newCB = new CheckBox();
            newCB.Text = name;
            Point mylocation = new Point(myX, myY);
            newCB.AutoSize = true;
            newCB.Name = "checkBox" + count.ToString();
            newCB.Size = new System.Drawing.Size(98, 21);
            newCB.TabIndex = count;
            newCB.UseVisualStyleBackColor = true;
            newCB.Location = mylocation;            
            newCB.CheckedChanged += genericCheckmarkChange;
            panelCheckboxes.Controls.Add(newCB);
            return newCB;
        }

        private string GetSelectedTag()
        {
            if (Properties.Settings.Default.ScoreList == null)
                Properties.Settings.Default.ScoreList = new System.Collections.Specialized.StringCollection();
            PuzzleInfo PI;
            string first = "";

            string OriginalChoice = Properties.Settings.Default.ProcessingLevel;
            if(OriginalChoice != null)
            {
                if (NB.PuzzleLevelHasUnsolved(OriginalChoice))
                    return OriginalChoice;
            }

            foreach (string str in NB.GetPuzzleNames())
            {
                if(!Properties.Settings.Default.ScoreList.Contains(str))
                {
                    PI = NB.GetPuzzleInfoFromName(str);
                    first = "Level_" + PI.Level;
                    break;
                }
            }
            if (first != "")
                return first;
            return NB.Translate("_All");
        }

        private void UpdateForm()
        {
            int selectedIndex = lbWindowData.SelectedIndex;
            string selected = "";
            if (lbWindowData.SelectedIndex != -1)
                selected = lbWindowData.Items[lbWindowData.SelectedIndex].ToString();
            lbWindowData.Items.Clear();
            cbLoadPuzzlesAtStart.Visible = false;
            btnReset.Visible = false;
            List<string> itemstrings = new List<string>();
            if (MyMode == LBContents.messages)
            {
                itemstrings.AddRange(myPacketMessage.GetMessagesSummary());
                itemstrings.AddRange(myPacketMessage.GetMessagesLike(WhatToDisplay));
                foreach (string str in itemstrings)
                {
                    lbWindowData.Items.Add(str);
                }
            }
            if(MyMode == LBContents.routes)
            {
                itemstrings.Add(NB.Translate("LBW_UpdateFormStatRout"));
                itemstrings.AddRange(myNetDevice.DeviceRouteStrings());
                EditableCount = itemstrings.Count();
                itemstrings.Add(NB.Translate("LBW_UpdateFormNICRout"));
                itemstrings.AddRange(myNetDevice.NICRouteStrings());
                foreach (string str in itemstrings)
                {
                    lbWindowData.Items.Add(str);
                }
            }
            if (MyMode == LBContents.dhcp)
            {
                myNetDevice.CheckDHCPRangesAgainstInterfaces();
                itemstrings.AddRange(myNetDevice.DHCPStrings());
                foreach (string str in itemstrings)
                {
                    lbWindowData.Items.Add(str);
                }
            }
            if (MyMode == LBContents.puzzles)
            {
                cbLoadPuzzlesAtStart.Visible = true;
                btnReset.Visible = true;
                PuzzleInfo pi;
                if (Properties.Settings.Default.ScoreList == null)
                    Properties.Settings.Default.ScoreList = new System.Collections.Specialized.StringCollection();
                string shown_name;
                List<string> Puzzles = NB.GetPuzzleNames();
                if (Puzzles == null) return;
                foreach (string str in Puzzles)
                {
                    if (FilterString == "")
                    {
                        pi = NB.GetPuzzleInfoFromName(str);
                        shown_name = pi.PuzzleName;
                        if (Properties.Settings.Default.ScoreList.Contains(str))
                            shown_name = "* " + shown_name;
                        foreach (string tag in pi.PuzzleTags)
                        {
                            if (isChecked(tag))
                            {
                                lbWindowData.Items.Add(shown_name);
                                break;
                            }
                        }
                    }else
                    {
                        //We are filtering stuff
                        pi = NB.GetPuzzleInfoFromName(str);
                        shown_name = pi.PuzzleName;
                        bool added = false;
                        string localFilter = ".*" + FilterString + ".*";
                        if (Properties.Settings.Default.ScoreList.Contains(str))
                            shown_name = "* " + shown_name;
                        if (!added && pi.PuzzleName != null && Regex.IsMatch(pi.PuzzleName, localFilter, RegexOptions.IgnoreCase))
                        {
                            added = true;
                            lbWindowData.Items.Add(shown_name);
                        }
                        if (!added && pi.PuzzleDescription!= null && Regex.IsMatch(pi.PuzzleDescription, localFilter, RegexOptions.IgnoreCase))
                        {
                            added = true;
                            lbWindowData.Items.Add(shown_name);
                        }
                        if (!added && pi.PuzzleTitle != null && Regex.IsMatch(pi.PuzzleTitle, localFilter,RegexOptions.IgnoreCase))
                        {
                            added = true;
                            lbWindowData.Items.Add(shown_name);
                        }
                        foreach (string tag in pi.PuzzleTags)
                        {
                            if (!added && pi.PuzzleTitle != null && Regex.IsMatch(tag, localFilter, RegexOptions.IgnoreCase))
                            {
                                lbWindowData.Items.Add(shown_name);
                                break;
                            }
                        }
                    }
                }
                if(selected != null && selected != "")
                {
                    if (lbWindowData.Items.Contains(selected))
                        lbWindowData.SelectedItem = selected;
                }
                if(lbWindowData.SelectedIndex != -1)
                {
                    btnOK.Enabled = true;
                }
                else
                {
                    btnOK.Enabled = false;
                }
            }
        }

        private void btnOK_Click(object sender, EventArgs e)
        {
            if (MyMode == LBContents.puzzles && lbWindowData.SelectedItem != null)
            {
                string TheName = lbWindowData.SelectedItem.ToString();
                TheName = Regex.Replace(TheName, @"^\* ", "");
                Visible = false;
                BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"];
                if (myWin == null)
                {
                    myWin.Activate();
                }
                if(Properties.Settings.Default.AutoStartPuzzles != cbLoadPuzzlesAtStart.Checked)
                {
                    Properties.Settings.Default.AutoStartPuzzles = cbLoadPuzzlesAtStart.Checked;
                    Properties.Settings.Default.Save();
                }
                if (lbWindowData.SelectedItem != null)
                    NB.LoadNetworkFromResource(TheName);
            }
            Close();
        }

        /// <summary>
        /// The checkmark was changed.  Tally up everything
        /// </summary>
        /// <param name="sender">The checkmark that changed</param>
        /// <param name="e"></param>
        private void genericCheckmarkChange(object sender, EventArgs e)
        {
            if (processing) return;
            CheckBox mybox = (CheckBox)sender;
            if (MyMode == LBContents.messages)
            {
                if (mybox.Checked)
                {
                    WhatToDisplay = WhatToDisplay | NB.ParseEnum<DebugLevel>(mybox.Text);
                }
                else
                {
                    WhatToDisplay = WhatToDisplay ^ NB.ParseEnum<DebugLevel>(mybox.Text);
                }
            }
            UpdateChecked();
        }

        private bool isChecked(string Name)
        {            
            foreach (Control mycontrol in panelCheckboxes.Controls)
            {
                //pull out the name
                CheckBox cb = (CheckBox)mycontrol;
                //make an enum.  See if that is set.  If so, mark it as checked
                if(cb.Text.ToLower() == Name.ToLower())
                {
                    return cb.Checked;
                }
            }
            return false;
        }

        private void UpdateChecked()
        {
            processing = true;
            DebugLevel toFind;
            int mycount = 0;
            string labelname = "";
            if (MyMode == LBContents.puzzles)
            {
                foreach (Control mycontrol in panelCheckboxes.Controls)
                {
                    //pull out the name
                    CheckBox cb = (CheckBox)mycontrol;
                    //make an enum.  See if that is set.  If so, mark it as checked
                    if (cb.Checked)
                    {
                        mycount++;
                        labelname = mycontrol.Text;
                    }
                }
                if (mycount == 1)
                {
                    //We only have one item checked.  Store this value for later
                    Properties.Settings.Default.ProcessingLevel = labelname;
                    Properties.Settings.Default.Save();
                }
            }
            if (MyMode == LBContents.messages)
            {
                foreach (Control mycontrol in panelCheckboxes.Controls)
                {
                    //pull out the name
                    CheckBox cb = (CheckBox)mycontrol;
                    //make an enum.  See if that is set.  If so, mark it as checked
                    toFind = NB.ParseEnum<DebugLevel>(mycontrol.Text);
                    if ((toFind & WhatToDisplay) == toFind)
                    {
                        cb.Checked = true;
                        labelname = mycontrol.Text;
                        mycount++;
                    }
                    else    //If not, mark it as not checked.
                    {
                        cb.Checked = false;
                    }
                }
            }
            processing=false;
            UpdateForm();
        }

        private void btnAdd_Click(object sender, EventArgs e)
        {
            if (MyMode == LBContents.routes)
            {
                AddRoute();
            }
            if(MyMode == LBContents.puzzles)
            {
                if (Properties.Settings.Default.AutoStartPuzzles != cbLoadPuzzlesAtStart.Checked)
                {
                    Properties.Settings.Default.AutoStartPuzzles = cbLoadPuzzlesAtStart.Checked;
                    Properties.Settings.Default.Save();
                }
                Close();
            }
        }
        private void AddRoute()
        {
            IPAddress newip = new IPAddress(NB.ZeroIPString, NB.ZeroIPString, NB.ZeroIPString);
            newip.Edit(myNetDevice, this, NB.Translate("LBW_AddRouteCreate"));
            myNetDevice.AddRoute(newip);
            UpdateForm();
        }

        private void lbWindowData_DoubleClick(object sender, EventArgs e)
        {
            
            if (MyMode == LBContents.routes)
            {
                if (lbWindowData.SelectedIndex >= EditableCount) return;
                if (lbWindowData.SelectedIndex < 1) return;
                //we always subtract 1 since we have added one line of comment to the list
                myNetDevice.EditRoute(lbWindowData.SelectedIndex - 1, this);
            }
            if(MyMode == LBContents.dhcp)
            {
                //We always add one since we are skipping the loopback device
                myNetDevice.EditDHCP(lbWindowData.SelectedIndex + 1, this);
            }
            if (MyMode == LBContents.puzzles)
            {
                //Just like pressing the OK button.   We load the map
                btnOK_Click(sender, e);
            }
            UpdateForm();
        }
        private void lbWindowData_Edit_Click(object sender, EventArgs e)
        {
            lbWindowData_DoubleClick(sender, e);
        }
        private void lbWindowData_Delete_Click(object sender, EventArgs e)
        {
            if (MyMode == LBContents.routes)
            {
                if (lbWindowData.SelectedIndex >= EditableCount) return;
                if (lbWindowData.SelectedIndex < 1) return;
                //we always subtract 1 since we have added one line of comment to the list
                myNetDevice.DeleteRoute(lbWindowData.SelectedIndex - 1);
            }
            UpdateForm();
        }
        private void lbWindowData_RightMouseUp(object sender, MouseEventArgs e)
        {
            int index=0;
            if(MyMode == LBContents.routes)
            {
                if (lbWindowData.ContextMenuStrip == null)
                {
                    lbWindowData.ContextMenuStrip = new ContextMenuStrip();
                }
                lbWindowData.ContextMenuStrip.Items.Clear();
                lbWindowData.ContextMenuStrip.Items.Add(NB.Translate("_Edit"));
                lbWindowData.ContextMenuStrip.Items[index++].Click += lbWindowData_Edit_Click;
                lbWindowData.ContextMenuStrip.Items.Add(NB.Translate("_Delete"));
                lbWindowData.ContextMenuStrip.Items[index++].Click += lbWindowData_Delete_Click;
            }
        }
        private void lbWindowData_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Right)
            {
                lbWindowData_RightMouseUp(sender, e);
                return;
            }
            else
            {
                if(MyMode == LBContents.puzzles)
                {
                    UpdateForm();
                }
            }
        }

        private void btnReset_Click(object sender, EventArgs e)
        {
            if (Properties.Settings.Default.ScoreList == null)
                Properties.Settings.Default.ScoreList = new System.Collections.Specialized.StringCollection();
            DialogResult answer = MessageBox.Show(NB.Translate("LBW_btnResetYouSure"), NB.Translate("LBW_btnResetForget"), MessageBoxButtons.YesNo);
            if (answer == System.Windows.Forms.DialogResult.Yes)
            {
                Properties.Settings.Default.ScoreList.Clear();
                Properties.Settings.Default.Save();
                UpdateForm();
            }
        }

        private void tbSearchBox_TextChanged(object sender, EventArgs e)
        {
            //If there are more than 2 characters, then we start to see if we can filter it
            if (tbSearchBox.Text.Length > 2)
            {
                //Now we filter the results
                FilterString = tbSearchBox.Text;
                UpdateForm();
            }
            else
            {
                FilterString = "";
                UpdateForm();
            }
        }
    }
}
