protected virtual bool VerifyPathGestures(KSPictureLoginPathGesture verifyGesture, KSPictureLoginPathGesture storedGesture, RectangleF drawingViewRect)
        {
            var numHitScreenPoints = 0;
            //var hitScreenPointIndexes = new List<int>();
            // Number of locations in the gesture to verify.
            int numMaxGesturePoints = 0;
            // Number of locations of the current recorded gesture.
            int numRecordedGestureLocations = 0;

            numRecordedGestureLocations = storedGesture.Path.Count;

            // Convert the drawn locations of the gesture into validation rects.
            IEnumerable<KSPictureLoginValidationRect> storedValidationRects = storedGesture.Path.Select (p => p.ScaleLocation(drawingViewRect.Size).GetValidationRect(KSPictureLoginController.GridRectSize));

            // Convert gesture points into scaled points.
            IEnumerable<PointF> verifyScreenPoints = verifyGesture.Path.Select (p => p.ScaleLocation(drawingViewRect.Size));
            // Get how many points this gesture has.
            numMaxGesturePoints = verifyScreenPoints.Count ();

            // Loop all the currently drawn points and compare if they are close to a recorded point.
            foreach (var validationRect in storedValidationRects)
            {
                //int index = 0;
                foreach (var verifyPoint in verifyScreenPoints)
                {
                    // Remember the amount of hit points of the gesture.
                    if (validationRect.Contains (verifyPoint))
                    {
                        numHitScreenPoints++;
                    }

                    // TODO: Add indexed gesture verification as additional feature.
                    // If the rectangle around the just drawn point contains a point of the gesture to verify, remember the index
                    // of the point. The user has to hit the points in the correct order.
                    // Only add if not already previously hit.
                    //						if(validationRect.Contains(verifyPoint) && !hitScreenPointIndexes.Contains(index))
                    //						{
                    //							hitScreenPointIndexes.Add(index);
                    //						}
                    //						index++;
                }
            }

            // Get the number of gesture points that were hit in ascending order.
            //				int compareIndex = -1;
            //				int ascendingIndexesHit = 0;
            //				foreach(int index in hitScreenPointIndexes)
            //				{
            //					if(index > compareIndex)
            //					{
            //						ascendingIndexesHit++;
            //						compareIndex = index;
            //					}
            //				}

            if(numHitScreenPoints > numMaxGesturePoints)
            {
                numHitScreenPoints = numMaxGesturePoints;
            }

            // Get a percentage: how many percent of the possible gesture points were hit?
            var hitRatioPercentage = Convert.ToSingle (numHitScreenPoints) / Convert.ToSingle (numMaxGesturePoints);
            if (hitRatioPercentage < KSPictureLoginGestureVerifier.VerifyGestureRequiredAccuracyPercentage)
            {
                KSPictureLoginGlobal.Log ("Required accuracy of {0:.00}% not met. Gesture {1} was not matched by gesture {2}.", KSPictureLoginGestureVerifier.VerifyGestureRequiredAccuracyPercentage * 100f, verifyGesture, storedGesture);
                return false;
            }
            else
            {
                // The required amount of points of the gesture was hit.
                // Check if the user matched the gesture by drawing a reasonable amount of points or if he just painted all
                // across the screen and made a lucky guess.
                var overflowPointsPercentage = Convert.ToSingle (numRecordedGestureLocations) / Convert.ToSingle (numMaxGesturePoints) - 1f;
                if (overflowPointsPercentage > KSPictureLoginGestureVerifier.VerifyGestureMaxLocationOverflowPercentage)
                {
                    KSPictureLoginGlobal.Log ("Maximum overflow of {0:.00}% not met (was {1:.00}%). Gesture {2} was not matched by gesture {3}.", KSPictureLoginGestureVerifier.VerifyGestureMaxLocationOverflowPercentage * 100f, overflowPointsPercentage * 100f, verifyGesture, storedGesture);
                    return false;
                }
                else
                {
                    KSPictureLoginGlobal.Log ("Gesture {0} was matched by gesture {1} with {2:.00}% accuracy and an overflow of {3:.00}%.", verifyGesture, storedGesture, hitRatioPercentage * 100f, overflowPointsPercentage * 100f);
                }
            }

            return true;
        }
        /// <summary>
        /// Gets called if touches ended or were cancelled. This adds the last drawn gesture to the list of gestures to be saved.
        /// </summary>
        /// <param name="touches">Touches.</param>
        /// <param name="evt">Evt.</param>
        public virtual void HandleTouchesEnded(NSSet touches, UIEvent evt)
        {
            this.PictureLoginView.DrawingAreaView.EnableGestureVisualizationLayer = false;

            TimeSpan touchDuration = DateTime.Now - this.touchStartTime;

            // Check if the touch should be recorded as a tap.
            if(touchDuration.TotalSeconds < KSPictureLoginController.TapTouchThresholdSeconds)
            {
                var tapGesture = this.Factory.CreateGesture<KSPictureLoginTapGesture> ();
                tapGesture.Location = this.touchStartLocation.NormalizePoint (this.PictureLoginView.DrawingAreaView.Bounds.Size);

                this.gestureCollection.Add (tapGesture);
                this.PictureLoginView.DrawingAreaView.AddTapGesture (this.touchStartLocation);
                KSPictureLoginGlobal.Log ("Adding tap gesture to list: {0}", tapGesture);
            }
            else if (this.currentPathGesture != null)
            {
                KSPictureLoginGlobal.Log ("Adding path gesture to list: {0}", this.currentPathGesture);
                this.gestureCollection.Add (this.currentPathGesture);
                this.currentPathGesture = null;
            }

            // If a gesture ended and we're in verification mode, check if the gesture to be verfied was matched.
            if (this.GesturesToVerify != null)
            {
                bool gestureVerified = this.VerifyGesture ();
                KSPictureLoginGlobal.Log ("Gesture verified: {0}", gestureVerified);

                // Let the user know that the gesture was verified.
                var gestureVerifiedCallback = this.GestureVerified;
                if (gestureVerifiedCallback != null)
                {
                    gestureVerifiedCallback (gestureVerified);
                }
            }

            // Update the view.
            this.PictureLoginView.DrawingAreaView.SetNeedsDisplay();
        }
        public override void TouchesMoved(NSSet touches, UIEvent evt)
        {
            base.TouchesMoved (touches, evt);

            // If there isn't an active path gesture, create one now.
            if(this.currentPathGesture == null)
            {
                this.currentPathGesture = this.Factory.CreateGesture<KSPictureLoginPathGesture> ();
                this.currentPathGesture.Path.Add (this.touchStartLocation.NormalizePoint(this.PictureLoginView.DrawingAreaView.Bounds.Size));
            }

            UITouch touch = touches.AnyObject as UITouch;

            var viewLocation = touch.LocationInView (this.PictureLoginView.DrawingAreaView);
            // Don't allow drawing outside of the image.
            viewLocation = viewLocation.LimitValues (this.PictureLoginView.DrawingAreaView.Bounds);

            this.PictureLoginView.DrawingAreaView.SetGestureVisualizationLayerPosition (viewLocation);
            this.PictureLoginView.DrawingAreaView.EnableGestureVisualizationLayer = true;

            // We only store the point if it does not collide with the previous validation rectangle.
            // This reduces the amount of points being stored.
            var currentRasterizationRect = viewLocation.GetValidationRect (KSPictureLoginController.GridRectSize);
            if (previousRasterizationRect == null || !currentRasterizationRect.IntersectsWith (this.previousRasterizationRect))
            {
                // The current rect is different from the previous validation rect. Store the center of the rect as a new location.
                var normalizedPoint = currentRasterizationRect.Center.NormalizePoint (this.PictureLoginView.DrawingAreaView.Bounds.Size);
                this.currentPathGesture.Path.Add (normalizedPoint);
                this.PictureLoginView.DrawingAreaView.ContinuePathGesture (currentRasterizationRect.Center);

                // Remember the current validation rect for the next iteration.
                this.previousRasterizationRect = currentRasterizationRect;

                // Update the view.
                this.PictureLoginView.DrawingAreaView.SetNeedsDisplay();
            }
        }
 /// <summary>
 /// Clears the gestures recorded so far. Triggers the user's callback if registered.
 /// </summary>
 public void ClearGestures()
 {
     this.gestureCollection = new KSPictureLoginGestureCollection ();
     this.currentPathGesture = null;
     this.PictureLoginView.DrawingAreaView.ClearGestures ();
 }