using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace IMLibrary.Controls.Toolbox
{
    partial class Toolbox
    {
        /// <summary>
        /// Enumerates the default context menu items of the <see cref="Toolbox"/>.
        /// </summary>
        protected enum ContextMenuItems
        {
            /// <summary>
            /// No item.
            /// </summary>
            None = 0,
            /// <summary>
            /// A 'List View' item. Not implemented in default context menus.
            /// </summary>
            ListView,
            /// <summary>
            /// A 'Show All' item.
            /// </summary>
            ShowAll,
            /// <summary>
            /// A 'Choose Items...' item. Not implemented in default context menus.
            /// </summary>
            ChooseItems,
            /// <summary>
            /// A 'Sort alphabetically' menu item.
            /// </summary>
            SortItems,
            /// <summary>
            /// A 'Reset Toolbox' menu item. Not implemented in default context menus.
            /// </summary>
            Reset,
            /// <summary>
            /// An 'Add Tab' menu item.
            /// </summary>
            AddTab,
            /// <summary>
            /// A 'Remove Tab (Item)' menu item.
            /// </summary>
            Remove,
            /// <summary>
            /// A 'Rename Tab (Item)' menu item.
            /// </summary>
            Rename,
            /// <summary>
            /// A 'Move Up' menu item.
            /// </summary>
            MoveUp,
            /// <summary>
            /// A 'Move Down' menu item.
            /// </summary>
            MoveDown,
            /// <summary>
            /// A 'Cut' menu item.
            /// </summary>
            Cut,
            /// <summary>
            /// A 'Copy' menu item.
            /// </summary>
            Copy,
            /// <summary>
            /// A 'Paste' menu item.
            /// </summary>
            Paste
        }

        private static Bitmap _cutImage;
        private static Bitmap _copyImage;
        private static Bitmap _deleteImage;
        private static Bitmap _pasteImage;

        private Bitmap GetMenuImage(string name)
        {
            switch (name)
            {
                case "Cut":
                    if (_cutImage == null)
                    {
                        _cutImage = LoadImage(Properties.Resources.Cut);
                    }
                    return _cutImage;
                case "Copy":
                    if (_copyImage == null)
                    {
                        _copyImage = LoadImage(Properties.Resources.Copy);
                    }
                    return _copyImage;
                case "Delete":
                    if (_deleteImage == null)
                    {
                        _deleteImage = LoadImage(Properties.Resources.Delete);
                    }
                    return _deleteImage;
                case "Paste":
                    if (_pasteImage == null)
                    {
                        _pasteImage = LoadImage(Properties.Resources.Paste);
                    }
                    return _pasteImage;
            }
            return null;
        }

        private static Bitmap LoadImage(Bitmap original)
        {
            Bitmap bitmap = null;
            try
            {
                bitmap = new Bitmap(original);
                bitmap.MakeTransparent(bitmap.GetPixel(0, 0));
            }
            catch (System.IO.FileNotFoundException) { }
            catch (ArgumentNullException) { }
            return bitmap;
        }

        #region Item Menu
        /// <summary>
        /// Creates a default <see cref="ContextMenuStrip">menu</see> to display on <see cref="Item">items</see>.
        /// </summary>
        /// <returns>A formed item <see cref="ContextMenuStrip">context menu</see>.</returns>
        protected virtual ContextMenuStrip CreateItemMenu()
        {
            ContextMenuStrip strip = new ContextMenuStrip();
            strip.Opening += new System.ComponentModel.CancelEventHandler(OnItemMenuOpening);

            ToolStripMenuItem item = new ToolStripMenuItem(Properties.Resources.ToolboxMenuCut);
            item.Image = GetMenuImage("Cut");
            item.Click += new EventHandler(OnMenuItemCutItem);
            item.Tag = ContextMenuItems.Cut;
            strip.Items.Add(item);

            item = new ToolStripMenuItem(Properties.Resources.ToolboxMenuCopy);
            item.Image = GetMenuImage("Copy");
            item.Click += new EventHandler(OnMenuItemCopyItem);
            item.Tag = ContextMenuItems.Copy;
            strip.Items.Add(item);

            item = new ToolStripMenuItem(Properties.Resources.ToolboxMenuPaste);
            item.Image = GetMenuImage("Paste");
            item.Click += new EventHandler(OnMenuItemPasteItem);
            item.Tag = ContextMenuItems.Paste;
            strip.Items.Add(item);

            item = new ToolStripMenuItem(Properties.Resources.ToolboxMenuDelete);
            item.Image = GetMenuImage("Delete");
            item.Click += new EventHandler(OnMenuItemDeleteItem);
            item.Tag = ContextMenuItems.Remove;
            strip.Items.Add(item);

            item = new ToolStripMenuItem(Properties.Resources.ToolboxMenuRenameItem);
            item.Click += new EventHandler(OnMenuItemRenameItem);
            item.Tag = ContextMenuItems.Rename;
            strip.Items.Add(item);

            strip.Items.Add(new ToolStripSeparator());

            item = new ToolStripMenuItem(Properties.Resources.ToolboxMenuShowAll);
            item.Click += new EventHandler(OnMenuItemShowAll);
            item.Tag = ContextMenuItems.ShowAll;
            strip.Items.Add(item);

            strip.Items.Add(new ToolStripSeparator());

            item = new ToolStripMenuItem(Properties.Resources.ToolboxMenuSortAlphabetically);
            item.Click += new EventHandler(OnMenuItemSortAlphabetically);
            item.Tag = ContextMenuItems.SortItems;
            strip.Items.Add(item);

            item = new ToolStripMenuItem(Properties.Resources.ToolboxMenuResetToolbox);
            item.Click += new EventHandler(OnMenuItemResetToolbox);
            item.Tag = ContextMenuItems.Reset;
            strip.Items.Add(item);

            strip.Items.Add(new ToolStripSeparator());

            item = new ToolStripMenuItem(Properties.Resources.ToolboxMenuAddTab);
            item.Click += new EventHandler(OnMenuItemAddTab);
            item.Tag = ContextMenuItems.AddTab;
            strip.Items.Add(item);

            strip.Items.Add(new ToolStripSeparator());

            item = new ToolStripMenuItem(Properties.Resources.ToolboxMenuMoveUp);
            item.Click += new EventHandler(OnMenuItemMoveUp);
            item.Tag = ContextMenuItems.MoveUp;
            strip.Items.Add(item);

            item = new ToolStripMenuItem(Properties.Resources.ToolboxMenuMoveDown);
            item.Click += new EventHandler(OnMenuItemMoveDown);
            item.Tag = ContextMenuItems.MoveDown;
            strip.Items.Add(item);

            return strip;
        }

        void OnItemMenuOpening(object sender, System.ComponentModel.CancelEventArgs e)
        {
            Item caller = ItemMenu.Tag as Item;
            foreach (ToolStripItem stripItem in ItemMenu.Items)
            {
                if (stripItem is ToolStripMenuItem && stripItem.Tag != null && stripItem.Tag is ContextMenuItems)
                {
                    ToolStripMenuItem item = (ToolStripMenuItem)stripItem;
                    ContextMenuItems context = (ContextMenuItems)item.Tag;
                    switch (context)
                    {
                        case ContextMenuItems.ListView:
                            break;
                        case ContextMenuItems.ShowAll:
                            item.Checked = ShowAll;
                            break;
                        case ContextMenuItems.ChooseItems:
                            break;
                        case ContextMenuItems.SortItems:
                            item.Enabled = (caller.Category != null);
                            break;
                        case ContextMenuItems.Reset:
                            break;
                        case ContextMenuItems.AddTab:
                            break;
                        case ContextMenuItems.Rename:
                            item.Enabled = (caller != null);
                            break;
                        case ContextMenuItems.MoveUp:
                            item.Enabled = (caller != null && !IsPointerItem(caller) && caller.Owner.Items.IndexOf(caller) != 0);
                            break;
                        case ContextMenuItems.MoveDown:
                            item.Enabled = (caller != null && !IsPointerItem(caller) && caller.Owner.Items.IndexOf(caller) != caller.Owner.Items.Count - 1);
                            break;
                        case ContextMenuItems.Cut:
                            item.Enabled = (caller != null && !IsPointerItem(caller));
                            break;
                        case ContextMenuItems.Copy:
                            item.Enabled = (caller != null && !IsPointerItem(caller));
                            break;
                        case ContextMenuItems.Paste:
                            item.Enabled = (caller != null && Clipboard.ContainsData(ClipboardFormat.Item));
                            break;
                        case ContextMenuItems.Remove:
                            item.Enabled = (caller != null && !IsPointerItem(caller));
                            break;
                    }
                }
            }
        }
        #endregion

        #region Category Menu
        /// <summary>
        /// Creates a default <see cref="ContextMenuStrip">menu</see> to display on <see cref="Tab">categories</see>.
        /// </summary>
        /// <returns>A formed tab <see cref="ContextMenuStrip">context menu</see>.</returns>
        protected virtual ContextMenuStrip CreateTabMenu()
        {
            ContextMenuStrip strip = new ContextMenuStrip();
            strip.Opening += new System.ComponentModel.CancelEventHandler(OnTabMenuOpening);

            ToolStripMenuItem item = new ToolStripMenuItem(Properties.Resources.ToolboxMenuShowAll);
            item.Click += new EventHandler(OnMenuItemShowAll);
            item.Tag = ContextMenuItems.ShowAll;
            strip.Items.Add(item);

            strip.Items.Add(new ToolStripSeparator());

            item = new ToolStripMenuItem(Properties.Resources.ToolboxTabPasteItem);
            item.Click += new EventHandler(OnMenuItemPasteItem);
            item.Tag = ContextMenuItems.Paste;
            strip.Items.Add(item);

            strip.Items.Add(new ToolStripSeparator());

            item = new ToolStripMenuItem(Properties.Resources.ToolboxMenuSortAlphabetically);
            item.Click += new EventHandler(OnMenuItemSortAlphabetically);
            item.Tag = ContextMenuItems.SortItems;
            strip.Items.Add(item);

            item = new ToolStripMenuItem(Properties.Resources.ToolboxMenuResetToolbox);
            item.Click += new EventHandler(OnMenuItemResetToolbox);
            item.Tag = ContextMenuItems.Reset;
            strip.Items.Add(item);

            strip.Items.Add(new ToolStripSeparator());

            item = new ToolStripMenuItem(Properties.Resources.ToolboxMenuAddTab);
            item.Click += new EventHandler(OnMenuItemAddTab);
            item.Tag = ContextMenuItems.AddTab;
            strip.Items.Add(item);

            item = new ToolStripMenuItem(Properties.Resources.ToolboxMenuTabDelete);
            item.Click += new EventHandler(OnMenuItemDeleteTab);
            item.Tag = ContextMenuItems.Remove;
            strip.Items.Add(item);

            item = new ToolStripMenuItem(Properties.Resources.ToolboxMenuRenameTab);
            item.Click += new EventHandler(OnMenuItemRenameTab);
            item.Tag = ContextMenuItems.Rename;
            strip.Items.Add(item);

            strip.Items.Add(new ToolStripSeparator());

            item = new ToolStripMenuItem(Properties.Resources.ToolboxMenuMoveUp);
            item.Click += new EventHandler(OnMenuItemMoveUp);
            item.Tag = ContextMenuItems.MoveUp;
            strip.Items.Add(item);

            item = new ToolStripMenuItem(Properties.Resources.ToolboxMenuMoveDown);
            item.Click += new EventHandler(OnMenuItemMoveDown);
            item.Tag = ContextMenuItems.MoveDown;
            strip.Items.Add(item);

            return strip;
        }

        void OnTabMenuOpening(object sender, System.ComponentModel.CancelEventArgs e)
        {
            Tab caller = TabMenu.Tag as Tab;
            foreach (ToolStripItem stripItem in TabMenu.Items)
            {
                if (stripItem is ToolStripMenuItem && stripItem.Tag != null && stripItem.Tag is ContextMenuItems)
                {
                    ToolStripMenuItem item = (ToolStripMenuItem)stripItem;
                    ContextMenuItems context = (ContextMenuItems)item.Tag;
                    switch (context)
                    {
                        case ContextMenuItems.ListView:
                            break;
                        case ContextMenuItems.ShowAll:
                            item.Checked = ShowAll;
                            break;
                        case ContextMenuItems.ChooseItems:
                            break;
                        case ContextMenuItems.SortItems:
                            item.Enabled = (caller != null);
                            break;
                        case ContextMenuItems.Reset:
                            break;
                        case ContextMenuItems.AddTab:
                            break;
                        case ContextMenuItems.Remove:
                            item.Enabled = (caller != null && caller.AllowDelete);
                            break;
                        case ContextMenuItems.Rename:
                            item.Enabled = (caller != null);
                            break;
                        case ContextMenuItems.MoveUp:
                            item.Enabled = (caller != null && Categories.IndexOf(caller) != 0);
                            break;
                        case ContextMenuItems.MoveDown:
                            item.Enabled = (caller != null && Categories.IndexOf(caller) != Categories.Count - 1);
                            break;
                        case ContextMenuItems.Paste:
                            item.Enabled = (caller != null && Clipboard.ContainsData(ClipboardFormat.Item));
                            break;
                    }
                }
            }
        }
        #endregion

        #region MenuItem handlers
        void OnMenuItemRenameItem(object sender, EventArgs e)
        {
            Item item = ItemMenu.Tag as Item;
            if (item != null)
                OnRenameItem(item);
        }

        void OnMenuItemDeleteItem(object sender, EventArgs e)
        {
            OnDeleteItem(LastSelectedTool as Item);
        }

        void OnMenuItemPasteItem(object sender, EventArgs e)
        {
            IDataObject dataObject = Clipboard.GetDataObject();
            if (dataObject.GetDataPresent(ClipboardFormat.Item))
            {
                Item item = (Item)dataObject.GetData(ClipboardFormat.Item, true);
                ITab selTab = LastSelectedTool as Tab;
                if (selTab == null && LastSelectedTool is Item)
                    selTab = LastSelectedTool.Owner;
                if (selTab != null)
                    OnPasteItem(item, selTab);
            }
        }

        void OnMenuItemCopyItem(object sender, EventArgs e)
        {
            OnCopyItem(LastSelectedTool as Item);
        }

        void OnMenuItemCutItem(object sender, EventArgs e)
        {
            OnCutItem(LastSelectedTool as Item);
        }

        void OnMenuItemMoveDown(object sender, EventArgs e)
        {
            Tab selTab = LastSelectedTool as Tab;
            if (selTab != null && selTab.Owner != null)
            {
                TabCollection tabCollection = selTab.Owner.Categories;
                int index = tabCollection.IndexOf(selTab);
                if (index < tabCollection.Count - 1)
                {
                    bool allowDelete = selTab.AllowDelete;
                    try
                    {
                        selTab.AllowDelete = true;
                        tabCollection.RemoveAt(index);
                        tabCollection.Insert(index + 1, selTab);
                    }
                    finally
                    {
                        selTab.AllowDelete = allowDelete;
                    }
                }
            }

            Item selItem = LastSelectedTool as Item;
            if (selItem != null && selItem.Owner != null)
            {
                ItemCollection itemCollection = selItem.Owner.Items;
                int index = itemCollection.IndexOf(selItem);
                if (index < itemCollection.Count - 1)
                {
                    itemCollection.RemoveAt(index);
                    itemCollection.Insert(index + 1, selItem);
                }
            }
        }

        void OnMenuItemMoveUp(object sender, EventArgs e)
        {
            Tab selTab = LastSelectedTool as Tab;
            if (selTab != null && selTab.Owner != null)
            {
                TabCollection tabCollection = selTab.Owner.Categories;
                int index = tabCollection.IndexOf(selTab);
                if (index > 0)
                {
                    bool allowDelete = selTab.AllowDelete;
                    try
                    {
                        selTab.AllowDelete = true;
                        tabCollection.RemoveAt(index);
                        tabCollection.Insert(index - 1, selTab);
                    }
                    finally
                    {
                        selTab.AllowDelete = allowDelete;
                    }
                }
            }

            Item selItem = LastSelectedTool as Item;
            if (selItem != null && selItem.Owner != null)
            {
                ItemCollection itemCollection = selItem.Owner.Items;
                int index = itemCollection.IndexOf(selItem);
                if (index > 0)
                {
                    itemCollection.RemoveAt(index);
                    itemCollection.Insert(index - 1, selItem);
                }
            }
        }

        void OnMenuItemRenameTab(object sender, EventArgs e)
        {
            Tab caller = LastSelectedTool as Tab;
            if (caller != null)
                OnRenameTab(caller, caller.Text);
        }

        void OnMenuItemDeleteTab(object sender, EventArgs e)
        {
            Tab selected = LastSelectedTool as Tab;
            if (selected != null && selected.Owner != null && selected.AllowDelete)
                selected.Owner.Categories.Remove(selected);
        }

        void OnMenuItemAddTab(object sender, EventArgs e)
        {
            AddEmptyTab();
        }

        void OnMenuItemResetToolbox(object sender, EventArgs e)
        {
            OnResetToolbox();
        }

        void OnMenuItemSortAlphabetically(object sender, EventArgs e)
        {
            OnSortAlphabetically();
        }

        void OnMenuItemShowAll(object sender, EventArgs e)
        {
            ShowAll = !ShowAll;
        }
        #endregion

        /// <summary>
        /// Creates and adds an empty category tab.
        /// </summary>
        /// <remarks>Invoked by the 'Add Tab' menu item.</remarks>
        protected virtual void AddEmptyTab()
        {
            ITab owner = LastSelectedTool as ITab;
            if (owner == null && LastSelectedTool != null)
                owner = LastSelectedTool.Owner;
            if (owner == null)
                owner = this;
            Tab tab = CreateNewTab(GetUnusedCategoryName(owner));
            tab.Opened = true;
            owner.Categories.Add(tab);
            OnPaint(new PaintEventArgs(CreateGraphics(), ClientRectangle));
            OnRenameTab(tab, string.Empty);
        }

        /// <summary>
        /// Sorts currently selected category tab items in ascending order.
        /// </summary>
        /// <remarks>Invoked by the 'Sort Alphabetically' menu item.</remarks>
        protected virtual void OnSortAlphabetically()
        {
            Tab selected = LastSelectedTool as Tab;
            if (selected == null && LastSelectedTool != null)
                selected = LastSelectedTool.Owner as Tab;
            if (selected != null)
                selected.SortItems(SortOrder.Ascending);
        }

        /// <summary>
        /// Resets the state of the <see cref="Toolbox"/>.
        /// </summary>
        /// <remarks>Invoked by the 'Reset Toolbox' menu item.</remarks>
        protected virtual void OnResetToolbox()
        {
        }

        /// <summary>
        /// Copies to the clipboard and removes an <paramref name="item"/> from the <see cref="Toolbox"/>.
        /// </summary>
        /// <param name="item">An <see cref="Item"/> to cut.</param>
        /// <remarks>Invoked by the 'Cut' menu item.</remarks>
        protected virtual void OnCutItem(Item item)
        {
            OnCopyItem(item);
            OnDeleteItem(item);
        }

        /// <summary>
        /// Copies an <paramref name="item"/> to the clipboard.
        /// </summary>
        /// <param name="item">An <see cref="Item"/> to copy.</param>
        /// <remarks>Invoked by the 'Copy' menu item.</remarks>
        protected virtual void OnCopyItem(Item item)
        {
            if (item == null)
                throw new ArgumentNullException("item");

            IDataObject dataObject = new DataObject(ClipboardFormat.Item, item.Clone());
            Clipboard.SetDataObject(dataObject, false);
        }

        /// <summary>
        /// Removes an <paramref name="item"/> from the <see cref="Toolbox"/>.
        /// </summary>
        /// <param name="item">An <see cref="Item"/> to remove.</param>
        /// <remarks>Invoked by the 'Delete' menu item.</remarks>
        protected virtual void OnDeleteItem(Item item)
        {
            if (item == null)
                throw new ArgumentNullException("item");

            if (item.Owner == null)
                throw new ArgumentException(Properties.Resources.ToolboxDeleteNonTabbedItem, "item");

            item.Owner.Items.Remove(item);
        }

        /// <summary>
        /// Inserts an <paramref name="item"/> to the <paramref name="category"/> tab.
        /// </summary>
        /// <param name="item">An <see cref="Item"/> to paste.</param>
        /// <param name="tab">A <see cref="Tab"/> to add an item.</param>
        /// <remarks>Invoked by the 'Paste' menu item.</remarks>
        protected virtual void OnPasteItem(Item item, ITab tab)
        {
            if (item == null)
                throw new ArgumentNullException("item");
            if (tab == null)
                throw new ArgumentNullException("category");
            if (item.Owner != null)
            {
                if (item.Owner == tab)
                    return;

                item.Owner.Items.Remove(item);
            }
            tab.Items.Add(item);
        }
    }
}
