using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using foxit.pdf;
using PDFReader_Demo_CSharp.Common;

namespace PDFReader_Demo_CSharp.UI
{
    public enum SearchContextState
    {
        SearchNone,
        SearchStart,
        SearchNoFind,
        SearchFind,
        SearchFindEnd,
        SearchStop
    }

    public class SearchEventArgs : EventArgs
    {
        internal SearchEventArgs(SearchContextState state, int page_index, foxit.pdf.TextSearch text_search)
        {
            State = state;
            PageIndex = page_index;
            SearchHandle = text_search;
        }

        public SearchContextState State { get; set; }
        public int PageIndex { get; set; }
        public TextSearch SearchHandle { get; set; }
    }

    class SearchContext : IDisposable
    {
        private CPDFReaderDoc reader_doc_;
        private bool is_searching_ = false;
        private int start_find_page_index_;
        private int current_page_index_;

        private string search_string_ = null;
        private int search_flag_;
        private bool is_forward_direction_;

        private string search_string_last_ = null;
        private int search_flag_last_;
        private bool is_forward_direction_last_;

        private foxit.pdf.TextSearch text_search_;
        private bool has_find_;
        private int last_find_charindex_;

        public event EventHandler<SearchEventArgs> SearchResult;

        public SearchContext(CPDFReaderDoc pdf_doc)
        {
            this.reader_doc_ = pdf_doc;
            last_find_charindex_ = -1;
        }

        ~SearchContext()
        {
            Dispose();
        }

        public void Dispose()
        {
            text_search_ = null;
            reader_doc_ = null;
        }

        public bool IsSearching
        {
            get
            {
                return this.is_searching_;
            }
        }

        public void StartSearch(int page_index, string string_to_find, bool is_match_case_sensitive, bool is_match_whole_word, int direction)
        {
            if (string_to_find.Equals(""))
            {
                System.Windows.Forms.MessageBox.Show("Searching content is blank!", "Information", System.Windows.Forms.MessageBoxButtons.OK);
                return;
            }

            start_find_page_index_ = page_index;
            current_page_index_ = start_find_page_index_;
            search_string_ = string_to_find;
            is_searching_ = true;

            int flag = 0;
            if (is_match_case_sensitive) { flag |= (int)TextSearch.SearchFlags.e_SearchMatchCase; }
            if (is_match_whole_word) { flag |= (int)TextSearch.SearchFlags.e_SearchMatchWholeWord; }
            search_flag_ = flag;

            is_forward_direction_ = direction == 0 ? true : false;

            SearchNext(direction == 0 ? true : false);

            search_string_last_ = search_string_;
            search_flag_last_ = search_flag_;
            is_forward_direction_last_ = is_forward_direction_;
        }

        public void StopSearch()
        {
            is_searching_ = false;
            search_string_ = null;
            search_flag_ = 0;
            start_find_page_index_ = -1;

            OnSearchResult(SearchContextState.SearchStop,  -1, null);
        }

        public void SearchNext(bool is_forward = true)
        {
            bool is_match = false;
            int page_count = reader_doc_.GetPageCount();

            if (search_string_last_ == search_string_ && search_flag_last_ == search_flag_ && is_forward_direction_last_ == is_forward_direction_)
            {
                is_match = is_forward_direction_ ? text_search_.FindNext() : text_search_.FindPrev();
            }
            else
            {
                bool bIsDynamicXFA = reader_doc_.IsDynamicXFA();

                text_search_ = bIsDynamicXFA ? new TextSearch(reader_doc_.GetXFADoc(), null) : new TextSearch(reader_doc_.GetPDFDocument(), null, 0);
                text_search_.SetSearchFlags((int)search_flag_);
                text_search_.SetStartPage(current_page_index_);
                text_search_.SetEndPage(is_forward ? page_count - 1 : 0);
                text_search_.SetPattern(search_string_, false);
                has_find_ = false;

                if (is_forward_direction_)
                {
                    is_match = text_search_.FindNext();
                    if (last_find_charindex_ != -1)
                    {
                        int nFindCharIndex = text_search_.GetMatchStartCharIndex();
                        int nFindPageIndex = text_search_.GetMatchPageIndex();
                        while (is_match && nFindPageIndex == start_find_page_index_ && nFindCharIndex <= last_find_charindex_)
                        {
                            is_match = text_search_.FindNext();
                            nFindCharIndex = text_search_.GetMatchStartCharIndex();
                            nFindPageIndex = text_search_.GetMatchPageIndex();
                        }
                    }
                }
                else
                {
                    is_match = text_search_.FindPrev();
                    if (last_find_charindex_ != -1)
                    {
                        int nFindCharIndex = text_search_.GetMatchStartCharIndex();
                        int nFindPageIndex = text_search_.GetMatchPageIndex();
                        while (is_match && nFindPageIndex == start_find_page_index_ && nFindCharIndex >= last_find_charindex_)
                        {
                            is_match = text_search_.FindPrev();
                            nFindCharIndex = text_search_.GetMatchStartCharIndex();
                            nFindPageIndex = text_search_.GetMatchPageIndex();
                        }
                    }
                }

                if (is_match)
                {
                    if (!has_find_)
                        has_find_ = true;
                }
            }

            SearchContextState state = 0;
            if (!has_find_)
            {
                state = SearchContextState.SearchNoFind;
                last_find_charindex_ = -1;
                is_searching_ = false;
            }
            else
            {
                if (is_match)
                {
                    state = SearchContextState.SearchFind;
                    last_find_charindex_ = text_search_.GetMatchStartCharIndex();
                }
                else
                {
                    state = SearchContextState.SearchFindEnd;
                    last_find_charindex_ = -1;
                    is_searching_ = false;
                    search_string_ = "";
                }
            }
            System.Diagnostics.Debug.WriteLine(string.Format("GetMatchPageIndex: {0}", text_search_.GetMatchPageIndex()));
            OnSearchResult(state, is_match ? text_search_.GetMatchPageIndex() : -1, text_search_);
        }

        protected void OnSearchResult(SearchContextState state, int page_index, foxit.pdf.TextSearch text_search)
        {
            SearchEventArgs search_event_args = new SearchEventArgs(state, page_index, text_search);

            OnSearchResult(search_event_args);
        }

        protected void OnSearchResult(SearchEventArgs e)
        {
            EventHandler<SearchEventArgs> handler = SearchResult;
            if (handler != null)
            {
                handler(this, e);
            }
        }
    }
}
