using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using pdftron.Common;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Controls;

using UIPoint = System.Windows.Point;
using PDFPoint = pdftron.PDF.Point;
using PDFRect = pdftron.PDF.Rect;
using PDFPage = pdftron.PDF.Page;
using pdftron.PDF;
using System.Windows.Ink;
using System.Windows.Input;


namespace pdftron.PDF.Tools
{
    public class FreehandCreate : SimpleShapeCreate
    {
        protected Path mShape;
        protected List<PDFPoint> mCurrentStrokeList = null; // A list of strokes
        protected List<List<PDFPoint>> mListOfStrokeLists = null; // Contains all the lists above
        protected PathFigureCollection mPathPoints;
        protected PathFigure mCurrentPathFigure;
        protected bool mFirstTime = false; // Whether or not a pointer has been pressed already.
        protected double mLeftmost, mRightmost, mTopmost, mBottommost;
        protected bool mCreateMultiPathAnnotation = false;
        protected int mShapePageNumber = 0;
        protected bool mIgnoreMouseEvents = false;
        protected bool mSmoothInk = true;

        protected bool mUseInkCanvas = false;
        protected Dictionary<int, InkCanvas> mInkCanvases;
        protected bool mHasAddedStroke = false;

        public bool CreateMultiPathAnnotation
        {
            get
            {
                return mCreateMultiPathAnnotation;
            }
            set
            {
                mCreateMultiPathAnnotation = value;
            }
        }

        public FreehandCreate(PDFViewWPF view, ToolManager manager)
            : base(view, manager)
        {
            mNextToolMode = ToolManager.ToolType.e_ink_create;
            mToolMode = ToolManager.ToolType.e_ink_create;
            mListOfStrokeLists = new List<List<PDFPoint>>();
        }

        internal override void OnCreate()
        {
            base.OnCreate();

            if (mUseInkCanvas)
            {
                mViewerCanvas.Children.Insert(0, this);
                mInkCanvases = new Dictionary<int, InkCanvas>();
                ApplyStyle();
                AddInkCanvases();
            }
        }

        internal override void OnClose()
        {
            if (mUseInkCanvas && !mHasAddedStroke && mViewerCanvas.Children.Contains(this))
            {
                mViewerCanvas.Children.Remove(this);
            }
            base.OnClose();
        }

        /// <summary>
        /// We need to override the base class and add some functionality here in case we want multiple strokes 
        /// to be part of 1 ink annotation.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal override void MouseLeftButtonDownHandler(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            base.MouseLeftButtonDownHandler(sender, e);
            mShapeHasBeenCreated = false;
            if (mFirstTime)
            {
                if (mShapePageNumber != mDownPageNumber)
                {
                    mIgnoreMouseEvents = true;
                }
                else
                {
                    mIgnoreMouseEvents = false;
                }
            }
        }

        /// <summary>
        /// We need to override the base class here, because it will always end the tool.
        /// We want the user to explicitly end simple shape create if they want multiples strokes
        /// to be part of 1 ink annotation.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal override void MouseLeftButtonUpHandler(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            if (!mUseInkCanvas)
            {
                ProcessInputMove(e);
            }
            // This is what tool does for us.
            mLeftButtonDown = false;
            mIsDragging = false;
            base.MouseLeftButtonUpHandler(sender, e);

            ProcessInputUp(e);
        }

        public override void TouchUpHandler(object sender, System.Windows.Input.TouchEventArgs e)
        {
            if (!mUseInkCanvas)
            {
                ProcessInputMove(e);
            }
            base.TouchUpHandler(sender, e);
            ProcessInputUp(e);
        }

        private void ProcessInputUp(System.Windows.Input.InputEventArgs e)
        {
            if (mUseInkCanvas)
            {
                return;
            }
            if (mCreateMultiPathAnnotation)
            {
                mShapeHasBeenCreated = false;
            }
            else if (mIsDrawing)
            {
                Create();
                EndCurrentTool(ToolManager.ToolType.e_pan);
            }
        }

        internal override void KeyDownAction(object sender, System.Windows.Input.KeyEventArgs e)
        {
            if (!mIsDragging)
            {
                if (e.Key == System.Windows.Input.Key.Y)
                {
                    Create();
                    EndCurrentTool(ToolManager.ToolType.e_pan);
                }
                else if (e.Key == System.Windows.Input.Key.N)
                {
                    EndCurrentTool(ToolManager.ToolType.e_pan);
                }
            }
        }


        #region Override Functions

        private bool mHasFirstPoint = false;
        private UIPoint mLastPoint;
        protected override void Draw()
        {
            if (mIgnoreMouseEvents)
            {
                return;
            }

            double x, y;

            if (!mShapeHasBeenCreated)
            {
                mShapeHasBeenCreated = true;

                x = mDownPoint.X - mPDFView.GetHScrollPos();
                y = mDownPoint.Y - mPDFView.GetVScrollPos();
                mPDFView.ConvScreenPtToPagePt(ref x, ref y, mDownPageNumber);

                if (!mFirstTime)
                {
                    mFirstTime = true;
                    mShapePageNumber = mDownPageNumber; // from now on, mouse presses outside of this page number will be ignored

                    // set bounds
                    mLeftmost = x;
                    mRightmost = x;
                    mTopmost = y;
                    mBottommost = y;
                    mPathPoints = new PathFigureCollection();
                }

                mHalfThickness = mStrokeThickness / 2;
                mCurrentPathFigure = new PathFigure();
                mCurrentPathFigure.StartPoint = new UIPoint(mDownPoint.X - mPageCropOnClient.x1, mDownPoint.Y - mPageCropOnClient.y1);
                mPathPoints.Add(mCurrentPathFigure);
                mListOfStrokeLists.Add(new List<PDFPoint>());
                mCurrentStrokeList = mListOfStrokeLists[mListOfStrokeLists.Count() - 1];

                mCurrentStrokeList.Add(new PDFPoint(x, y));

                PathGeometry geom = new PathGeometry();
                mShape = new Path();
                mShape.StrokeLineJoin = PenLineJoin.Round;
                mShape.StrokeEndLineCap = PenLineCap.Round;
                mShape.StrokeStartLineCap = PenLineCap.Round;
                mShape.StrokeMiterLimit = 1;
                mShape.Data = geom;
                mShape.StrokeThickness = mDrawThickness;
                mShape.Stroke = mStrokeBrush;
                this.Children.Add(mShape);
            }

            if (mSmoothInk)
            {
                if (!mHasFirstPoint)
                {
                    mHasFirstPoint = true;
                }
                else
                {
                    UIPoint ctrlPt = new UIPoint(mLastPoint.X - mPageCropOnClient.x1, mLastPoint.Y - mPageCropOnClient.y1);
                    double endX = (mLastPoint.X + mDragPoint.X) / 2;
                    double endY = (mLastPoint.Y + mDragPoint.Y) / 2;
                    UIPoint endPt = new UIPoint(endX - mPageCropOnClient.x1, endY - mPageCropOnClient.y1);
                    System.Windows.Media.BezierSegment cbz = new BezierSegment(ctrlPt, ctrlPt, endPt, true);
                    QuadraticBezierSegment qbz = new QuadraticBezierSegment(ctrlPt, endPt, true);
                    mCurrentPathFigure.Segments.Add(cbz);
                }
                mLastPoint = new UIPoint(mDragPoint.X, mDragPoint.Y);
            }
            else
            {
                mCurrentPathFigure.Segments.Add(new LineSegment()
                {
                    Point = new UIPoint(mDragPoint.X -
                        mPageCropOnClient.x1, mDragPoint.Y - mPageCropOnClient.y1)
                });
            }

            x = mDragPoint.X - mPDFView.GetHScrollPos();
            y = mDragPoint.Y - mPDFView.GetVScrollPos();
            mPDFView.ConvScreenPtToPagePt(ref x, ref y, mDownPageNumber);

            mCurrentStrokeList.Add(new PDFPoint(x, y));
            if (mCurrentStrokeList.Count % 1000 == 0)
            {
                System.Diagnostics.Debug.WriteLine("Count is " + mCurrentStrokeList.Count);
            }

            // Update bounds
            if (x < mLeftmost)
            {
                mLeftmost = x;
            }
            if (x > mRightmost)
            {
                mRightmost = x;
            }
            if (y > mTopmost)
            {
                mTopmost = y;
            }
            if (y < mBottommost)
            {
                mBottommost = y;
            }

            (mShape.Data as PathGeometry).Figures = mPathPoints;
        }

        protected override void Create()
        {
            if (mListOfStrokeLists.Count() == 0)
            {
                return;
            }

            try
            {
                mPDFView.DocLock(true);
                Rect rect = new Rect(mLeftmost, mBottommost, mRightmost, mTopmost);
                if (rect != null)
                {
                    pdftron.PDF.Annots.Ink ink = pdftron.PDF.Annots.Ink.Create(mPDFView.GetDoc().GetSDFDoc(), rect);

                    Annot.BorderStyle bs = ink.GetBorderStyle();
                    bs.width = mStrokeThickness;
                    ink.SetBorderStyle(bs);

                    double sx = mPDFView.GetHScrollPos();
                    double sy = mPDFView.GetVScrollPos();

                    ink.SetSmoothing(mSmoothInk);

                    // Shove the points into the Doc
                    int i = 0;
                    PDFPoint pdfp = new PDFPoint();
                    foreach (List<PDFPoint> pointList in mListOfStrokeLists)
                    {
                        int j = 0;
                        foreach (PDFPoint p in pointList)
                        {
                            pdfp.x = p.x;
                            pdfp.y = p.y;
                            ink.SetPoint(i, j, pdfp);
                            j++;
                        }
                        i++;
                    }

                    SetStyle(ink);
                    ink.RefreshAppearance();

                    pdftron.PDF.Page page = mPDFView.GetDoc().GetPage(mDownPageNumber);
                    page.AnnotPushBack(ink);

                    mAnnotPageNum = mDownPageNumber;
                    mAnnot = ink;
                    mPDFView.Update(mAnnot, mAnnotPageNum);
                    mPDFView.SetProgressiveRendering(false);
                }
            }
            catch (System.Exception)
            {
            }
            finally
            {
                mPDFView.DocUnlock();
                mListOfStrokeLists.Clear();
            }
            mToolManager.RaiseAnnotationAddedEvent(mAnnot);
            mToolManager.DelayRemoveTimers.Add(new PDFViewWPFToolsCS2013.Utilities.DelayRemoveTimer(mViewerCanvas, this, this, mDownPageNumber));
        }

        protected override void CheckBounds(ref UIPoint point)
        {
            if (mPageCropOnClient != null)
            {
                if (point.X < mPageCropOnClient.x1 + mHalfThickness)
                {
                    point.X = mPageCropOnClient.x1 + mHalfThickness;
                }
                if (point.X > mPageCropOnClient.x2 - mHalfThickness)
                {
                    point.X = mPageCropOnClient.x2 - mHalfThickness;
                }
                if (point.Y < mPageCropOnClient.y1 + mHalfThickness)
                {
                    point.Y = mPageCropOnClient.y1 + mHalfThickness;
                }
                if (point.Y > mPageCropOnClient.y2 - mHalfThickness)
                {
                    point.Y = mPageCropOnClient.y2 - mHalfThickness;
                }
            }
        }

        protected override void HandleResizing()
        {
            if (!mFirstTime)
            {
                return;
            }

            mPageCropOnClient = BuildPageBoundBoxOnClient(mDownPageNumber);
            this.SetValue(System.Windows.Controls.Canvas.LeftProperty, mPageCropOnClient.x1);
            this.SetValue(System.Windows.Controls.Canvas.TopProperty, mPageCropOnClient.y1);
            this.Width = mPageCropOnClient.x2 - mPageCropOnClient.x1;
            this.Height = mPageCropOnClient.y2 - mPageCropOnClient.y1;

            double sx = mPDFView.GetHScrollPos();
            double sy = mPDFView.GetVScrollPos();
            double x, y;

            mLeftmost = -1;
            mRightmost = -1;
            mTopmost = -1;
            mBottommost = -1;

            mZoomLevel = mPDFView.GetZoom();
            mDrawThickness = mStrokeThickness * mZoomLevel;
            mHalfThickness = mDrawThickness / 2;

            this.Children.Clear();

            PathGeometry geom = new PathGeometry();
            mShape = new Path();
            mShape.StrokeLineJoin = PenLineJoin.Miter;
            mShape.StrokeMiterLimit = 1;
            mShape.Data = geom;
            mShape.StrokeThickness = mDrawThickness;
            mShape.Stroke = mStrokeBrush;
            this.Children.Add(mShape);

            mPathPoints = new PathFigureCollection();

            foreach (List<PDFPoint> strokeList in mListOfStrokeLists)
            {
                mCurrentPathFigure = new PathFigure();
                mPathPoints.Add(mCurrentPathFigure);
                bool first = true;
                foreach (PDFPoint point in strokeList)
                {
                    x = point.x;
                    y = point.y;
                    mPDFView.ConvPagePtToScreenPt(ref x, ref y, mDownPageNumber);

                    if (first)
                    {
                        first = false;
                        mCurrentPathFigure.StartPoint = new UIPoint(x + sx - mPageCropOnClient.x1, y + sy - mPageCropOnClient.y1);
                    }
                    else
                    {
                        mCurrentPathFigure.Segments.Add(new LineSegment() { Point = new UIPoint(x + sx - 
                            mPageCropOnClient.x1, y + sy - mPageCropOnClient.y1) });
                    }

                }
            }
            (mShape.Data as PathGeometry).Figures = mPathPoints;
        }

        protected override void MultiTouchDetected()
        {
            if (mPathPoints.Contains(mCurrentPathFigure))
            {
                mPathPoints.Remove(mCurrentPathFigure);
            }
            if (mListOfStrokeLists.Contains(mCurrentStrokeList))
            {
                mListOfStrokeLists.Remove(mCurrentStrokeList);
            }
        }

        internal override void ZoomChangedHandler(object sender, System.Windows.RoutedEventArgs e)
        {
            base.ZoomChangedHandler(sender, e);
            if (mUseInkCanvas)
            {
                RedrawAllInkCanvases();
            }
        }

        internal override void LayoutChangedHandler(object sender, System.Windows.RoutedEventArgs e)
        {
            base.LayoutChangedHandler(sender, e);
            if (mUseInkCanvas)
            {
                RedrawAllInkCanvases();
            }
        }

        internal override void CurrentPageNumberChangedHandler(PDFViewWPF viewer, int currentPage, int totalPages)
        {
            base.CurrentPageNumberChangedHandler(viewer, currentPage, totalPages);
            if (mUseInkCanvas)
            {
                PDFViewWPF.PagePresentationMode ppm = mPDFView.GetPagePresentationMode();
                if (ppm == PDFViewWPF.PagePresentationMode.e_single_page ||
                    ppm == PDFViewWPF.PagePresentationMode.e_facing ||
                    ppm == PDFViewWPF.PagePresentationMode.e_facing_cover)
                {
                    RedrawAllInkCanvases();
                }
            }
        }

        internal override void CurrentScrollChangedHandler(PDFViewWPF viewer, ScrollChangedEventArgs e)
        {
            base.CurrentScrollChangedHandler(viewer, e);
            if (mUseInkCanvas)
            {
                AddInkCanvases();
            }
        }

        internal override void PreviewMouseWheelHandler(object sender, System.Windows.Input.MouseWheelEventArgs e)
        {
            base.PreviewMouseWheelHandler(sender, e);
            if (mUseInkCanvas && mDownPageNumber >= 1)
            {
                e.Handled = true;
            }
        }

        #endregion Override Functions


        #region Context Menu

        public override void AddContextMenuItems(System.Windows.Controls.ContextMenu menu, double x, double y)
        {
            base.AddContextMenuItems(menu, x, y);

            // We're drawing a shape
            if (mFirstTime)
            {
                Separator sep = new Separator();
                menu.Items.Add(sep);

                MenuItem m = new MenuItem();
                m.Header = "Save Shape";
                m.Click += ContextMenu_Finish;
                menu.Items.Add(m);


                m = new MenuItem();
                m.Header = "Discard Shape";
                m.Click += ContextMenu_Discard;
                menu.Items.Add(m);
            }
        }

        private void ContextMenu_Finish(object sender, System.Windows.RoutedEventArgs e)
        {
            SaveShape();
        }

        private void ContextMenu_Discard(object sender, System.Windows.RoutedEventArgs e)
        {
            DiscardShape();
        }


        #endregion Context Menu


        /// <summary>
        /// Save the current drawing
        /// </summary>
        public void SaveShape()
        {
            mHasAddedStroke = true;
            Create();
            EndCurrentTool(ToolManager.ToolType.e_pan);
        }

        // Discard the current drawing
        public void DiscardShape()
        {
            EndCurrentTool(ToolManager.ToolType.e_pan);
        }

        #region InkCanvas

        public override void TouchMoveHandler(object sender, TouchEventArgs e)
        {
            if(mUseInkCanvas) return;
            base.TouchMoveHandler(sender, e);
        }

        private void AddInkCanvasToPage(int pageNumber)
        {
            if (!mInkCanvases.ContainsKey(pageNumber))
            {
                PDFRect rect = BuildPageBoundBoxOnClient(pageNumber);
                InkCanvas inkCanvas = new InkCanvas();
                this.Children.Add(inkCanvas);
                mInkCanvases.Add(pageNumber, inkCanvas);
                inkCanvas.Width = rect.Width();
                inkCanvas.Height = rect.Height();
                inkCanvas.SetValue(Canvas.LeftProperty, rect.x1);
                inkCanvas.SetValue(Canvas.TopProperty, rect.y1);
                inkCanvas.PreviewMouseLeftButtonDown += mInkCanvas_PreviewMouseLeftButtonDown;
                inkCanvas.StrokeCollected += mInkCanvas_StrokeCollected;
                inkCanvas.Background = Brushes.Transparent;
                inkCanvas.RequestBringIntoView += (s, e) =>
                {
                    e.Handled = true;
                };

                ApplyStyleToPage(pageNumber);
            }
        }


        void mInkCanvas_StrokeCollected(object sender, InkCanvasStrokeCollectedEventArgs e)
        {
            if (mDownPageNumber > 0 && mInkCanvases.ContainsKey(mDownPageNumber))
            {
                if (mListOfStrokeLists == null)
                {
                    mListOfStrokeLists = new List<List<PDFPoint>>();
                }
                InkCanvas inkCanvas = mInkCanvases[mDownPageNumber];
                List<PDFPoint> points = new List<PDFPoint>();
                double left = (double)inkCanvas.GetValue(Canvas.LeftProperty) - mPDFView.GetHScrollPos();
                double top = (double)inkCanvas.GetValue(Canvas.TopProperty) - mPDFView.GetVScrollPos();
                PDFPoint lastPoint = null;
                bool lastPointInBounds = true;
                foreach (System.Windows.Input.StylusPoint spt in e.Stroke.StylusPoints)
                {
                    PDFPoint pt = new PDFPoint(spt.X, spt.Y);
                    bool ptInBounds = IsInBounds(inkCanvas, pt);
                    if (!lastPointInBounds && ptInBounds)
                    {
                        mListOfStrokeLists.Add(points);
                        points = new List<PDFPoint>();
                        PDFPoint borderPoint = SnapPointToInkCanvas(inkCanvas, pt, lastPoint);

                        double bx = borderPoint.x + left;
                        double by = borderPoint.y + top;
                        mPDFView.ConvScreenPtToPagePt(ref bx, ref by, mDownPageNumber);
                        AddPointToPointCollection(points, bx, by);
                    }
                    else if (lastPointInBounds && !ptInBounds)
                    {
                        PDFPoint borderPoint = SnapPointToInkCanvas(inkCanvas, lastPoint, pt);
                        double bx = borderPoint.x + left;
                        double by = borderPoint.y + top;
                        mPDFView.ConvScreenPtToPagePt(ref bx, ref by, mDownPageNumber);
                        AddPointToPointCollection(points, bx, by);
                    }
                    
                    if (ptInBounds)
                    {
                        double x = spt.X + left;
                        double y = spt.Y + top;
                        mPDFView.ConvScreenPtToPagePt(ref x, ref y, mDownPageNumber);

                        AddPointToPointCollection(points, x, y);
                    }

                    lastPoint = pt;
                    lastPointInBounds = ptInBounds;
                }
                mListOfStrokeLists.Add(points);
                if (!mCreateMultiPathAnnotation)
                {
                    mHasAddedStroke = true;
                    Create();
                    EndCurrentTool(ToolManager.ToolType.e_pan);
                }
            }
        }

        private void AddPointToPointCollection(List<PDFPoint> points, double x, double y)
        {
            points.Add(new PDFPoint(x, y));
            if (mLeftmost < 0 || x < mLeftmost)
            {
                mLeftmost = x;
            }
            if (mRightmost < 0 || x > mRightmost)
            {
                mRightmost = x;
            }
            if (mTopmost < 0 || y > mTopmost)
            {
                mTopmost = y;
            }
            if (mBottommost < 0 || y < mBottommost)
            {
                mBottommost = y;
            }
        }

        void mInkCanvas_PreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            UIPoint point = GetPosition(e, mPDFView);
            int downPage = mPDFView.GetPageNumberFromScreenPt(point.X, point.Y);
            if (downPage >= 1 && (mDownPageNumber < 1 || mDownPageNumber == downPage))
            {
                mDownPageNumber = downPage;
            }
            else
            {
                System.Diagnostics.Debug.WriteLine("Out of bounds");
                e.Handled = true;
                return;
            }
        }

        internal void ApplyStyle()
        {
            pdftron.PDF.Tools.Utilities.ColorSettings.ToolColor col = pdftron.PDF.Tools.Utilities.ColorSettings.StrokeColor;
            mUseStroke = col.Use;
            Color color = Color.FromArgb(255, col.R, col.G, col.B);
            mStrokeBrush = new SolidColorBrush(color);
            mStrokeThickness = pdftron.PDF.Tools.Properties.Settings.Default.StrokeThickness;
            mZoomLevel = mPDFView.GetZoom();
            mDrawThickness = mStrokeThickness * mZoomLevel;
            mOpacity = pdftron.PDF.Tools.Properties.Settings.Default.MarkupOpacity;

            foreach (int pageNumber in mInkCanvases.Keys)
            {
                ApplyStyleToPage(pageNumber);
            }
        }

        internal void ApplyStyleToPage(int pageNumber)
        {
            if (mInkCanvases.ContainsKey(pageNumber))
            {
                DrawingAttributes inkDA = new DrawingAttributes();
                inkDA.StylusTip = StylusTip.Ellipse;
                inkDA.Color = mStrokeBrush.Color;
                inkDA.Width = mDrawThickness;
                inkDA.Height = mDrawThickness;
                inkDA.IgnorePressure = true; // PDF specification makes pressure quite difficult to add in a nice way.
                inkDA.FitToCurve = false;

                if (mInkCanvases[pageNumber] != null)
                {
                    mInkCanvases[pageNumber].Opacity = mOpacity;
                    mInkCanvases[pageNumber].DefaultDrawingAttributes = inkDA;
                }
            }
        }

        private bool IsInBounds(InkCanvas canvas, PDFPoint point)
        {
            return !(point.x < 0 || point.x > canvas.Width || point.y < 0 || point.y > canvas.Height);
        }

        private PDFPoint SnapPointToInkCanvas(InkCanvas canvas, PDFPoint pointInBounds, PDFPoint pointOutsideBounds)
        {
            PDFPoint outpoint = new PDFPoint(pointOutsideBounds.x, pointOutsideBounds.y);
            double xDist = outpoint.x - pointInBounds.x;
            double yDist = outpoint.y - pointInBounds.y;
            if (outpoint.x < 0)
            {
                outpoint.y = pointInBounds.y * Math.Abs(outpoint.x / xDist) + outpoint.y * Math.Abs(pointInBounds.x / xDist);
                outpoint.x = 0;
            }
            if (outpoint.x > canvas.Width)
            {
                double y1 = pointInBounds.y;
                double l1 = Math.Abs(outpoint.x - canvas.Width);
                double xd = Math.Abs(xDist);
                double r1 = l1 / xd;
                double y2 = outpoint.y;
                double l2 = Math.Abs(outpoint.x - canvas.Width);
                double r2 = l2 / xd;
                outpoint.y = pointInBounds.y * Math.Abs((outpoint.x - canvas.Width) / xDist) + outpoint.y * Math.Abs((pointInBounds.x - canvas.Width) / xDist);
                outpoint.x = canvas.Width;
            }

            if (outpoint.y < 0)
            {
                outpoint.x = pointInBounds.x * Math.Abs(outpoint.y / yDist) + outpoint.x * Math.Abs(pointInBounds.y / yDist);
                outpoint.y = 0;
            }
            if (outpoint.y > canvas.Height)
            {
                outpoint.x = pointInBounds.x * Math.Abs((outpoint.y - canvas.Height) / yDist) + outpoint.x * Math.Abs((pointInBounds.y - canvas.Height) / yDist);
                outpoint.y = canvas.Height;
            }

            return outpoint;
        }

        private void AddInkCanvases()
        {
            int[] visiblePages = mPDFView.GetVisiblePages();
            foreach (int i in visiblePages)
            {
                if (!mInkCanvases.ContainsKey(i))
                {
                    AddInkCanvasToPage(i);
                }
            }
        }

        private void RedrawAllInkCanvases()
        {
            if (mInkCanvases != null)
            {
                foreach (InkCanvas canvas in mInkCanvases.Values)
                {
                    if (this.Children.Contains(canvas))
                    {
                        this.Children.Remove(canvas);
                    }
                }
                mInkCanvases.Clear();
            }
            AddInkCanvases();
            ApplyStyle();
        }

        #endregion InkCanvas

    }
}
