using System;
using System.Linq;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using FooEditEngine;
using FooEditEngine.WPF;
using Prop = FooEditor.Properties;

namespace FooEditor
{
    /// <summary>
    /// FindReplaceWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class FindReplaceWindow : UserControl
    {
        private DocumentWindow CurrentDocument;
        private MainWindow Main;
        private int currentIndex;

        public FindReplaceWindow()
        {
            InitializeComponent();
            this.Title = "検索と置き換え";

            this.CommandBindings.Add(new CommandBinding(FindReplaceCommands.FindStart, FindStartCommand));
            this.CommandBindings.Add(new CommandBinding(FindReplaceCommands.ReplaceStart, ReplaceStartCommand));
            this.CommandBindings.Add(new CommandBinding(FindReplaceCommands.ReplaceAllStart, ReplaceAlStartlCommand));

            this.FindText.TextChanged += new TextChangedEventHandler(FindText_TextChanged);

            this.AllDocuments.Checked += AllDocuments_Checked;
        }

        const string SearchResultIteratorName = "SearchResult";

        IEnumerator<SearchResult> GetSearchResultIterator(DocumentWindow doc)
        {
            object value;
            if (doc.ExtraDataCollection.TryGetValue("SearchResult", out value))
                return (IEnumerator<SearchResult>)value;
            else
                return null;
        }

        void AllDocuments_Checked(object sender, RoutedEventArgs e)
        {
            this.Reset();
        }

        public FindReplaceWindow(MainWindow main) : this()
        {
            this.Main = main;
            this.Main.ActiveDocumentChanged += Main_ActiveDocumentChanged;
            this.Main.Documents.CollectionChanged += Documents_CollectionChanged;
        }

        void Documents_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            this.Reset();
        }

        void Main_ActiveDocumentChanged(object sender, EventArgs e)
        {
            this.CurrentDocument = this.Main.ActiveDocument;
        }

        void Reset(DocumentWindow targetDoc = null)
        {
            if (targetDoc == null)
            {
                foreach (DocumentWindow doc in this.Main.Documents)
                    doc.ExtraDataCollection.Remove(SearchResultIteratorName);
            }
            else
            {
                targetDoc.ExtraDataCollection.Remove(SearchResultIteratorName);
            }
            this.currentIndex = 0;
            this.CurrentDocument = null;
        }

        public string Title
        {
            get;
            set;
        }

        void FindText_TextChanged(object sender, TextChangedEventArgs e)
        {
            this.Reset();
        }

        private RegexOptions DecideRegexOpt()
        {
            RegexOptions opt = RegexOptions.None;
            if (this.RestrictSearch.IsChecked == true)
                opt |= RegexOptions.IgnoreCase;
            return opt;
        }

        void FindStartCommand(object sender, ExecutedRoutedEventArgs e)
        {
            if (this.CurrentDocument == null)
            {
                if ((bool)this.AllDocuments.IsChecked)
                    this.CurrentDocument = this.Main.Documents.First();
                else
                    this.CurrentDocument = this.Main.ActiveDocument;
                this.Main.ActivateDocument(this.CurrentDocument);
            }

            findstartbegin:
            
            if ((bool)this.AllDocuments.IsChecked && this.CurrentDocument != this.Main.Documents[this.currentIndex])
                this.Main.ActivateDocument(this.Main.Documents[this.currentIndex]);

            DocumentWindow docwnd = this.CurrentDocument;

            if (docwnd.TextBox.RectSelectMode)
            {
                MessageBox.Show(Prop.Resources.MustBeDisableRectSelect);
                return;
            }

            IEnumerator<SearchResult> it = this.GetSearchResultIterator(docwnd);
            if (it == null)
            {
                try
                {
                    docwnd.TextBox.Document.SetFindParam(this.FindText.Text, (bool)this.UseRegEx.IsChecked, DecideRegexOpt());
                    it = docwnd.TextBox.Document.Find();
                    docwnd.ExtraDataCollection.Add(SearchResultIteratorName, it);
                }
                catch (ArgumentException ex)
                {
                    MessageBox.Show(ex.Message);
                    return;
                }
            }

            if (!it.MoveNext())
            {
                docwnd.TextBox.DeSelectAll();
                if ((bool)this.AllDocuments.IsChecked)
                {
                    this.currentIndex++;
                    if (this.currentIndex < this.Main.Documents.Count)
                    {
                        this.Main.ActivateDocument(this.Main.Documents[this.currentIndex]);
                        goto findstartbegin;    //スタックの浪費を防ぐため
                    }
                    this.Reset();
                }
                else
                {
                    this.Reset(docwnd);
                }
                MessageBox.Show(Prop.Resources.FindDialogNotFound);
                return;
            }

            SearchResult sr = it.Current;
            docwnd.TextBox.JumpCaret(sr.End);
            docwnd.TextBox.Select(sr.Start, sr.End - sr.Start + 1);
            docwnd.TextBox.Refresh();

            this.ReplaceButton.IsEnabled = true;
        }

        void ReplaceStartCommand(object sender, ExecutedRoutedEventArgs e)
        {
            DocumentWindow docwnd = this.CurrentDocument;
            IEnumerator<SearchResult> it = this.GetSearchResultIterator(docwnd);
            if ((bool)this.UseGroup.IsChecked)
                docwnd.TextBox.SelectedText = it.Current.Result(this.ReplaceText.Text);
            else
                docwnd.TextBox.SelectedText = this.ReplaceText.Text;
            this.FindStartCommand(sender, e);
        }
        
        void ReplaceAlStartlCommand(object sender, ExecutedRoutedEventArgs e)
        {
            IEnumerable<DocumentWindow> docwndit;

            if ((bool)this.AllDocuments.IsChecked)
                docwndit = this.Main.Documents;
            else
                docwndit = new DocumentWindow[] { this.Main.ActiveDocument };

            foreach (DocumentWindow docwnd in docwndit)
            {
                if (docwnd.TextBox.RectSelectMode)
                {
                    MessageBox.Show(Prop.Resources.MustBeDisableRectSelect);
                    return;
                }
            }

            foreach (DocumentWindow docwnd in docwndit)
            {
                docwnd.TextBox.Document.SetFindParam(this.FindText.Text, (bool)this.UseRegEx.IsChecked, DecideRegexOpt());
                docwnd.TextBox.Document.ReplaceAll(this.ReplaceText.Text, (bool)this.UseGroup.IsChecked);
            }

            MessageBox.Show(Prop.Resources.ReplaceAllComplete);
        }
    }

    public static class FindReplaceCommands
    {
        public static RoutedCommand FindStart = new RoutedCommand("FindStart", typeof(FindReplaceWindow));
        public static RoutedCommand ReplaceStart = new RoutedCommand("ReplaceStart", typeof(FindReplaceWindow));
        public static RoutedCommand ReplaceAllStart = new RoutedCommand("ReplaceAllStart", typeof(FindReplaceWindow));
    }
}
