void ITextRangeProvider.ExpandToEnclosingUnit(TextUnit unit)
        {
            Misc.SetFocus(_provider._hwnd);

            switch (unit)
            {
            case TextUnit.Character:
                // if it is a degenerate range then expand it to be one character.
                // otherwise, leave it as it is.
                if (Start == End)
                {
                    int moved;
                    End = MoveEndpointForward(End, TextUnit.Character, 1, out moved);
                }
                break;

            case TextUnit.Word:
            {
                // this works same as paragraph except we look for word boundaries instead of paragraph boundaries.

                // get the text so we can figure out where the boundaries are
                string text = _provider.GetText();
                ValidateEndpoints();

#if WCP_NLS_ENABLED
                // use the same word breaker that Avalon Text uses.
                WordBreaker   breaker   = new WordBreaker();
                TextContainer container = new TextContainer(text);
                // if the starting point of the range is not already at a word break
                // then move it backwards to the nearest word break.
                TextNavigator startNavigator = new TextNavigator(Start, container);
                if (!breaker.IsAtWordBreak(startNavigator))
                {
                    breaker.MoveToPreviousWordBreak(startNavigator);
                    Start = startNavigator.Position;
                }

                // if the range is degenerate or the ending point of the range is not already at a word break
                // then move it forwards to the nearest word break.
                TextNavigator endNavigator = new TextNavigator(End, container);
                if (Start == End || !breaker.IsAtWordBreak(endNavigator))
                {
                    breaker.MoveToNextWordBreak(endNavigator);
                    End = endNavigator.Position;
                }
#else
                // move start left until we reach a word boundary.
                for (; !AtWordBoundary(text, Start); Start--)
                {
                    ;
                }

                // move end right until we reach word boundary (different from Start).
                End = Math.Min(Math.Max(End, Start + 1), text.Length);
                for (; !AtWordBoundary(text, End); End++)
                {
                    ;
                }
#endif
            }
            break;

            case TextUnit.Line:
            {
                if (_provider.GetLineCount() != 1)
                {
                    int startLine = _provider.LineFromChar(Start);
                    int endLine   = _provider.LineFromChar(End);

                    MoveTo(_provider.LineIndex(startLine), _provider.LineIndex(endLine + 1));
                }
                else
                {
                    MoveTo(0, _provider.GetTextLength());
                }
            }
            break;

            case TextUnit.Paragraph:
            {
                // this works same as paragraph except we look for word boundaries instead of paragraph boundaries.

                // get the text so we can figure out where the boundaries are
                string text = _provider.GetText();
                ValidateEndpoints();

                // move start left until we reach a paragraph boundary.
                for (; !AtParagraphBoundary(text, Start); Start--)
                {
                    ;
                }

                // move end right until we reach a paragraph boundary (different from Start).
                End = Math.Min(Math.Max(End, Start + 1), text.Length);
                for (; !AtParagraphBoundary(text, End); End++)
                {
                    ;
                }
            }
            break;

            case TextUnit.Format:
            case TextUnit.Page:
            case TextUnit.Document:
                MoveTo(0, _provider.GetTextLength());
                break;

            //break;
            default:
                throw new System.ComponentModel.InvalidEnumArgumentException("unit", (int)unit, typeof(TextUnit));
            }
        }
        // moves an endpoint backward a certain number of units.
        // the endpoint is just an index into the text so it could represent either
        // the endpoint.
        private int MoveEndpointBackward(int index, TextUnit unit, int count, out int moved)
        {
            switch (unit)
            {
            case TextUnit.Character:
            {
                int limit = _provider.GetTextLength();
                ValidateEndpoints();

                int oneBasedIndex = index + 1;

                moved = Math.Max(count, -oneBasedIndex);
                index = index + moved;

                index = index < 0 ? 0 : index;
            }
            break;

            case TextUnit.Word:
            {
                string text = _provider.GetText();
                ValidateEndpoints();

#if WCP_NLS_ENABLED
                // use the same word breaker as Avalon Text.
                WordBreaker   breaker   = new WordBreaker();
                TextContainer container = new TextContainer(text);
                TextNavigator navigator = new TextNavigator(index, container);

                // move backward one word break for each count
                for (moved = 0; moved > count && index > 0; moved--)
                {
                    if (!breaker.MoveToPreviousWordBreak(navigator))
                    {
                        break;
                    }
                }

                index = navigator.Position;
#else
                for (moved = 0; moved > count && index > 0; moved--)
                {
                    for (index--; !AtWordBoundary(text, index); index--)
                    {
                        ;
                    }
                }
#endif
            }
            break;

            case TextUnit.Line:
            {
                // Note count < 0.

                // Get 1-based line.
                int line = _provider.LineFromChar(index) + 1;

                int lineMax = _provider.GetLineCount();

                // Truncate the count to the number of available lines.
                int actualCount = Math.Max(count, -line);

                moved = actualCount;

                if (actualCount == -line)
                {
                    // We are moving by the maximum number of possible lines,
                    // so we know the resulting index will be 0.
                    index = 0;

                    // If a line other than the first consists of only "\r\n",
                    // you can move backwards past this line and the position changes,
                    // hence this is counted.  The first line is special, though:
                    // if it is empty, and you move say from the second line back up
                    // to the first, you cannot move further; however if the first line
                    // is nonempty, you can move from the end of the first line to its
                    // beginning!  This latter move is counted, but if the first line
                    // is empty, it is not counted.

                    // Recalculate the value of "moved".
                    // The first line is empty if it consists only of
                    // a line separator sequence.
                    bool firstLineEmpty =
                        ((lineMax > 1 && _provider.LineIndex(1) == _lineSeparator.Length) ||
                         lineMax == 0);

                    if (moved < 0 && firstLineEmpty)
                    {
                        ++moved;
                    }
                }
                else         // actualCount > -line
                {
                    // Move the endpoint to the beginning of the following line,
                    // then back by the line separator length to get to the end
                    // of the previous line, since the Edit control has
                    // no method to get the character index of the end
                    // of a line directly.
                    index = _provider.LineIndex(line + actualCount) - _lineSeparator.Length;
                }
            }
            break;

            case TextUnit.Paragraph:
            {
                // just like moving words but we look for paragraph boundaries instead of
                // word boundaries.
                string text = _provider.GetText();
                ValidateEndpoints();

                for (moved = 0; moved > count && index > 0; moved--)
                {
                    for (index--; !AtParagraphBoundary(text, index); index--)
                    {
                        ;
                    }
                }
            }
            break;

            case TextUnit.Format:
            case TextUnit.Page:
            case TextUnit.Document:
            {
                // since edit controls are plain text moving one uniform format unit will
                // take us all the way to the beginning of the document, just like
                // "pages" and document.

                // we'll move 1 format unit if we aren't already at the beginning of the
                // document.  Otherwise, we won't move at all.
                moved = index > 0 ? -1 : 0;
                index = 0;
            }
            break;

            default:
                throw new System.ComponentModel.InvalidEnumArgumentException("unit", (int)unit, typeof(TextUnit));
            }

            return(index);
        }
        // moves an endpoint forward a certain number of units.
        // the endpoint is just an index into the text so it could represent either
        // the endpoint.
        private int MoveEndpointForward(int index, TextUnit unit, int count, out int moved)
        {
            switch (unit)
            {
            case TextUnit.Character:
            {
                int limit = _provider.GetTextLength();
                ValidateEndpoints();

                moved = Math.Min(count, limit - index);
                index = index + moved;

                index = index > limit ? limit : index;
            }
            break;

            case TextUnit.Word:
            {
                string text = _provider.GetText();
                ValidateEndpoints();

#if WCP_NLS_ENABLED
                // use the same word breaker as Avalon Text.
                WordBreaker   breaker   = new WordBreaker();
                TextContainer container = new TextContainer(text);
                TextNavigator navigator = new TextNavigator(index, container);

                // move forward one word break for each count
                for (moved = 0; moved < count && index < text.Length; moved++)
                {
                    if (!breaker.MoveToNextWordBreak(navigator))
                    {
                        break;
                    }
                }

                index = navigator.Position;
#else
                for (moved = 0; moved < count && index < text.Length; moved++)
                {
                    for (index++; !AtWordBoundary(text, index); index++)
                    {
                        ;
                    }
                }
#endif
            }
            break;

            case TextUnit.Line:
            {
                // figure out what line we are on.  if we are in the middle of a line and
                // are moving left then we'll round up to the next line so that we move
                // to the beginning of the current line.
                int line = _provider.LineFromChar(index);

                // limit the number of lines moved to the number of lines available to move
                // Note lineMax is always >= 1.
                int lineMax = _provider.GetLineCount();
                moved = Math.Min(count, lineMax - line - 1);

                if (moved > 0)
                {
                    // move the endpoint to the beginning of the destination line.
                    index = _provider.LineIndex(line + moved);
                }
                else if (moved == 0 && lineMax == 1)
                {
                    // There is only one line so get the text length as endpoint
                    index = _provider.GetTextLength();
                    moved = 1;
                }
            }
            break;

            case TextUnit.Paragraph:
            {
                // just like moving words but we look for paragraph boundaries instead of
                // word boundaries.
                string text = _provider.GetText();
                ValidateEndpoints();

                for (moved = 0; moved < count && index < text.Length; moved++)
                {
                    for (index++; !AtParagraphBoundary(text, index); index++)
                    {
                        ;
                    }
                }
            }
            break;

            case TextUnit.Format:
            case TextUnit.Page:
            case TextUnit.Document:
            {
                // since edit controls are plain text moving one uniform format unit will
                // take us all the way to the end of the document, just like
                // "pages" and document.
                int limit = _provider.GetTextLength();
                ValidateEndpoints();

                // we'll move 1 format unit if we aren't already at the end of the
                // document.  Otherwise, we won't move at all.
                moved = index < limit ? 1 : 0;
                index = limit;
            }
            break;

            default:
                throw new System.ComponentModel.InvalidEnumArgumentException("unit", (int)unit, typeof(TextUnit));
            }

            return(index);
        }