using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using System.IO;
using System.Globalization;
using NotepadEnhanced.AppState;
using NotepadEnhanced.GUI.Controls;
using NotepadEnhanced.GUI.Controls.Panels;
using System.ComponentModel;
using System.Diagnostics;
using System.Collections.ObjectModel;
using NotepadEnhanced.Helpers;
using System.Net;
using NotepadEnhanced.Localization;
using NotepadEnhanced.Refactexing;
using Resources = NotepadEnhanced.Properties.Resources;

namespace NotepadEnhanced.GUI.Forms
{
    public partial class MainForm : Form
    {
        #region Global Declarations
        // The amount of time required for the app to idle before prompting to add tabs
        const int _IDLE_TIME_BEFORE_PROMPT = 15;
        private uint _ticks;
        private string _lastFindTerm = string.Empty;
        private Printing _printing;
        private readonly SystemTrayIcon _trayIcon;
        // I decided to keep a reference to each panel global so that I dont have to do look ups
        // for them. The values for these members are only allocated when needed
        private FindPanel _pnlFind;
        private GotoPanel _pnlGoto;
        private ReplacePanel _pnlReplace;
        private DocInfoPanel _pnlDocumentInfo;
        private PromptButton _btnPrompt;
        /// <summary>
        /// Shortcut to Settings
        /// </summary>
        private readonly UserSettings Settings = UserSettings.Instance;
        #endregion

        #region MainForm
        public MainForm()
        {
            InitializeComponent();
            this.SuspendLayout(); // Resume layout OnLoad
            //tabControl.ShowToolTips = true;
            _trayIcon = new SystemTrayIcon(this);

            LoadLastSettings();
            tabControl.BringToFront();
            UpdateControlAbilitys();
        }

        private void Generic_MouseMove(object sender, MouseEventArgs e)
        {
            if (tsmiFullscreen.Checked)
                mainMenu.Visible = (e.Y < 5);
        }

        protected override void OnKeyDown(KeyEventArgs e)
        {
            base.OnKeyDown(e);

            if (e.Control && e.KeyCode == Keys.L)
            {
                tsmiLineNumbers.Checked = !tsmiLineNumbers.Checked;
            }
            else if (e.KeyCode.Equals(Keys.Escape) && tsmiFullscreen.Checked)
            {
                tsmiFullscreen.Checked = false;
            }
            else if (e.KeyCode.Equals(Keys.Print))
            {
                _printing.PrintRichTextDocument(PtbActive.Document.SafeFileName);
            }
            else if (e.KeyData.Equals(Keys.Oemplus | Keys.Control))
            {
                if (tabControl.SelectedIndex.Equals(-1)) return;
                Font font = Settings.Font;
                Settings.Font = new Font(font.FontFamily, font.SizeInPoints + 2, font.Style);

                foreach (PlainTextBox plainTextBox in PlainTextBoxes)
                    plainTextBox.Font = Settings.Font;
            }
            else if (e.KeyData.Equals(Keys.OemMinus | Keys.Control))
            {
                if (Settings.Font.Size < 8 || tabControl.SelectedIndex.Equals(-1))
                    return;

                Font font = Settings.Font;
                Settings.Font = new Font(font.FontFamily, font.SizeInPoints - 2, font.Style);

                foreach (PlainTextBox plainTextBox in PlainTextBoxes)
                    plainTextBox.Font = Settings.Font;
            }
        }

        public void LoadLastSettings()
        {
            tabControl.TrackCaret = Settings.TrackSelection;
            tsmiWordWrap.Checked = Settings.WordWrap;
            tsmiStatusBar.Checked = Settings.StatusBarVisible;
            tsmiAlwaysOnTop.Checked = Settings.TopMost;
            tsmiSmartTabbing.Checked = Settings.SmartTabbing;
            tsmiLineNumbers.Checked = Settings.LineNumVisible;

            SetMultilineTabbing();

            if (Settings.FirstBoot)
            {
                SetDefaults();
            }
            else
            {
                this.Bounds = Settings.MainFormBounds;
                this.WindowState = Settings.MainFormState;
            }
        }

        /// <summary>
        /// Set program defaults for first boot
        /// </summary>
        private void SetDefaults()
        {
            this.CenterToScreen();
            Settings.MainFormBounds = this.Bounds;
            const float FONT_SIZE = 14f;

            // Preferable font verdana
            if (IsFontInstalled("Verdana"))
                Settings.Font = new Font("Verdana", FONT_SIZE, FontStyle.Regular);
            // if verdana is not installed then try tahoma
            else if (IsFontInstalled("Tahoma"))
                Settings.Font = new Font("Tahoma", FONT_SIZE, FontStyle.Regular);
            // Otherwise install a readily available font that looks ok
            else if (IsFontInstalled(FontFamily.GenericSansSerif.Name))
                Settings.Font = new Font(FontFamily.GenericSansSerif, FONT_SIZE);

            Settings.Signature = Environment.UserName;
            Settings.FirstBoot = false;
        }

        public static bool IsFontInstalled(string fontName)
        {
            using (Font testFont = new Font(fontName, 8f))
            {
                var SC = StringComparison.InvariantCultureIgnoreCase;
                return (0 == string.Compare(fontName, testFont.Name, SC));
            }
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            if (SingleInstanceBase.CmdLineArgs.Length > 0)
            {
                LoadDocuments(SingleInstanceBase.CmdLineArgs);
            }
            // Only add blank tab if no documents are loaded on startup
            else if (Settings.AddTabOnStart)
            {
                AddBlankTab();
                PtbActive.Select();
            }

            // If blank tab has been added
            if (tabControl.SelectedIndex != -1)
            {
                _printing = new Printing(PtbActive);
            }

            // Check for updates on every 5 application boot ups
            if (++Settings.BootCount >= 5)
            {
                Settings.BootCount = 0;
                UpdateChecker updateChecker = new UpdateChecker(Resources.DownloadLink, Resources.UpdateLocation);
                updateChecker.BeginChecking(true);
            }

            if (Settings.PromptToRestore && Settings.LastSession != null)
            {
                _btnPrompt = new PromptButton(tabControl);
                _btnPrompt.Click += _btnPrompt_Click;
                this.Controls.Add(_btnPrompt);
            }

            this.ResumeLayout(true);
        }

        private void _btnPrompt_Click(object sender, EventArgs e)
        {
            this.SuspendLayout();

            // Get rid of blank tab if present
            if (tabControl.TabCount > 0)
            {
                CloseSelectedTab();
            }

            if (Settings.LastSession.FilesOpen.Count > 0)
                LoadDocuments(Settings.LastSession.FilesOpen.ToArray());

            if (tabControl.TabCount > 0 && Settings.LastSession.SelectedTabIndex < tabControl.TabCount)
            {
                tsmiFind.Checked = Settings.LastSession.FindPanelOpen;
                tsmiDocumentInfo.Checked = Settings.LastSession.DocumentInfoPanelOpen;
                tsmiGoto.Checked = Settings.LastSession.GotoPanelOpen;
                tsmiReplace.Checked = Settings.LastSession.ReplacePanelOpen;

                // Do not reselect tab or it will be unselected
                if (!tabControl.SelectedIndex.Equals(Settings.LastSession.SelectedTabIndex))
                    tabControl.SelectedIndex = Settings.LastSession.SelectedTabIndex;

                PtbActive.Select(Settings.LastSession.SelectedTextIndex, Settings.LastSession.SelectedTextLength);
            }

            this.ResumeLayout();
        }

        private void AddBlankTab()
        {
            if (!this.Text.Equals(Application.ProductName))
                this.Text = Application.ProductName;

            tmrMessage.Dispose();
            tabControl.TabPages.Add(Strings.NewDoc);
            tabControl.SelectedIndex = tabControl.TabCount - 1;
            PtbActive.Focus();
        }

        protected override void OnClosing(CancelEventArgs e)
        {
            if (Settings.PromptToRestore)
            {
                SaveCurrentSession();
            }

            base.OnClosing(e);

            int lastIndex = tabControl.SelectedIndex;
            tabControl.SelectedIndex = 0;

            //Prompt to save modified documents
            foreach (TabPage tabPage in tabControl.TabPages)
            {
                bool hasTabPages = tabControl.TabCount != 0;

                if (hasTabPages && PtbActive.Modified && PromptToSave())
                {
                    e.Cancel = true;
                    tabControl.SelectedIndex = lastIndex;
                    return;
                }

                tabControl.SelectedIndex++;
            }

            SaveFormState();
            Settings.Save();
        }

        private void SaveCurrentSession()
        {
            int selectionIndex = -1, selectionLength = -1;

            if (tabControl.TabCount > 0)
            {
                selectionIndex = PtbActive.SelectionStart;
                selectionLength = PtbActive.SelectionLength;
            }

            string lastFindTerm;

            // If find panel open use the textbox within for the last searh term
            if (_pnlFind != null)
                lastFindTerm = _pnlFind.PatternBox.Text;
            // Do the same for the replace panel
            else if (_pnlReplace != null)
                lastFindTerm = _pnlReplace.FindText;
            else
                lastFindTerm = _lastFindTerm;

            var openFiles = PlainTextBoxes.Select(t => t.Document.FileName).ToList();
            Settings.LastSession.FindPanelOpen = tsmiFind.Checked;
            Settings.LastSession.ReplacePanelOpen = tsmiReplace.Checked;
            Settings.LastSession.GotoPanelOpen = tsmiGoto.Checked;
            Settings.LastSession.DocumentInfoPanelOpen = tsmiDocumentInfo.Checked;
            Settings.LastSession.SelectedTabIndex = tabControl.SelectedIndex;
            Settings.LastSession.FilesOpen = openFiles;
            Settings.LastSession.SelectedTextLength = selectionLength;
            Settings.LastSession.SelectedTextIndex = selectionIndex;
            Settings.LastSession.FindText = lastFindTerm;
        }

        private void SaveFormState()
        {
            //Save form dimension and size for default
            Settings.MainFormState = this.WindowState;

            if (this.WindowState == FormWindowState.Normal)
                Settings.MainFormBounds = this.Bounds;
            else
                Settings.MainFormBounds = this.RestoreBounds;
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            tsmiDock.Enabled = !this.WindowState.Equals(FormWindowState.Maximized);
        }
        #endregion

        #region Main Menu
        #region File Menu
        private void tsmiFile_MouseEnter(object sender, EventArgs e)
        {
            tsmiOpenRecent.DropDownItems.Clear();

            if (Settings.RecentFilesEnabled)
            {
                foreach (string name in RecentFileQue.FileNames)
                {
                    string safeFileName = Path.GetFileName(name);

                    var menuItem = new ToolStripMenuItem
                        (safeFileName, null, btnRecentFileDropDown_Click);

                    menuItem.TextAlign = ContentAlignment.MiddleCenter;
                    menuItem.Tag = menuItem.ToolTipText = name;
                    tsmiOpenRecent.DropDownItems.Add(menuItem);
                }

                tsmiOpenRecent.Enabled = (RecentFileQue.FileNames.Count > 0);
            }
            else
            {
                tsmiOpenRecent.Enabled = false;
            }
        }

        private void tsmiAddTab_Click(object sender, EventArgs e)
        {
            AddBlankTab();
        }

        private void tsmiCloseTab_Click(object sender, EventArgs e)
        {
            CloseSelectedTab();
        }

        private void tsmiCloseAllTabs_Click(object sender, EventArgs e)
        {
            this.SuspendLayout();

            while (tabControl.TabCount > 0)
                CloseSelectedTab();

            this.ResumeLayout();
        }

        private void tmsiCloseAllButCurrent_Click(object sender, EventArgs e)
        {
            tabControl.SuspendLayout();

            TabPage activeTab = tabControl.SelectedTab;
            tabControl.SelectedIndex = 0;

            while (tabControl.TabCount > 1)
            {
                if (tabControl.SelectedTab == activeTab)
                    tabControl.SelectedIndex++;

                CloseSelectedTab();
            }

            tabControl.ResumeLayout();
        }

        private void cmsiCloseAllButCurrent_Click(object sender, EventArgs e)
        {
            tabControl.SuspendLayout();

            tabControl.SelectedIndex = 0;
            int tabIndex = (int)cmsTabPage.Tag;
            TabPage activeTab = tabControl.TabPages[tabIndex];

            while (tabControl.TabCount > 1)
            {
                if (tabControl.SelectedTab == activeTab)
                    tabControl.SelectedIndex++;

                CloseSelectedTab();
            }

            tabControl.ResumeLayout();
        }

        private void cmsiCloseThis_Click(object sender, EventArgs e)
        {
            int clickedIndex = (int)cmsTabPage.Tag;

            if (clickedIndex == tabControl.SelectedIndex)
            {
                tabControl.SelectedIndex = clickedIndex;
                CloseSelectedTab();
            }
            else
            {
                // Only restore the last selected tab if
                // closing a tab that is not the current selection
                TabPage tab = tabControl.SelectedTab;
                tabControl.SelectedIndex = clickedIndex;
                CloseSelectedTab();
                tabControl.SelectedTab = tab;
            }
        }

        private void cmsiShowInFolder_Click(object sender, EventArgs e)
        {

            int clickedIndex = (int)cmsTabPage.Tag;
            string fileName = PlainTextBoxes[clickedIndex].Document.FileName;
            // Construct argument using the select switch and the entire filepath
            // to select the file after showing in folder
            string argument = "/select, \"" + fileName + "\"";
            StartProcess("explorer.exe", argument);
        }

        private void cmsiOpenInWinNotepad_Click(object sender, EventArgs e)
        {
            int clickedIndex = (int)cmsTabPage.Tag;
            string fileName = PlainTextBoxes[clickedIndex].Document.FileName;
            StartProcess("Notepad.exe", fileName);
        }

        private void tsmiOpen_Click(object sender, EventArgs e)
        {
            using (var dlgOpenFile = new OpenFileDialog())
            {
                dlgOpenFile.Multiselect = true;
                dlgOpenFile.Filter = Strings.FilterOpenFile;
                dlgOpenFile.FilterIndex = Settings.OpenFilterIndex; // 7 is the last in the list

                if (dlgOpenFile.ShowDialog() == DialogResult.OK)
                {
                    LoadDocuments(dlgOpenFile.FileNames);
                    Settings.OpenFilterIndex = dlgOpenFile.FilterIndex;
                }
            }
        }

        private void tsmiDlWebpage_DropDownOpened(object sender, EventArgs e)
        {
            // Check to see if there is a link in the clipboard, if there is then use it
            string text = Clipboard.GetText();

            UriHostNameType nameType = Uri.CheckHostName(text);

            if (nameType != UriHostNameType.Unknown)
            {
                txtHTMLLink.Text = text;
            }

            txtHTMLLink.Focus();
            txtHTMLLink.SelectAll();
        }

        private void txtHtmlLink_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode.Equals(Keys.Enter))
            {
                e.SuppressKeyPress = true;
                e.Handled = true;
                DownloadWebpageAsync();
            }
        }

        /// <summary>
        /// Downloads a webpage with the specified link, returns an empty string
        /// if download fails
        /// </summary>
        private void DownloadWebpageAsync()
        {
            tsmiDlWebpage.Enabled = false;
            tsmiFile.HideDropDown();
            string link = StringOps.MakeUrlFriendly(txtHTMLLink.Text);
            var client = new WebClient();
            client.DownloadStringCompleted += client_DownloadStringCompleted;
            this.Cursor = Cursors.WaitCursor;

            try
            {
                client.DownloadStringAsync(new Uri(link));
            }
            catch (Exception ex)
            {
                MsgBox.Show(ex.Message);
            }
            finally
            {
                client.Dispose();
                this.Cursor = Cursors.Default;
                tsmiDlWebpage.Enabled = true;
            }
        }

        void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs args)
        {
            if (args.Error != null)
            {
                MsgBox.Show(args.Error.Message);
                return;
            }

            if (tabControl.TabCount > 0)
            {
                if (PtbActive.Document.FileName.Length != 0)
                    AddBlankTab();
            }
            else AddBlankTab();

            if (args.Result.Length > 0)
            {
                PtbActive.Text = args.Result;
                PtbActive.Text = args.Result;
                string title = StringOps.MakeStringFilenameSafe(tsmiDlWebpage.Text);
                PtbActive.Document.SafeFileName = title;
                txtHTMLLink.Clear();
            }

            tsmiDlWebpage.Enabled = true;
        }

        private void btnRecentFileDropDown_Click(object sender, EventArgs e)
        {
            string filename = ((ToolStripMenuItem)sender).Tag.ToString();
            LoadDocuments(filename);
        }

        /// <summary>
        /// Write to file with or without prompt accordingly
        /// </summary>
        private void Save()
        {
            if (PtbActive.Document.SavedOrOpened)
            {
                WriteActiveDocumentToFile();
                PtbActive.Modified = false;
                UpdateTabTextModifiedIndicator();
            }
            else
            {
                SaveAs();
            }
        }

        private void tsmiSave_Click(object sender, EventArgs e)
        {
            Save();
        }

        private void tsmiSaveAs_Click(object sender, EventArgs e)
        {
            SaveAs();
        }

        private void SaveAs()
        {
            using (var dlgSaveFile = new SaveFileDialog())
            {
                dlgSaveFile.Filter = Strings.FilterSaveFile;

                // If no safefilename and first line has little text then
                if (PtbActive.Document.SafeFileName.Equals(Strings.NewDoc) &&
                    PtbActive.TextLength > 0 && PtbActive.Lines[0].Length < 30)
                {
                    // use first line as filename
                    dlgSaveFile.FileName = StringOps.MakeStringFilenameSafe(PtbActive.Lines[0]);
                }
                else
                {
                    string title = StringOps.MakeStringFilenameSafe(PtbActive.Document.SafeFileName);
                    dlgSaveFile.FileName = title;
                }

                string ext = Path.GetExtension(PtbActive.Document.SafeFileName).ToLower();

                // if no extension specified of extension is .txt
                if (ext.Length.Equals(0) || ext.Equals(".txt"))
                {
                    dlgSaveFile.FilterIndex = 1; // txt file
                }
                else
                {
                    dlgSaveFile.FilterIndex = 2; // other file
                }

                if (dlgSaveFile.ShowDialog() == DialogResult.OK)
                {
                    PtbActive.Document.FileName = dlgSaveFile.FileName;
                    WriteActiveDocumentToFile();
                    string safeFileName = Path.GetFileName(dlgSaveFile.FileName);
                    safeFileName = StringOps.GetElipsisedText(safeFileName);
                    tabControl.SelectedTab.Text = safeFileName;

                    Settings.SaveFilterIndex = dlgSaveFile.FilterIndex;
                    PtbActive.Modified = false;

                    if (_pnlDocumentInfo != null)
                    {
                        _pnlDocumentInfo.DocumentFormat = Path.GetExtension(dlgSaveFile.FileName);
                    }

                    UpdateTabTextModifiedIndicator();
                }
            }
        }

        private void WriteActiveDocumentToFile()
        {
            PtbActive.Document.WatcherEnabled = false;
            PtbActive.ClearUndo();

            try
            {
                File.WriteAllLines(PtbActive.Document.FileName, PtbActive.Lines);
                // Display save animation
                SaveAnimation save = new SaveAnimation(this);
                save.Animate();
                PtbActive.Document.WatcherEnabled = true;
            }
            catch (Exception ex)
            {
                MsgBox.Show(ex.Message);
            }
        }

        private void tsmiPrint_Click(object sender, EventArgs e)
        {
            _printing.PrintRichTextDocument(PtbActive.Document.SafeFileName);
        }

        private void tsmiPrintPreview_Click(object sender, EventArgs e)
        {
            // Make sure the form is not "Always on top"
            bool mainFormTopMost = this.TopMost;
            this.TopMost = false;
            _printing.ShowPrintPreview();
            this.TopMost = mainFormTopMost;
        }

        private void tsmiPageSetup_Click(object sender, EventArgs e)
        {
            _printing.ShowPageSetupDialog();
        }

        private void tsmiCloseAndDelete_Click(object sender, EventArgs e)
        {
            if (PtbActive.Document.FileName.Length > 0)
            {
                DialogResult result = MsgBox.Show(Strings.MsgDeleteConfirmation,
                    MessageBoxIcon.Question, MessageBoxButtons.YesNo);

                if (result == DialogResult.Yes)
                {
                    DeleteFile(PtbActive.Document.FileName);
                    PtbActive.Modified = false;
                    CloseSelectedTab();
                }
            }
            else
            {
                CloseSelectedTab();
            }
        }

        private static void DeleteFile(string fileName)
        {
            try
            {
                if (File.Exists(fileName))
                    File.Delete(fileName);
            }
            catch (Exception ex)
            {
                MsgBox.Show(ex.Message);
            }
        }

        private void tsmiExit_Click(object sender, EventArgs e)
        {
            this.Close();
        }
        #endregion

        #region Edit Menu
        private void tsmiUndo_Click(object sender, EventArgs e)
        {
            if (PtbActive.Focused)
            {
                PtbActive.Undo();
                UpdateRedoUndoMenuItems();
            }
            else
            {
                UserControl userControl = this.ActiveControl as UserControl;

                if (userControl != null)
                {
                    TextBox textBox = userControl.ActiveControl as TextBox;
                    if (textBox != null) textBox.Undo();
                }
                else
                {
                    TextBox textBox = this.ActiveControl as TextBox;
                    if (textBox != null) textBox.Undo();
                }
            }
        }

        private void tsmiRedo_Click(object sender, EventArgs e)
        {
            if (PtbActive.Focused)
            {
                PtbActive.Redo();
                UpdateRedoUndoMenuItems();
            }
        }

        private void tsmiCut_Click(object sender, EventArgs e)
        {
            if (PtbActive.Focused)
            {
                PtbActive.Cut();
            }
            else
            {
                UserControl userControl = this.ActiveControl as UserControl;

                if (userControl != null)
                {
                    TextBox textBox = userControl.ActiveControl as TextBox;
                    if (textBox != null) textBox.Cut();
                }
                else
                {
                    TextBox textBox = this.ActiveControl as TextBox;
                    if (textBox != null) textBox.Cut();
                }
            }
        }

        private void tsmiCopy_Click(object sender, EventArgs e)
        {
            if (PtbActive.Focused)
            {
                PtbActive.Copy();
            }
            else
            {
                UserControl userControl = this.ActiveControl as UserControl;

                if (userControl != null)
                {
                    TextBox textBox = userControl.ActiveControl as TextBox;
                    if (textBox != null) textBox.Copy();
                }
                else
                {
                    TextBox textBox = this.ActiveControl as TextBox;
                    if (textBox != null) textBox.Copy();
                }
            }
        }

        private void tsmiPaste_Click(object sender, EventArgs e)
        {
            if (PtbActive.Focused)
            {
                var formats = DataFormats.GetFormat(DataFormats.Text);
                PtbActive.Modified = false;
                PtbActive.Paste(formats);
            }
            else
            {
                UserControl userControl = this.ActiveControl as UserControl;

                if (userControl != null)
                {
                    TextBox textBox = userControl.ActiveControl as TextBox;
                    if (textBox != null) textBox.Paste();
                }
                else
                {
                    TextBox textBox = this.ActiveControl as TextBox;
                    if (textBox != null) textBox.Paste();
                }
            }
        }

        private void tsmiDelete_Click(object sender, EventArgs e)
        {
            if (PtbActive.Focused)
            {
                PtbActive.SelectedText = string.Empty;
            }
            else
            {
                UserControl userControl = this.ActiveControl as UserControl;

                if (userControl != null)
                {
                    TextBox textBox = userControl.ActiveControl as TextBox;
                    if (textBox != null) textBox.SelectedText = string.Empty;
                }
                else
                {
                    TextBox textBox = this.ActiveControl as TextBox;
                    if (textBox != null) textBox.SelectedText = string.Empty;
                }
            }
        }

        private void tsmiFind_CheckedChanged(object sender, EventArgs e)
        {
            if (tsmiFind.Checked)
            {
                _pnlFind = new FindPanel(this);

                if (PtbActive.SelectedText.Length > 0)
                {
                    _pnlFind.PatternBox.Text = PtbActive.SelectedText;
                }
                else
                {
                    _pnlFind.PatternBox.Text = _lastFindTerm;
                }

                _pnlFind.RelatedMenuItem = tsmiFind;
                this.Controls.Add(_pnlFind);
                _pnlFind.Show();
                _pnlFind.PatternBox.Focus();
            }
            else
            {
                _lastFindTerm = _pnlFind.PatternBox.Text;
            }
        }

        private void tsmiFindNext_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(PtbActive.LastPattern))
            {
                tsmiFind.Checked = true;
            }
            else
            {
                bool finishedSearching = PtbActive.FindNext(PtbActive.LastPattern,
                    Settings.IsFindMatchCase);

                if (finishedSearching)
                {
                    SetFindTextBoxBackColors(Program.SearchDoneColor);
                }
                else
                {
                    SetFindTextBoxBackColors(Color.FromKnownColor(KnownColor.Window));
                }
            }
        }

        private void SetFindTextBoxBackColors(Color color)
        {
            if (_pnlFind != null)
                _pnlFind.PatternBox.BackColor = color;

            if (_pnlReplace != null)
                _pnlReplace.SetFindTextBoxBackColor(color);
        }

        private void tsmiReplace_CheckedChanged(object sender, EventArgs e)
        {
            if (tsmiReplace.Checked)
            {
                _pnlReplace = new ReplacePanel(this);
                _pnlReplace.RelatedMenuItem = tsmiReplace;

                if (PtbActive.SelectedText.Length > 0)
                    _pnlReplace.FindText = PtbActive.SelectedText;
                else
                    _pnlReplace.FindText = _lastFindTerm;

                this.Controls.Add(_pnlReplace);
                _pnlReplace.BringToFront();
                tabControl.BringToFront();
                _pnlReplace.Show();
                _pnlReplace.SetTextBoxFocus();
            }

            else
            {
                _lastFindTerm = _pnlReplace.FindText;
            }
        }

        private void tsmiGoto_CheckedChanged(object sender, EventArgs e)
        {
            if (tsmiGoto.Checked)
            {
                _pnlGoto = new GotoPanel(this);
                _pnlGoto.RelatedMenuItem = tsmiGoto;
                this.Controls.Add(_pnlGoto);
                _pnlGoto.Show();
            }
        }

        private void tsmiSelectAll_Click(object sender, EventArgs e)
        {
            PtbActive.SelectAll();
        }

        private void tsmiLongDateTime_Click(object sender, EventArgs e)
        {
            PtbActive.SelectedText = DateTime.Now.ToLongDateString()
                + " " + DateTime.Now.ToLongTimeString();
        }

        private void tsmiShortDateTime_Click(object sender, EventArgs e)
        {
            PtbActive.SelectedText = DateTime.Now.ToShortDateString()
                + " " + DateTime.Now.ToShortTimeString();
        }

        private void tsmiSignature_Click(object sender, EventArgs e)
        {
            PtbActive.AppendText("\n\n" + Settings.Signature);
        }

        /// <summary>
        /// Also used to handle the enable changed event
        /// </summary>
        private void tsmiSmartTabbing_CheckedChanged(object sender, EventArgs e)
        {
            if (!tsmiSmartTabbing.Enabled)
            {
                Settings.SmartTabbing = false;
                return;
            }

            Settings.SmartTabbing = tsmiSmartTabbing.Checked;

            foreach (PlainTextBox textBox in PlainTextBoxes)
            {
                textBox.SmartTabbing = tsmiSmartTabbing.Checked;
            }
        }

        private void tsmiRegexRefactoring_Click(object sender, EventArgs e)
        {
            using (var dlgRegexRefact = new RegexRefactoringForm(PtbActive))
            {
                dlgRegexRefact.ShowDialog();
            }
        }
        #endregion

        #region View Menu
        private void tsmiStatusBar_CheckedChanged(object sender, EventArgs e)
        {
            if (tsmiStatusBar.Checked)
            {
                statusBar.Show();
                UpdateStatusBar();
                tsmiWordWrap.Checked = tsmiWordWrap.Enabled = false;
            }
            else
            {
                statusBar.Hide();
                tsmiWordWrap.Enabled = true;
            }

            Settings.StatusBarVisible = statusBar.Visible;
        }

        private void tsmiWordWrap_CheckedChanged(object sender, EventArgs e)
        {
            //Apply wordwrap to all richTextBoxes and save it as a setting
            foreach (PlainTextBox textBox in PlainTextBoxes)
            {
                textBox.WordWrap = tsmiWordWrap.Checked;
            }

            // Update the current line number strip
            for (int i = 0; i < LineNumberStrips.Count; i++)
            {
                if (i == tabControl.SelectedIndex)
                    LineNumberStrips[i].Invalidate();
            }

            if (tsmiWordWrap.Checked) statusBar.Hide();
            tsmiSmartTabbing.Enabled = !tsmiWordWrap.Checked;
            tsmiStatusBar.Enabled = !tsmiWordWrap.Checked;
            Settings.WordWrap = tsmiWordWrap.Checked;
        }

        private void tsmiLineNumbers_CheckedChanged(object sender, EventArgs e)
        {
            Settings.LineNumVisible = tsmiLineNumbers.Checked;

            foreach (TabPage tabPage in tabControl.TabPages)
            {
                if (Settings.LineNumVisible)
                {
                    var plainTextBox = (PlainTextBox)tabPage.Controls[0];
                    var lineNumberStrip = new LineNumberStrip(plainTextBox, this);
                    tabPage.Controls.Add(lineNumberStrip);
                }
                else
                {
                    tabPage.Controls.RemoveAt(1);
                }
            }
        }

        private void tsmiResetDock_Click(object sender, EventArgs e)
        {
            this.Size = new Size(700, 600);
            this.CenterToScreen();
        }

        private void tsmiDockLeft_Click(object sender, EventArgs e)
        {
            this.DockLeft();
        }

        private void tsmiDockRight_Click(object sender, EventArgs e)
        {
            this.DockRight();
        }

        private void tsmiDockTop_Click(object sender, EventArgs e)
        {
            this.DockTop();
        }

        private void tsmiDockBottom_Click(object sender, EventArgs e)
        {
            this.DockBottom();
        }

        private void tsmiFullscreen_CheckedChanged(object sender, EventArgs e)
        {
            this.SuspendLayout();

            if (tsmiFullscreen.Checked)
            {
                if (this.WindowState == FormWindowState.Maximized)
                {
                    this.WindowState = FormWindowState.Normal;
                }

                this.FormBorderStyle = FormBorderStyle.None;
                this.WindowState = FormWindowState.Maximized;
                mainMenu.Hide();
                tsmiDockLeft.Enabled = tsmiDockRight.Enabled = false;
                tsmiDockBottom.Enabled = tsmiDockTop.Enabled = false;
                tsmiResetDock.Enabled = false;
            }
            else
            {
                this.FormBorderStyle = FormBorderStyle.Sizable;
                this.WindowState = FormWindowState.Normal;
                mainMenu.Show();
                tsmiDockLeft.Enabled = tsmiDockTop.Enabled = true;
                tsmiDockRight.Enabled = tsmiDockBottom.Enabled = true;
                tsmiResetDock.Enabled = true;
            }

            this.ResumeLayout();
        }

        private void tsmiDocumentInfo_CheckedChanged(object sender, EventArgs e)
        {
            if (tsmiDocumentInfo.Checked)
            {
                _pnlDocumentInfo = new DocInfoPanel();
                _pnlDocumentInfo.RelatedMenuItem = tsmiDocumentInfo;
                this.Controls.Add(_pnlDocumentInfo);
                _pnlDocumentInfo.BringToFront();
                tabControl.BringToFront();
                UpdateDocumentInfo();
                _pnlDocumentInfo.Show();
            }
        }

        private void tsmiSettings_CheckedChanged(object sender, EventArgs e)
        {
            using (var frmSettings = new SettingsForm(this))
            {
                frmSettings.TopMost = Settings.TopMost;
                frmSettings.ShowDialog();
            }
        }

        private void tsmiShowReadingWindow_Click(object sender, EventArgs e)
        {
            this.Hide();
            var frmReadingView = new ReadingForm(PtbActive.Text);
            frmReadingView.Closed += delegate { this.Show(); };
            frmReadingView.ClientSize = new Size(Settings.ReadingWidth, 500);

            if (Settings.ReadingViewBounds.Equals(Rectangle.Empty))
            {
                frmReadingView.ClientSize = new Size(Settings.ReadingWidth, 500);
                frmReadingView.StartPosition = FormStartPosition.CenterScreen;
            }
            else
            {
                frmReadingView.DesktopBounds = Settings.ReadingViewBounds;
            }

            frmReadingView.Show();
        }

        private void tsmiMinimizeToTray_Click(object sender, EventArgs e)
        {
            _trayIcon.MinimizeToTray();
        }

        private void tsmiAlwaysOnTop_CheckedChanged(object sender, EventArgs e)
        {
            Settings.TopMost = tsmiAlwaysOnTop.Checked;
            this.TopMost = tsmiAlwaysOnTop.Checked;
        }
        #endregion

        #region Help Menu
        private void tsmiAbout_CheckedChanged(object sender, EventArgs e)
        {
            using (AboutForm frmAbout = new AboutForm())
            {
                frmAbout.TopMost = this.TopMost;
                frmAbout.ShowDialog();
            }
        }

        private void tsmiProductDoc_Click(object sender, EventArgs e)
        {
            StartProcess(Resources.DocumentationFilename);
        }

        private void tsmiUpdates_Click(object sender, EventArgs e)
        {
            tsmiUpdates.Enabled = false;
            UpdateChecker updateChecker = new UpdateChecker(Resources.DownloadLink, Resources.UpdateLocation);
            updateChecker.Completed += (s, e2) => tsmiUpdates.Enabled = true;
            updateChecker.BeginChecking(false);
        }
        #endregion
        #endregion

        #region PlainTextBox
        private void PlainTextBox_TextChanged(object sender, EventArgs e)
        {
            UpdateAllInfo();
        }

        private void PlainTextBox_MouseClick(object sender, MouseEventArgs e)
        {
            // Make sure enter key is for newlines when textbox has focus
            this.AcceptButton = null;
        }

        private void PlainTextBox_SelectionChanged(object sender, EventArgs e)
        {
            if (statusBar.Visible)
            {
                lblCurrentLine.Text = PtbActive.CurrentLine.ToString();
                lblCurrentColumn.Text = PtbActive.CurrentColumn.ToString();
            }

            if (Settings.TrackSelection)
            {
                tabControl.UpdateCaretTraker();
            }
        }

        private void PlainTextBox_DragDrop(object sender, DragEventArgs e)
        {
            // If drag content is text, insert at cursor pos
            // Otherwise append file if filedrop
            if (e.Data.GetDataPresent(DataFormats.Text))
            {
                string content = e.Data.GetData(DataFormats.Text).ToString();
                Point pos = new Point(e.X, e.Y);
                pos = PtbActive.PointToClient(pos);
                int index = PtbActive.GetCharIndexFromPosition(pos);
                PtbActive.Text = PtbActive.Text.Insert(index, content);
                PtbActive.Select(index, 0);
                PtbActive.Focus();
            }
            else
            {
                var filenames = e.Data.GetData(DataFormats.FileDrop) as string[];
                if (filenames != null) AppendFiles(filenames);
            }
        }

        private void plainTextBox_FileNameChanged(object sender, EventArgs e)
        {
            PlainTextBox box = (PlainTextBox)sender;
            tabControl.SelectedTab.ToolTipText = box.Document.FileName;
        }

        private void plainTextBox_Scroll(object sender, EventArgs e)
        {
            if (Settings.TrackSelection)
            {
                tabControl.UpdateCaretTraker();
            }
        }

        private void plainTextBox_ModifiedChanged(object sender, EventArgs e)
        {
            UpdateTabTextModifiedIndicator();
        }
        #endregion

        #region TabControl
        /// <summary>
        /// Every time a tapPage is added tot he tabControl. Add a PlainTextBox
        /// Control inside that tabPage. Also setup events for the textBox.
        /// </summary>
        private void tabControl_ControlAdded(object sender, ControlEventArgs e)
        {
            tmrMessage.Dispose();
            this.Text = Application.ProductName;
            // Only Update for the first tab as the selected index changed event
            // will not raise
            if (tabControl.TabCount.Equals(1))
            {
                UpdateControlAbilitys();
            }

            //Setup PlainTextBox control
            var plainTextBox = new PlainTextBox
                {
                    ContextMenuStrip = cmsPTB,
                    ScrollBars = RichTextBoxScrollBars.ForcedBoth,
                    Modified = false // Modified is true by defaut for some reason...
                };

            plainTextBox.TextChanged += PlainTextBox_TextChanged;
            plainTextBox.SelectionChanged += PlainTextBox_SelectionChanged;
            plainTextBox.MouseClick += PlainTextBox_MouseClick;
            plainTextBox.DragDrop += PlainTextBox_DragDrop;
            plainTextBox.VScroll += plainTextBox_Scroll;
            plainTextBox.HScroll += plainTextBox_Scroll;
            plainTextBox.Document.FileNameChanged += plainTextBox_FileNameChanged;
            plainTextBox.ModifiedChanged += plainTextBox_ModifiedChanged;

            e.Control.Controls.Add(plainTextBox);

            if (Settings.LineNumVisible)
            {
                var lineNumberStrip = new LineNumberStrip(plainTextBox, this);
                e.Control.Controls.Add(lineNumberStrip);
            }

            _printing = new Printing(PtbActive);
        }

        private void tabControl_SelectedIndexChanged(object sender, EventArgs e)
        {
            UpdateAllInfo();
            UpdateControlAbilitys();

            if (tabControl.TabCount > 0)
            {
                _printing = new Printing(PtbActive);
                PtbActive.Select();
            }
        }

        private void tabControl_MouseDown(object sender, MouseEventArgs e)
        {
            //if we right click the tab we will open up a context for that tab
            if (e.Button == MouseButtons.Right)
            {
                for (int i = 0; i < tabControl.TabCount; i++)
                {
                    if (tabControl.GetTabRect(i).Contains(e.Location))
                    {
                        cmsTabPage.Tag = i;
                        bool hasFilename = PtbActive.Document.FileName.Length > 0;
                        cmsiShowInFolder.Enabled = cmsiOpenInWinNotepad.Enabled = hasFilename;
                        cmsTabPage.Show(tabControl, e.Location);
                        return;
                    }
                }
            }
        }

        private void tabControl_MouseMove(object sender, MouseEventArgs e)
        {
            if (tsmiFullscreen.Checked)
            {
                // The smaller the number the less sensitive
                const uint SHOW_SENSITIVITY = 5;
                mainMenu.Visible = (e.Y < SHOW_SENSITIVITY);
            }

            for (int i = 0; i < tabControl.TabCount; i++)
            {
                if (tabControl.GetTabRect(i).Contains(e.Location))
                {
                    tabControl.TabPages[i].ToolTipText = PlainTextBoxes[i].Document.FileName;
                    return;
                }
            }
        }

        /// <summary>
        /// Loads documents into the app
        /// Always call this instead of the two load into methods
        /// </summary>
        public void LoadDocuments(params string[] fileNames)
        {
            tabControl.SuspendLayout();
            LoadIntoSeparateTabs(fileNames);
            UpdateAllInfo();
            tabControl.ResumeLayout();
        }

        private void tabControl_DragDrop(object sender, DragEventArgs e)
        {
            var fileNames = e.Data.GetData(DataFormats.FileDrop) as string[];
            if (fileNames != null) LoadDocuments(fileNames);
        }

        private void tabControl_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop, true))
            {
                e.Effect = DragDropEffects.All;
            }
        }
        #endregion

        // Any functions that can be placed near where they are used should not go here
        #region Misc Functions
        private static void StartProcess(string name)
        {
            try
            {
                Process.Start(name);
            }
            catch (Exception ex)
            {
                MsgBox.Show(ex.Message);
            }
        }

        private static void StartProcess(string name, string argument)
        {
            try
            {
                Process.Start(name, argument);
            }
            catch (Exception ex)
            {
                MsgBox.Show(ex.Message);
            }
        }
        /// <summary>
        /// Displays a message box and prompts for save
        /// the return value indicates whether or whether not the tab or app
        /// should be closed when the user presses a button.
        /// Cancel of course returns true so nothing will happen in the calling code
        /// </summary>
        private bool PromptToSave()
        {
            // Display from tab text here because it is all visual
            // full safe file name is not required
            string message = string.Format(CultureInfo.CurrentCulture,
                Strings.MsgSaveFile, PtbActive.Document.SafeFileName);

            DialogResult result = MsgBox.Show(message, MessageBoxIcon.Question, MessageBoxButtons.YesNoCancel);

            //return true to cancel the closing of the form
            if (result == DialogResult.Yes)
            {
                Save();
            }
            else if (result == DialogResult.Cancel)
            {
                return true;
            }

            return false;
        }

        private void CloseSelectedTab()
        {
            // A save prompt will only popup when document has been modified
            // and the current text does not matche up  with initial text state
            if (PtbActive.Modified)
            {
                if (!PromptToSave()) CleanUp();
            }
            else
            {
                CleanUp();
            }
        }

        private void CleanUp()
        {
            // Remove all document dependent panels before closing last tab
            if (tabControl.TabCount == 1)
            {
                tsmiGoto.Checked = tsmiFind.Checked = false;
                tsmiReplace.Checked = tsmiDocumentInfo.Checked = false;
            }

            PtbActive.Dispose();

            tabControl.TabPages.Remove(tabControl.SelectedTab);
            tabControl.SelectedIndex = tabControl.TabCount - 1;
        }

        private void UpdateDocumentInfo()
        {
            if (_pnlDocumentInfo != null)
            {
                _pnlDocumentInfo.DocumentFormat = Path.GetExtension(PtbActive.Document.SafeFileName);
                string docName = Path.GetFileNameWithoutExtension(PtbActive.Document.SafeFileName);
                _pnlDocumentInfo.SetDocumentName(docName);
                _pnlDocumentInfo.SetWordCount(PtbActive.WordCount);
                _pnlDocumentInfo.SetCharacterCount(PtbActive.CharacterCount);
                _pnlDocumentInfo.SetSentenceCount(PtbActive.SentenceCount);

                if (_pnlDocumentInfo.DocumentFormat.Length.Equals(0))
                {
                    _pnlDocumentInfo.DocumentFormat = Strings.Unknown;
                }
            }
        }

        private void UpdateStatusBar()
        {
            if (statusBar.Visible && !tabControl.SelectedIndex.Equals(-1))
            {
                lblTabCount.Text = (tabControl.TabCount).ToString();
                lblTabSelected.Text = (tabControl.SelectedIndex + 1).ToString();
                lblCurrentLine.Text = PtbActive.CurrentLine.ToString();
                lblCurrentColumn.Text = PtbActive.CurrentColumn.ToString();
            }
        }

        private void UpdateAllInfo()
        {
            if (!tabControl.TabCount.Equals(0))
            {
                UpdateDocumentInfo();
                UpdateStatusBar();
                UpdateRedoUndoMenuItems();
                UpdateTabTextModifiedIndicator();
            }
            else
            {
                lblTabSelected.Text = lblCurrentLine.Text = lblCurrentColumn.Text = lblTabCount.Text = "0";
            }
        }

        /// <summary>
        /// Updates the tab-text property with the appropriate save indication if necessary
        /// </summary>
        private void UpdateTabTextModifiedIndicator()
        {
            string title = tabControl.SelectedTab.Text.TrimEnd('*');

            if (PtbActive.Document.SavedOrOpened && PtbActive.Modified)
            {
                title += "*";
            }

            if (tabControl.SelectedTab.Text[tabControl.SelectedTab.Text.Length - 1] !=
                title[title.Length - 1])
            {
                tabControl.SelectedTab.Text = title;
            }
        }

        public void AppendFiles(IEnumerable<string> fileNames)
        {
            const string DOUBLE_LINE = "\n\n";

            PtbActive.SuspendLayout();

            foreach (string name in fileNames)
            {
                if (!LoadLargeFile(name)) continue;

                StreamReader SR = null;

                try
                {
                    SR = new StreamReader(name);
                    PtbActive.AppendText(DOUBLE_LINE + SR.ReadToEnd());

                    if (_pnlDocumentInfo != null)
                    {
                        _pnlDocumentInfo.DocumentFormat = Path.GetExtension(name);
                        _pnlDocumentInfo.SetDocumentName(Path.GetFileName(name));
                    }

                    RecentFileQue.AddFiles(name);
                    PtbActive.Modified = true;
                }
                catch (Exception ex)
                {
                    MsgBox.Show(ex.Message);
                }
                finally
                {
                    if (SR != null) SR.Close();
                }
            }

            PtbActive.Text = PtbActive.Text.Trim();
            PtbActive.ResumeLayout();
        }

        /// <summary>
        /// Checks to see if file is already loaded into a tab, if it is, the
        /// method returns true and selects that tab.
        /// </summary>
        private bool IsAlreadyOpen(string fileName)
        {
            for (int i = 0; i < PlainTextBoxes.Count; i++)
            {
                if (fileName.Equals(PlainTextBoxes[i].Document.FileName, StringComparison.OrdinalIgnoreCase))
                {
                    // Do not select the tabPage if it is already selected
                    // otherwise the tabControl will navigate to last selected
                    if (!tabControl.SelectedIndex.Equals(i))
                    {
                        tabControl.SelectTab(i);
                    }

                    return true;
                }
            }

            return false;
        }

        /// <returns>Returns true if user agrees to load large file, otherwise return false</returns>
        private static bool LoadLargeFile(string fileName)
        {
            FileInfo fileInfo = new FileInfo(fileName);

            if (UserSettings.Instance.ShowLargeFileWarning && fileInfo.IsFileLarge())
            {
                string safeFileName = Path.GetFileName(fileName);
                var msg = safeFileName + " " + Strings.MsgBigFile;
                DialogResult result = MsgBox.Show(msg, MessageBoxIcon.Warning, MessageBoxButtons.YesNo);
                return (result == DialogResult.Yes);
            }

            return true;
        }

        private void LoadIntoSeparateTabs(IEnumerable<string> fileNames)
        {
            bool hasOneFileAlreadyOpen = false;

            foreach (string name in fileNames)
            {
                if (name.Length == 0)
                {
                    AddBlankTab();
                    continue;
                }

                // If user decides not to load big file
                if (!LoadLargeFile(name)) continue;
                hasOneFileAlreadyOpen = IsAlreadyOpen(name);
                if (hasOneFileAlreadyOpen) continue;

                try
                {
                    string safeFileName = Path.GetFileName(name);
                    safeFileName = StringOps.GetElipsisedText(safeFileName);
                    tabControl.TabPages.Add(safeFileName);
                    int index = tabControl.TabPages.Count - 1;
                    PlainTextBoxes[index].Text = File.ReadAllText(name);
                    PlainTextBoxes[index].Document.FileName = name.TrimEnd();
                    PlainTextBoxes[index].Modified = false;

                    if (_pnlDocumentInfo != null)
                    {
                        _pnlDocumentInfo.DocumentFormat = Path.GetExtension(name);
                    }

                    RecentFileQue.AddFiles(name);
                }
                catch (Exception ex)
                {
                    tabControl.SelectedIndex = tabControl.TabCount - 1;
                    CloseSelectedTab();
                    MsgBox.Show(ex.Message);
                }
            }

            if (!hasOneFileAlreadyOpen)
            {
                tabControl.SelectedIndex = tabControl.TabCount - 1;
            }

            UpdateAllInfo();
        }

        public void OpenFileFromArguments(string[] args)
        {
            LoadDocuments(args);
            _trayIcon.UnMinimizeFromTray();
            this.BringToFront();
        }

        /// <summary>
        /// Disables and enables certain controls according to whether or not there are tabs
        /// Disabling controls lets the user know that certain operations are unavailable
        /// with certain criteria. This is better than an error dialog box by far.
        /// </summary>
        private void UpdateControlAbilitys()
        {
            bool isEnabled = (tabControl.TabCount > 0);

            tsmiEdit.Enabled = tsmiWordWrap.Enabled = isEnabled;
            tsmiFind.Enabled = tsmiGoto.Enabled = isEnabled;
            tsmiReplace.Enabled = tsmiInsert.Enabled = isEnabled;
            tsmiFindNext.Enabled = isEnabled;
            tsmiSaveAs.Enabled = tsmiSave.Enabled = isEnabled;
            tsmiShortDateTime.Enabled = tsmiLongDateTime.Enabled = isEnabled;
            tsmiPageSetup.Enabled = tsmiPrint.Enabled = isEnabled;
            tsmiPrintPreview.Enabled = tsmiCloseTab.Enabled = isEnabled;
            tsmiCloseAllTabs.Enabled = tsmiCloseAllButCurrent.Enabled = isEnabled;
            tsmiCloseAndDelete.Enabled = tsmiSelectAll.Enabled = isEnabled;
            tsmiDocumentInfo.Enabled = tsmiReadingWindow.Enabled = isEnabled;

            if (!isEnabled)
            {
                tsmiUndo.Enabled = tsmiRedo.Enabled = false;
            }
        }

        private void UpdateRedoUndoMenuItems()
        {
            tsmiUndo.Enabled = PtbActive.CanUndo;
            tsmiRedo.Enabled = PtbActive.CanRedo;
        }

        /// <summary>
        /// To update the multiline tab placement from the preference panel
        /// </summary>
        public void SetMultilineTabbing()
        {
            tabControl.Multiline = Settings.MultiLineTabs;
        }
        #endregion

        #region Properties
        /// <summary>
        /// Gets the PlainTextBox associated with the currently selected TabPage
        /// </summary>
        public PlainTextBox PtbActive
        {
            get { return (PlainTextBox)tabControl.SelectedTab.Controls[0]; }
        }

        public Collection<PlainTextBox> PlainTextBoxes
        {
            get
            {
                var plainTextBoxes = new Collection<PlainTextBox>();

                for (int i = 0; i < tabControl.TabPages.Count; i++)
                {
                    plainTextBoxes.Add((PlainTextBox)tabControl.TabPages[i].Controls[0]);
                }

                return plainTextBoxes;
            }
        }

        public Collection<LineNumberStrip> LineNumberStrips
        {
            get
            {
                var lineNumberStrips = new Collection<LineNumberStrip>();

                for (int i = 0; i < tabControl.TabPages.Count; i++)
                {
                    if (tabControl.TabPages[i].Controls.Count > 1)
                    {
                        lineNumberStrips.Add((LineNumberStrip)tabControl.TabPages[i].Controls[1]);
                    }
                }

                return lineNumberStrips;
            }
        }

        public bool TrackCaretOnTabControl
        {
            get { return tabControl.TrackCaret; }
            set { tabControl.TrackCaret = value; }
        }
        #endregion

        //Any events that do not belong in other regions should go here
        #region Misc Eventing
        private void tmrMessage_Tick(object sender, EventArgs e)
        {
            if (_ticks++ == _IDLE_TIME_BEFORE_PROMPT)
            {
                this.Text = Application.ProductName + " - " + Strings.MsgAddTabPrompt;
                // We will only display this message once so we may as well dispose of this after using
                tmrMessage.Dispose();
            }
        }

        private void statusBar_VisibleChanged(object sender, EventArgs e)
        {
            UpdateStatusBar();
        }
        #endregion
    }
}