using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Diagnostics;
using System.Threading;
using System.ComponentModel;

using pdftron;
using pdftron.PDF;
using pdftron.Common;

namespace PDFViewWPFTestCS
{
    /// <summary>
    /// Interaction logic for WholeDocumentSearchControl.xaml
    /// </summary>
    public partial class WholeDocumentSearchControl : UserControl
    {
        internal class SearchResult
        {
            internal String AmbientString { get; set; }
            internal String ToolTipString { get; set; }
            internal int PageNumber;
            internal String ResultString { get; set; }
            internal Highlights highlights { get; private set; }

            internal SearchResult(int pagenum, string result, string ambient, Highlights hlts)
            {
                AmbientString = ambient;
                PageNumber = pagenum;
                ToolTipString = ambient + "\nPage " + pagenum;
                ResultString = result;
                highlights = hlts;
            }

            public override string ToString()
            {
                return AmbientString;
            }
        }        

        internal PDFViewWPF _current_viewer;
        private pdftron.PDF.Tools.ToolManager _toolManager;

        pdftron.PDF.TextSearch textSearch;
        internal List<SearchResult> SearchResults;
        pdftron.PDF.TextSearch.ResultCode resultCode;
        internal List<Highlights> hlt_list;

        private BackgroundWorker bw;
        DoWorkEventArgs returnArgs;
        bool _cancelled;

        #region Property

        public String SearchTerm { get; set; }
        public PDFDoc _doc { get; set; }
        public int FoundCount { get; private set; }
        public int CurrentPage { get; private set; }

        #endregion

        public WholeDocumentSearchControl()
        {
            InitializeComponent();
            bw = new BackgroundWorker();
            bw.WorkerSupportsCancellation = true;
            bw.WorkerReportsProgress = true;
            bw.DoWork += new DoWorkEventHandler(StartSearch);
            bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(SearchComplete);
            bw.ProgressChanged += new ProgressChangedEventHandler(SearchProgressChanged);
        }

        #region Methods

        public void EnableSearch(PDFViewWPF viewer, pdftron.PDF.Tools.ToolManager toolManager)
        {
            if (viewer == null || viewer.GetDoc() == null) return;
            _current_viewer = viewer;
            _toolManager = toolManager;
            _doc = viewer.GetDoc();
            ListSearchResults.Items.Clear();
            SearchResults = new List<SearchResult>();
            hlt_list = new List<Highlights>();
        }       

        private class InformationForSearch
        {
            public InformationForSearch(string searchString, pdftron.PDF.TextSearch.SearchMode textSearchModes)
            {
                SearchString = searchString;
                Mode = textSearchModes;
            }
            public string SearchString;
            public pdftron.PDF.TextSearch.SearchMode Mode;
        }

        public void Search(String searchString, pdftron.PDF.TextSearch.SearchMode textSearchModes)
        {
            if (bw.IsBusy)
            {
                bw.CancelAsync();
            }
            else
            {
                _progressBar.Maximum = _current_viewer.GetPageCount();
                InformationForSearch ifs = new InformationForSearch(searchString, textSearchModes);
                bw.RunWorkerAsync(ifs);
            }
        }

        private void SearchWithOptions()
        {
            pdftron.PDF.TextSearch.SearchMode mode = pdftron.PDF.TextSearch.SearchMode.e_ambient_string | pdftron.PDF.TextSearch.SearchMode.e_highlight | pdftron.PDF.TextSearch.SearchMode.e_page_stop;
            if (WholeWordCheckBox.IsChecked == true)
                mode |= pdftron.PDF.TextSearch.SearchMode.e_whole_word;
            if (CaseSensitiveCheckBox.IsChecked == true)
                mode |= pdftron.PDF.TextSearch.SearchMode.e_case_sensitive;
            Search(this.SearchTerm, mode);
        }

        internal static void FormatText(ref TextBlock tb, string PartToFormat, FontWeight FontWeight)
        {
            string Text = tb.Text;
            tb.Inlines.Clear();

            Run r = new Run();
            r.Text = Text.Substring(0, Text.IndexOf(PartToFormat, StringComparison.OrdinalIgnoreCase));
            tb.Inlines.Add(r);

            r = new Run();
            r.Text = Text.Substring(Text.IndexOf(PartToFormat, StringComparison.OrdinalIgnoreCase), PartToFormat.Length);
            r.FontWeight = FontWeight;
            tb.Inlines.Add(r);

            r = new Run();
            r.Text = Text.Substring(Text.IndexOf(PartToFormat) + PartToFormat.Length, Text.Length - (Text.IndexOf(PartToFormat) + PartToFormat.Length));
            tb.Inlines.Add(r);
        }

        #endregion

        #region Events

        void SearchProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            _progressBar.Value = e.ProgressPercentage;
            _summary.Text = String.Format("{0} instances in active document ({1} pages searched)", FoundCount, CurrentPage);
        }

        void SearchComplete(object sender, RunWorkerCompletedEventArgs e)
        {
            _progressBar.Value = 0;
            if (_cancelled)
            {
                _summary.Text = String.Format("{0} instances in active document (aborted)", FoundCount);
                //MessageBox.Show("Search Cancelled");
            }
            else
            { 
                _summary.Text = String.Format("{0} instances in active document ({1} pages searched)", FoundCount, _current_viewer.GetPageCount());
                //MessageBox.Show("Search Completed");
            }
            CancelSearch.IsEnabled = false;
            return;
        }

        void StartSearch(object sender, DoWorkEventArgs e)
        {
            returnArgs = e;
            this.Dispatcher.BeginInvoke((System.Action)delegate()
            {
                this.ListSearchResults.Items.Clear();
            });
            SearchResults.Clear();
            hlt_list.Clear();

            if (_current_viewer.GetDoc() != null)
                textSearch = new pdftron.PDF.TextSearch();
            else
                throw new Exception("WholeDocumentSearchControl Document property cannot be null.");

            pdftron.PDF.TextSearch.SearchMode mode = (e.Argument as InformationForSearch).Mode;
            textSearch.Begin(_doc, SearchTerm, (Int32)mode, 1, _current_viewer.GetPageCount());
            FoundCount = 0;
            CurrentPage = 0;

            int page_num = 0;
            String result_str = string.Empty;
            String ambient_str = string.Empty;
            Highlights hlts = new Highlights();
            
            try
            {
                while (true)
                {
                    Thread.Sleep(1);
                    _doc.Lock();

                    if (bw.CancellationPending)
                    {
                        _doc.Unlock();
                        returnArgs.Cancel = true;
                        return;
                    }

                    hlts = new Highlights();
                    resultCode = textSearch.Run(ref page_num, ref result_str, ref ambient_str, hlts);
                    CurrentPage = textSearch.GetCurrentPage();
                    bw.ReportProgress(CurrentPage);                    

                    if (resultCode == pdftron.PDF.TextSearch.ResultCode.e_found)
                    {
                        SearchResult result = new SearchResult(page_num, result_str, ambient_str, hlts);
                        SearchResults.Add(result);
                        hlt_list.Add(hlts);
                        FoundCount++;

                        this.Dispatcher.BeginInvoke((System.Action)delegate()
                        {
                            TextBlock b = new TextBlock();
                            TextBlock t = new TextBlock();
                            b.Text = result.AmbientString;
                            t.Text = result.ToolTipString;
                            FormatText(ref b, result.ResultString, FontWeights.Bold);
                            FormatText(ref t, result.ResultString, FontWeights.Bold);

                            ToolTipService.SetToolTip(b, t);
                            ListSearchResults.Items.Add(b);
                        });

                        _doc.Unlock();                        
                    }
                    else if (resultCode == pdftron.PDF.TextSearch.ResultCode.e_page)
                    {
                        _doc.Unlock();
                    }
                    else
                    {
                        _doc.Unlock();
                        return;
                    }                    
                }
            }
            catch
            {
                _doc.Unlock();
                Debug.WriteLine("Text search exception happend.");
            }            
        }

        private void SearchTextBox_KeyDown(object sender, KeyEventArgs e)
        {
            if (_current_viewer != null && _current_viewer.GetPageCount() > 0 && e.Key == Key.Enter)
            {
                _cancelled = false;
                SearchTerm = SearchTextBox.Text.TrimStart();
                SearchTerm = SearchTerm.TrimEnd();
                if (!string.IsNullOrWhiteSpace(SearchTerm))
                {
                    SearchWithOptions();
                    CancelSearch.IsEnabled = true;
                }
            }
        }

        private void SearchButton_Click(object sender, RoutedEventArgs e)
        {
            _cancelled = false;
            if (_current_viewer == null) return;
            SearchTerm = SearchTextBox.Text.TrimStart();
            SearchTerm = SearchTerm.TrimEnd();
            if (!string.IsNullOrWhiteSpace(SearchTerm))
            {
                SearchWithOptions();
                CancelSearch.IsEnabled = true;
            }
        }

        private void CancelSearch_Click(object sender, RoutedEventArgs e)
        {
            _cancelled = true;
            bw.CancelAsync();
            CancelSearch.IsEnabled = false;
        }

        private void ListSearchResults_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (ListSearchResults.SelectedIndex >= 0)
            {
                Highlights hlt = hlt_list[ListSearchResults.SelectedIndex];

                hlt.Begin(_doc);

                _current_viewer.SetCurrentPage(hlt.GetCurrentPageNumber());
                _current_viewer.Select(hlt);
                _current_viewer.SetVScrollPos(_current_viewer.GetVScrollPos());
                _current_viewer.SetHScrollPos(_current_viewer.GetHScrollPos());

                _toolManager.CurrentTool.TextSelectionHasChanged();
            }
        }

        #endregion

    }
}
