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 pdftron;
using pdftron.PDF;
using pdftron.SDF;
using pdftron.Filters;
using pdftron.Common;
using pdftron.PDF.Tools;

namespace PDFViewWPFSimple
{
     ///<summary>
     ///Interaction logic for MainWindow.xaml
     ///</summary>
    public partial class MainWindow : Window
    {
        private static pdftron.PDFNetLoader pdfNetLoader = pdftron.PDFNetLoader.Instance();
        static MainWindow() {}

        public PDFViewWPF PDFViewWPF
        {
            get { return MyPDFView; } // from xaml
        }
        private ToolManager _toolManager;
        private PDFDoc _pdfdoc;
        private String filePath;
        FindTextDialog _findTextDialog;

        private bool _updatingFromPDFViewWPF = false;

        public MainWindow()
        {
            // Initialize PDFNet.
            try
            {
                PDFNet.Initialize(PDFTronLicense.Key);
            }
            catch (pdftron.Common.PDFNetException ex)
            {
                MessageBox.Show(ex.GetMessage(), "Licensing Error");
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(ex.Message, "Licensing Error");
            }
            InitializeComponent();
            _toolManager = new ToolManager(PDFViewWPF);
            this.KeyDown += new KeyEventHandler(MainWindow_KeyDown);
            this.KeyUp += new KeyEventHandler(MainWindow_KeyUp);
            txtbox_zoom.KeyDown += new KeyEventHandler(txtbox_zoom_KeyDown);
            slider_zoom.ValueChanged += new RoutedPropertyChangedEventHandler<double>(slider_zoom_ValueChanged);
            txtbox_pagenum.KeyDown += txtbox_pagenum_KeyDown;
            PDFViewWPF.CurrentZoomChanged += PDFViewWPF_CurrentZoomChanged; // set zoom textbox value
            PDFViewWPF.CurrentPageNumberChanged += PDFViewWPF_CurrentPageNumberChanged;
            this.Closing += new System.ComponentModel.CancelEventHandler(MainWindow_Closing);
            PDFViewWPF.OnSetDoc += PDFViewWPF_OnSetDoc;
            PDFViewWPF.FindTextFinished += PDFViewWPF_FindTextFinished;
        }

        public bool OpenPDF(String filename)
        {
            try
            {
                PDFDoc oldDoc = PDFViewWPF.GetDoc();
                _pdfdoc = new PDFDoc(filename);

                PDFViewWPF.SetDoc(_pdfdoc);

                filePath = filename;
                if (oldDoc != null)
                {
                    oldDoc.Dispose();
                }
            }
            catch (PDFNetException ex)
            {
                MessageBox.Show(ex.Message);
                return false;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
                return false;
            }

            this.Title = filename;
            return true;
        }

        public void Save(string filename)
        {
            if (_pdfdoc == null) return;

            _pdfdoc.Lock();

            try
            {
                _pdfdoc.Save(filename, pdftron.SDF.SDFDoc.SaveOptions.e_remove_unused);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), "Error during the Save");
            }
            _pdfdoc.Unlock();
        }

        #region DependencyPropertyBinding

        internal void SetPropertyBinding(PDFViewWPF viewer, DependencyProperty dp, string propertyName, FrameworkElement element)
        {
            Binding b = new Binding(propertyName) { Source = element };
            b.Mode = BindingMode.TwoWay;
            viewer.SetBinding(dp, b);
        }

        #endregion

        #region Events

        void PDFViewWPF_OnSetDoc(PDFViewWPF viewer)
        {
            _updatingFromPDFViewWPF = true;
            int val = (int)Math.Round(PDFViewWPF.GetZoom() * 100);
            slider_zoom.Value = PDFViewWPF.GetZoom();
            txtbox_zoom.Text = val.ToString();
            txtbox_pagenum.Text = "" + PDFViewWPF.GetCurrentPage();
            _updatingFromPDFViewWPF = false;
        }

        void PDFViewWPF_CurrentPageNumberChanged(PDFViewWPF viewer, int currentPage, int totalPages)
        {
            txtbox_pagenum.Text = "" + currentPage;
        }

        void slider_zoom_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            int val = (int)Math.Round(e.NewValue * 100);
            if (!_updatingFromPDFViewWPF)
            {
                txtbox_zoom.Text = val.ToString();
                PDFViewWPF.SetZoom(e.NewValue, true);
            }
        }

        void PDFViewWPF_CurrentZoomChanged(PDFViewWPF viewer)
        {
            _updatingFromPDFViewWPF = true;
            int val = (int)Math.Round(PDFViewWPF.GetZoom() * 100);
            slider_zoom.Value = PDFViewWPF.GetZoom();
            txtbox_zoom.Text = val.ToString();
            _updatingFromPDFViewWPF = false;
        }

        private void txtbox_zoom_KeyDown(object sender, KeyEventArgs e)
        {

            if (e.Key == Key.Enter && !string.IsNullOrWhiteSpace(txtbox_zoom.Text))
            {
                int newzoom;
                if (Int32.TryParse(txtbox_zoom.Text, out newzoom))
                    PDFViewWPF.SetZoom(newzoom / 100);
            }
        }

        void txtbox_pagenum_KeyDown(object sender, KeyEventArgs e)
        {
            int pgnum;
            if (Int32.TryParse(txtbox_pagenum.Text, out pgnum))
                PDFViewWPF.SetCurrentPage(pgnum);
        }

        private void MainWindow_KeyDown(object sender, KeyEventArgs e)
        {
            if ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
            {
                if (e.Key == Key.F)
                {
                    if (_findTextDialog == null)
                    {
                        _findTextDialog = new FindTextDialog();
                        _findTextDialog.Owner = this;
                        _findTextDialog.Show();
                        _findTextDialog.Closed += FindTextDialog_Closed;
                    }
                    else
                    {
                        _findTextDialog.Activate();
                    }
                }

                if (e.Key == Key.S)
                {
                    if (_pdfdoc != null && PDFViewWPF != null && (_pdfdoc.IsModified()))
                        this.Save(_pdfdoc.GetFileName());
                }
            }
        }

        void FindTextDialog_Closed(object sender, EventArgs e)
        {
            _findTextDialog = null;
        }

        void MainWindow_KeyUp(object sender, KeyEventArgs e)
        {

        }

        void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (_pdfdoc != null && PDFViewWPF != null && (_pdfdoc.IsModified()))
            {
                string messageBoxText = "Would you like to save changes to " + _pdfdoc.GetFileName() + "?";
                string caption = "PDFViewWPF";
                MessageBoxButton button = MessageBoxButton.YesNoCancel;
                MessageBoxImage icon = MessageBoxImage.Question;
                MessageBoxResult defaultResult = MessageBoxResult.Yes;
                MessageBoxOptions options = MessageBoxOptions.DefaultDesktopOnly;

                MessageBoxResult result;
                result = MessageBox.Show(messageBoxText, caption, button, icon, defaultResult, options);

                if (result == MessageBoxResult.Yes)
                {
                    this.Save(_pdfdoc.GetFileName());
                }
                else if (result == MessageBoxResult.No)
                {
                    PDFViewWPF.CloseDoc();
                }
                else
                {
                    e.Cancel = true;
                }
            }
        }

        private void btnOpen_Clicked(object sender, RoutedEventArgs e)
        {
            Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
            dlg.CheckFileExists = true;
            dlg.CheckPathExists = true;
            dlg.Filter = "PDF (*.pdf)|*.pdf|All files (*.*)|*.*";
            dlg.DefaultExt = ".pdf";

            if (dlg.ShowDialog() == true)
            {
                OpenPDF(dlg.FileName);
                toolbar_header2.IsEnabled = true;
                toolbar_header3.IsEnabled = true;
                toolbar_footer.IsEnabled = true;
                txt_pagecount.Content = " / " + PDFViewWPF.GetPageCount().ToString();
                t_pan.IsChecked = true;
            }
        }

        private void btn_Prev_Clicked(object sender, RoutedEventArgs e)
        {
            if (PDFViewWPF.GetDoc() != null)
                PDFViewWPF.GotoPreviousPage();
        }

        private void btn_Next_Clicked(object sender, RoutedEventArgs e)
        {
            if (PDFViewWPF.GetDoc() != null)
                PDFViewWPF.GotoNextPage();
        }

        private void btn_ZoomIn_Clicked(object sender, RoutedEventArgs e)
        {
            if (PDFViewWPF.GetDoc() != null)
                PDFViewWPF.SetZoom(PDFViewWPF.GetZoom() * 1.25);
        }

        private void btn_ZoomOut_Clicked(object sender, RoutedEventArgs e)
        {
            if (PDFViewWPF.GetDoc() != null)
                PDFViewWPF.SetZoom(PDFViewWPF.GetZoom() / 1.25);
        }

        private void btnExit_Clicked(object sender, RoutedEventArgs e)
        {
            this.Close();
        }

        private void btn_LastPage_Clicked(object sender, RoutedEventArgs e)
        {
            if (PDFViewWPF.GetDoc() != null)
                PDFViewWPF.GotoLastPage();
        }

        private void btn_FirstPage_Clicked(object sender, RoutedEventArgs e)
        {
            if (PDFViewWPF.GetDoc() != null)
                PDFViewWPF.GotoFirstPage();
        }

        private void btn_RotateCCW_Clicked(object sender, RoutedEventArgs e)
        {
            GC.Collect();
            if (PDFViewWPF.GetDoc() != null)
                PDFViewWPF.RotateCounterClockwise();
        }

        private void btn_RotateCW_Clicked(object sender, RoutedEventArgs e)
        {
            if (PDFViewWPF.GetDoc() != null)
                PDFViewWPF.RotateClockwise();
        }

        private void FitWidth_Clicked(object sender, RoutedEventArgs e)
        {
            if (PDFViewWPF.GetDoc() != null)
                PDFViewWPF.SetPageViewMode(PDFViewWPF.PageViewMode.e_fit_width);
        }

        private void FitPageClicked(object sender, RoutedEventArgs e)
        {
            if (PDFViewWPF.GetDoc() != null)
                PDFViewWPF.SetPageViewMode(PDFViewWPF.PageViewMode.e_fit_page);
        }

        private void SinglePage_Clicked(object sender, RoutedEventArgs e)
        {
            if (PDFViewWPF.GetDoc() != null)
                PDFViewWPF.SetPagePresentationMode(PDFViewWPF.PagePresentationMode.e_single_page);
        }

        private void SingleContinuous_Clicked(object sender, RoutedEventArgs e)
        {
            if (PDFViewWPF.GetDoc() != null)
                PDFViewWPF.SetPagePresentationMode(PDFViewWPF.PagePresentationMode.e_single_continuous);
        }

        private void Facing_Clicked(object sender, RoutedEventArgs e)
        {
            if (PDFViewWPF.GetDoc() != null)
                PDFViewWPF.SetPagePresentationMode(PDFViewWPF.PagePresentationMode.e_facing);
        }

        private void FacingContinuous_Clicked(object sender, RoutedEventArgs e)
        {
            if (PDFViewWPF.GetDoc() != null)
                PDFViewWPF.SetPagePresentationMode(PDFViewWPF.PagePresentationMode.e_facing_continuous);
        }

        private void FacingCoverContinuous_Clicked(object sender, RoutedEventArgs e)
        {
            if (PDFViewWPF.GetDoc() != null)
                PDFViewWPF.SetPagePresentationMode(PDFViewWPF.PagePresentationMode.e_facing_continuous_cover);
        }

        private void FacingCover_Clicked(object sender, RoutedEventArgs e)
        {
            if (PDFViewWPF.GetDoc() != null)
                PDFViewWPF.SetPagePresentationMode(PDFViewWPF.PagePresentationMode.e_facing_cover);
        }

        private void btnSave_Clicked(object sender, RoutedEventArgs e)
        {
            if (_pdfdoc != null && PDFViewWPF != null)
            {
                this.Save(_pdfdoc.GetFileName());
            }
        }

        private void btnSaveAs_Clicked(object sender, RoutedEventArgs e)
        {
            if (_pdfdoc != null && PDFViewWPF != null)
            {
                Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
                dlg.Filter = "PDF Files (*.pdf)|*.pdf|All Files (*.*)|*.*";
                dlg.DefaultExt = ".pdf";
                dlg.FileName = _pdfdoc.GetFileName();

                if (dlg.ShowDialog() == true)
                {
                    this.Save(dlg.FileName);
                }
            }
        }

        private void btnClose_Clicked(object sender, RoutedEventArgs e)
        {
            PDFDoc doc = PDFViewWPF.GetDoc();
            PDFViewWPF.CloseDoc();
            //if (doc != null)
            //{
            //    doc.Dispose();
            //}
        }
        

        private void btnSelectAll_Clicked(object sender, RoutedEventArgs e)
        {
            PDFViewWPF.SelectAll();
        }

        private void btnDeselectAll_Clicked(object sender, RoutedEventArgs e)
        {
            PDFViewWPF.ClearSelection();
        }

        #endregion

        #region ToolMode

        private void OnPan_Clicked(object sender, RoutedEventArgs e)
        {
            if (PDFViewWPF.GetDoc() != null)
            {
                _toolManager.CreateTool(ToolManager.ToolType.e_pan);
                t_text_rect.IsChecked = false;
                t_text_struct.IsChecked = false;
            }
        }

        private void OnSelectStruct_Clicked(object sender, RoutedEventArgs e)
        {
            if (PDFViewWPF.GetDoc() != null)
            {
                _toolManager.CreateTool(ToolManager.ToolType.e_text_select);
                t_pan.IsChecked = false;
                t_text_rect.IsChecked = false;
            }
        }

        private void OnSelectRect_Clicked(object sender, RoutedEventArgs e)
        {
            if (PDFViewWPF.GetDoc() != null)
            {
                _toolManager.CreateTool(ToolManager.ToolType.e_text_select_rectangular);
                t_pan.IsChecked = false;
                t_text_struct.IsChecked = false;
            }
        }
        #endregion

        private PDFViewWPF.Selection _currentSearchSelection;
        private List<Rectangle> _onScreenSelection = new List<Rectangle>();

        void PDFViewWPF_FindTextFinished(PDFViewWPF viewer, bool found, PDFViewWPF.Selection selection)
        {
            if (_findTextDialog != null)
            {
                _currentSearchSelection = selection;
                HighlightSelection();
                PDFViewWPF.ClearSelection();
                //_toolManager.ClearSelectedTextHighlighting();
                _findTextDialog.TextSearchFinished(viewer, found, selection);
            }

        }

        /// <summary>
        /// Highlights the search result if any
        /// </summary>
        /// <param name="result">A text selection acquired by mPDFView.FindText</param>
        /// <returns>true if and only if the selections contains at least one highlight</returns>
        private bool HighlightSelection()
        {
            ClearSearchSelection();
            if (_currentSearchSelection == null)
            {
                return false;
            }

            double[] quads = _currentSearchSelection.GetQuads();
            int numQuads = quads.Length / 8;
            int pageNumber = _currentSearchSelection.GetPageNum();
            int quadNumber = 0;
            List<System.Windows.Rect> rects = new List<System.Windows.Rect>();

            // get highlights in control (screen) space
            for (int i = 0; i < numQuads; i++)
            {
                quadNumber = i * 8;
                double x1 = quads[quadNumber + 0];
                double y1 = quads[quadNumber + 1];

                double x2 = quads[quadNumber + 2];
                double y2 = quads[quadNumber + 3];

                double x3 = quads[quadNumber + 4];
                double y3 = quads[quadNumber + 5];

                double x4 = quads[quadNumber + 6];
                double y4 = quads[quadNumber + 7];

                PDFViewWPF.ConvPagePtToScreenPt(ref x1, ref y1, pageNumber);
                PDFViewWPF.ConvPagePtToScreenPt(ref x2, ref y2, pageNumber);
                PDFViewWPF.ConvPagePtToScreenPt(ref x3, ref y3, pageNumber);
                PDFViewWPF.ConvPagePtToScreenPt(ref x4, ref y4, pageNumber);

                double left, right, top, bottom;

                left = Math.Min(x1, Math.Min(x2, Math.Min(x3, x4)));
                right = Math.Max(x1, Math.Max(x2, Math.Max(x3, x4)));
                top = Math.Min(y1, Math.Min(y2, Math.Min(y3, y4)));
                bottom = Math.Max(y1, Math.Max(y2, Math.Max(y3, y4)));

                rects.Add(new System.Windows.Rect(left, top, right - left, bottom - top));
            }

            Canvas annotCanvas = PDFViewWPF.GetCanvas();

            // add highlight(s) to annotation canvas
            foreach (System.Windows.Rect rect in rects)
            {
                Rectangle highlight = new Rectangle();
                highlight.Fill = new SolidColorBrush() { Color = Colors.Blue };
                highlight.Fill.Opacity = 0.3;
                highlight.Width = rect.Width;
                highlight.Height = rect.Height;
                Canvas.SetLeft(highlight, rect.Left + PDFViewWPF.GetHScrollPos());
                Canvas.SetTop(highlight, rect.Top + PDFViewWPF.GetVScrollPos());
                annotCanvas.Children.Add(highlight);
                _onScreenSelection.Add(highlight);
            }

            return numQuads > 0;
        }

        /// <summary>
        /// Removes the rectangles highlighting the selection, but keeps the selection for future reference
        /// to be used with HighlightSelection
        /// </summary>
        /// <param name="deleteSelection">If true, will also delete the underlaying selection</param>
        public void ClearSearchSelection(bool deleteSelection = false)
        {
            foreach (Rectangle rect in _onScreenSelection)
            {
                Canvas parent = rect.Parent as Canvas;
                if (parent != null)
                {
                    parent.Children.Remove(rect);
                }
            }
            if (deleteSelection)
            {
                _currentSearchSelection = null;
            }
        }

    }
}
