/// <summary>
        ///     Creates a selection object spanning the portion of 'startNode' 
        ///     specified by 'locatorPart'.
        /// </summary>
        /// <param name="locatorPart">locator part specifying data to be spanned</param>
        /// <param name="startNode">the node to be spanned by the created 
        /// selection</param>
        /// <param name="attachmentLevel">set to AttachmentLevel.Full if the entire range of text
        /// was resolved, otherwise set to StartPortion, MiddlePortion, or EndPortion based on
        /// which part of the range was resolved</param>
        /// <returns>a selection spanning the portion of 'startNode' specified by     
        /// 'locatorPart', null if selection described by locator part could not be
        /// recreated</returns>
        /// <exception cref="ArgumentNullException">locatorPart or startNode are 
        /// null</exception>
        /// <exception cref="ArgumentException">locatorPart is of the incorrect type</exception>
        public override Object ResolveLocatorPart(ContentLocatorPart locatorPart, DependencyObject startNode, out AttachmentLevel attachmentLevel)
        {
            if (startNode == null)
                throw new ArgumentNullException("startNode");

            if (locatorPart == null)
                throw new ArgumentNullException("locatorPart");

            if (CharacterRangeElementName != locatorPart.PartType)
                throw new ArgumentException(SR.Get(SRID.IncorrectLocatorPartType, locatorPart.PartType.Namespace + ":" + locatorPart.PartType.Name), "locatorPart");

            // First we extract the offset and length of the 
            // text range from the locator part.
            int startOffset = 0;
            int endOffset = 0;

            string stringCount = locatorPart.NameValuePairs[CountAttribute];
            if (stringCount == null)
                throw new ArgumentException(SR.Get(SRID.InvalidLocatorPart, TextSelectionProcessor.CountAttribute));                
            int count = Int32.Parse(stringCount,NumberFormatInfo.InvariantInfo);

            TextAnchor anchor = new TextAnchor();

            attachmentLevel = AttachmentLevel.Unresolved; 
            
            for (int i = 0; i < count; i++)
            {
                GetLocatorPartSegmentValues(locatorPart, i, out startOffset, out endOffset);

                // Now we grab the TextRange so we can create a selection.  
                // TextBox doesn't expose its internal TextRange so we use
                // its API for creating and getting the selection.
                ITextPointer elementStart;
                ITextPointer elementEnd;
                // If we can't get the start/end of the node then we can't resolve the locator part
                if (!GetNodesStartAndEnd(startNode, out elementStart, out elementEnd))
                    return null;

                // If the offset is not withing the element's text range we return null
                int textRangeLength = elementStart.GetOffsetToPosition(elementEnd);
                if (startOffset > textRangeLength)
                    return null;

                ITextPointer start = elementStart.CreatePointer(startOffset);// new TextPointer((TextPointer)elementStart, startOffset);

                ITextPointer end = (textRangeLength <= endOffset) ?
                    elementEnd.CreatePointer() : //new TextPointer((TextPointer)elementEnd) :
                    elementStart.CreatePointer(endOffset);// new TextPointer((TextPointer)elementStart, endOffset);

                //we do not process 0 length selection
                if (start.CompareTo(end) >= 0)
                    return null;

                anchor.AddTextSegment(start, end);
            }           

            //we do not support 0 or negative length selection
            if (anchor.IsEmpty)
            {
                throw new ArgumentException(SR.Get(SRID.IncorrectAnchorLength), "locatorPart");
            }

            attachmentLevel = AttachmentLevel.Full; 
            
            if (_clamping)
            {
                ITextPointer currentStart = anchor.Start;
                ITextPointer currentEnd = anchor.End;
                IServiceProvider serviceProvider = null;
                ITextView textView = null;

                if (_targetPage != null)
                {
                    serviceProvider = _targetPage as IServiceProvider;
                }
                else
                {
                    FlowDocument content = currentStart.TextContainer.Parent as FlowDocument;
                    serviceProvider = PathNode.GetParent(content as DependencyObject) as IServiceProvider;
                }

                Invariant.Assert(serviceProvider != null, "No ServiceProvider found to get TextView from.");
                textView = serviceProvider.GetService(typeof(ITextView)) as ITextView;
                Invariant.Assert(textView != null, "Null TextView provided by ServiceProvider.");

                anchor = TextAnchor.TrimToIntersectionWith(anchor, textView.TextSegments);

                if (anchor == null)
                {
                    attachmentLevel = AttachmentLevel.Unresolved;
                }
                else
                {
                    if (anchor.Start.CompareTo(currentStart) != 0)
                    {
                        attachmentLevel &= ~AttachmentLevel.StartPortion;
                    }
                    if (anchor.End.CompareTo(currentEnd) != 0)
                    {
                        attachmentLevel &= ~AttachmentLevel.EndPortion;
                    }
                }            
            }

            return anchor;
        }
        /// <summary>
        ///     Creates a TextRange object spanning the portion of 'startNode' 
        ///     specified by 'locatorPart'.
        /// </summary>
        /// <param name="locatorPart">FixedTextRange locator part specifying start and end point of 
        /// the TextRange</param>
        /// <param name="startNode">the FixedPage containing this locator part</param>
        /// <param name="attachmentLevel">set to AttachmentLevel.Full if the FixedPage for the locator 
        /// part was found, AttachmentLevel.Unresolved otherwise</param>
        /// <returns>a TextRange spanning the text between start end end point in the FixedTextRange
        /// locator part
        /// , null if selection described by locator part could not be
        /// recreated</returns>
        /// <exception cref="ArgumentNullException">locatorPart or startNode are 
        /// null</exception>
        /// <exception cref="ArgumentException">locatorPart is of the incorrect type</exception>
        /// <exception cref="ArgumentException">startNode is not a FixedPage</exception>
        /// <exception cref="ArgumentException">startNode does not belong to the DocumentViewer</exception>
        public override Object ResolveLocatorPart(ContentLocatorPart locatorPart, DependencyObject startNode, out AttachmentLevel attachmentLevel)
        {
            if (startNode == null)
                throw new ArgumentNullException("startNode");

            DocumentPage docPage = null;
            FixedPage page = startNode as FixedPage;

            if (page != null)
            {
                docPage = GetDocumentPage(page);
            }
            else 
            {
                // If we were passed a DPV because we are walking the visual tree,
                // extract the DocumentPage from it;  its TextView will be used to
                // turn coordinates into text positions
                DocumentPageView dpv = startNode as DocumentPageView;
                if (dpv != null)
                {
                    docPage = dpv.DocumentPage as FixedDocumentPage;
                    if (docPage == null)
                    {
                        docPage = dpv.DocumentPage as FixedDocumentSequenceDocumentPage;
                    }
                }
            }

            if (docPage == null)
            {
                throw new ArgumentException(SR.Get(SRID.StartNodeMustBeDocumentPageViewOrFixedPage), "startNode");
            }

            if (locatorPart == null)
                throw new ArgumentNullException("locatorPart");

            attachmentLevel = AttachmentLevel.Unresolved;

            ITextView tv = (ITextView)((IServiceProvider)docPage).GetService(typeof(ITextView));
            Debug.Assert(tv != null);

            ReadOnlyCollection<TextSegment> ts = tv.TextSegments;

            //check first if a TextRange can be generated
            if (ts == null || ts.Count <= 0)
                return null;

            TextAnchor resolvedAnchor = new TextAnchor();
            
            if (docPage != null)
            {
                string stringCount = locatorPart.NameValuePairs["Count"];
                if (stringCount == null)
                    throw new ArgumentException(SR.Get(SRID.InvalidLocatorPart, TextSelectionProcessor.CountAttribute));                
                int count = Int32.Parse(stringCount, NumberFormatInfo.InvariantInfo);

                for(int i = 0; i < count; i++)
                {
                    // First we extract the start and end Point from the locator part.
                    Point start;
                    Point end;
                    GetLocatorPartSegmentValues(locatorPart, i, out start, out end);

                    //calulate start ITextPointer
                    ITextPointer segStart;
                    if (double.IsNaN(start.X) || double.IsNaN(start.Y))
                    {
                        //get start of the page
                        segStart = FindStartVisibleTextPointer(docPage);
                    }
                    else
                    {
                        //convert Point to TextPointer
                        segStart = tv.GetTextPositionFromPoint(start, true);
                    }

                    if (segStart == null)
                    {
                        //selStart can be null if there are no insertion points on this page 
                        continue;
                    }

                    //calulate end ITextPointer
                    ITextPointer segEnd;
                    if (double.IsNaN(end.X) || double.IsNaN(end.Y))
                    {
                        segEnd = FindEndVisibleTextPointer(docPage);
                    }
                    else
                    {
                        //convert Point to TextPointer
                        segEnd = tv.GetTextPositionFromPoint(end, true);
                    }

                    //end TP can not be null when start is not
                    Invariant.Assert(segEnd != null, "end TP is null when start TP is not");

                    attachmentLevel = AttachmentLevel.Full;  // Not always true right?
                    resolvedAnchor.AddTextSegment(segStart, segEnd);
                }
            }

            if (resolvedAnchor.TextSegments.Count > 0)
                return resolvedAnchor;
            else
                return null;
        }