using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Windows.Controls;
using FooEditor;
using FooEditor.Plugin;
using System.Windows;
using System.Windows.Input;
using Outline.Properties;
using FooEditEngine;
using FooEditEngine.WPF;

namespace Outline
{
    [Export(typeof(IPlugin))]
    public sealed class Outlline : IPlugin
    {
        MainWindow editor;
        ExplorerBar<OutlineWindow> outlineWindow;

        public void Initalize(MainWindow e)
        {
            this.editor = e;
            this.editor.ActiveDocumentChanged += new EventHandler(editor_ActiveDocumentChanged);
            this.editor.CreatedDocument += editor_CreatedDocument;
            this.editor.RemovedDocument += editor_RemovedDocument;

            this.outlineWindow = new ExplorerBar<OutlineWindow>();
            this.outlineWindow.Content = new OutlineWindow();
            this.editor.RegisterExploereBar<OutlineWindow>(this.outlineWindow);
            this.outlineWindow.IsVisible = false;

            MenuItem item = new MenuItem();
            item.Header = Resources.OutLineMenuName;
            item.Click += new RoutedEventHandler(item_Click);
            MenuItem toolMenuItem = (MenuItem)this.editor.FindName(FooEditorMenuItemName.LookMenuName);
            toolMenuItem.Items.Insert(0, item);

            e.CommandBindings.Add(new CommandBinding(OutlineCommands.PasteAsChild, PasteAsChildCommand, CanExecute));
            e.CommandBindings.Add(new CommandBinding(OutlineCommands.UpLevel, UpLevelCommand, CanExecute));
            e.CommandBindings.Add(new CommandBinding(OutlineCommands.DownLevel, DownLevelCommand, CanExecute));

            MenuItem editMenuItem = (MenuItem)this.editor.FindName(FooEditorMenuItemName.EditMenuName);

            MenuItem rootMenuItem = new MenuItem();
            rootMenuItem.Header = Resources.OutLineMenuName;

            item = new MenuItem();
            item.Header = Resources.UpLevelMenuName;
            item.Command = OutlineCommands.UpLevel;
            rootMenuItem.Items.Add(item);

            item = new MenuItem();
            item.Header = Resources.DownLevelMenuName;
            item.Command = OutlineCommands.DownLevel;
            rootMenuItem.Items.Add(item);

            item = new MenuItem();
            item.Header = Resources.PasteAsChildMenuName;
            item.Command = OutlineCommands.PasteAsChild;
            rootMenuItem.Items.Add(item);

            editMenuItem.Items.Add(new Separator());
            editMenuItem.Items.Add(rootMenuItem);

            //新しくインスタンスを作らないと例外が発生する
            rootMenuItem = new MenuItem();
            rootMenuItem.Header = Resources.OutLineMenuName;

            item = new MenuItem();
            item.Header = Resources.UpLevelMenuName;
            item.Command = OutlineCommands.UpLevel;
            rootMenuItem.Items.Add(item);

            item = new MenuItem();
            item.Header = Resources.DownLevelMenuName;
            item.Command = OutlineCommands.DownLevel;
            rootMenuItem.Items.Add(item);

            item = new MenuItem();
            item.Header = Resources.PasteAsChildMenuName;
            item.Command = OutlineCommands.PasteAsChild;
            rootMenuItem.Items.Add(item);

            ContextMenu contextMenu = (ContextMenu)this.editor.FindResource(FooEditorResourceName.ContextMenuName);
            contextMenu.Items.Add(new Separator());
            contextMenu.Items.Add(rootMenuItem);

            Config config = Config.GetInstance();
            config.SyntaxDefinitions.Add(new DocumentType(Resources.DocumentTypeWZText));
        }

        void editor_RemovedDocument(object sender, DocumentEventArgs e)
        {
            e.Document.DocumentTypeChangeing -= this.Document_DocumentTypeChangeing;
            e.Document.DocumentTypeChanged -= Document_DocumentTypeChanged;
        }

        void editor_CreatedDocument(object sender, DocumentEventArgs e)
        {
            e.Document.DocumentTypeChangeing += Document_DocumentTypeChangeing;
            e.Document.DocumentTypeChanged += Document_DocumentTypeChanged;
        }

        void Document_DocumentTypeChanged(object sender, EventArgs e)
        {
            this.outlineWindow.Content.ReGenerate();
        }

        void Document_DocumentTypeChangeing(object sender, DocumentTypeChangeingEventArgs e)
        {
            DocumentWindow doc = (DocumentWindow)sender;
            if (e.Type == Resources.DocumentTypeWZText)
            {
                doc.TextBox.Hilighter = null;
                doc.TextBox.FoldingStrategy = new WZTextFoldingGenerator();
                e.Handled = true;
            }
        }

        void editor_ActiveDocumentChanged(object sender, EventArgs e)
        {
            if (this.editor.ActiveDocument == null)
                return;
            this.outlineWindow.Content.Target = this.editor.ActiveDocument;
            this.outlineWindow.Content.ReGenerate();
        }

        void item_Click(object sender, RoutedEventArgs e)
        {
            if (this.editor.ActiveDocument == null)
                return;
            this.outlineWindow.Content.Target = this.editor.ActiveDocument;
            this.outlineWindow.IsVisible = true;
            this.outlineWindow.Content.ReGenerate();
        }

        public void ClosedApp()
        {
        }

        public void ShowConfigForm()
        {
        }

        #region Command
        void CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            FooTextBox textbox = this.outlineWindow.Content.Target.TextBox;
            OutlineItem item = textbox.LayoutLineCollection.FoldingCollection.Get(textbox.LayoutLineCollection.GetIndexFromTextPoint(textbox.CaretPostion), 1) as OutlineItem;
            e.CanExecute = item != null && textbox.FoldingStrategy is WZTextFoldingGenerator;
        }

        void PasteAsChildCommand(object sender, ExecutedRoutedEventArgs e)
        {
            FooTextBox textbox = this.outlineWindow.Content.Target.TextBox;
            int caretIndex = textbox.LayoutLineCollection.GetIndexFromTextPoint(textbox.CaretPostion);
            OutlineItem item = textbox.LayoutLineCollection.FoldingCollection.Get(caretIndex, 1) as OutlineItem;

            if (item == null)
                return;

            string text = Actions.FitOutlineLevel(Clipboard.GetText(), item, item.Level + 1);

            textbox.Document.Replace(item.End + 1, 0, text);
            textbox.Refresh();
        }

        void UpLevelCommand(object sender, ExecutedRoutedEventArgs e)
        {
            FooTextBox textbox = this.outlineWindow.Content.Target.TextBox;
            int caretIndex = textbox.LayoutLineCollection.GetIndexFromTextPoint(textbox.CaretPostion);
            OutlineItem item = textbox.LayoutLineCollection.FoldingCollection.Get(caretIndex, 1) as OutlineItem;

            if (item == null)
                return;

            string text = textbox.Document.ToString(item.Start, item.End - item.Start + 1);
            text = Actions.FitOutlineLevel(text, item, item.Level + 1);

            textbox.Document.Replace(item.Start, item.End - item.Start + 1, text);

            textbox.Refresh();

        }

        void DownLevelCommand(object sender, ExecutedRoutedEventArgs e)
        {
            FooTextBox textbox = this.outlineWindow.Content.Target.TextBox;
            int caretIndex = textbox.LayoutLineCollection.GetIndexFromTextPoint(textbox.CaretPostion);
            OutlineItem item = textbox.LayoutLineCollection.FoldingCollection.Get(caretIndex, 1) as OutlineItem;

            if (item == null || item.Level == 0)
                return;

            string text = textbox.Document.ToString(item.Start, item.End - item.Start + 1);
            text = Actions.FitOutlineLevel(text, item, item.Level - 1);

            textbox.Document.Replace(item.Start, item.End - item.Start + 1, text);

            textbox.Refresh();
        }
        #endregion
    }
}
