/// <summary>
        /// Gets the entry at counter position.
        /// </summary>
        /// <param name="start">The start.</param>
        /// <param name="searchPosition">The search position.</param>
        /// <param name="cookie">The cookie.</param>
        /// <param name="preferLeftMost">if set to <c>true</c> prefer left most.</param>
        /// <returns></returns>
        TreeTableWithCounterEntry GetEntryAtCounterPosition(ITreeTableCounter start, ITreeTableCounter searchPosition, int cookie, bool preferLeftMost)
        {
            int treeNodeCount = GetCount();

            //if (searchPosition < 0 || searchPosition >= VisibleCount)
            if (searchPosition.Compare(GetStartCounterPosition(), cookie) < 0)
            {
                throw new ArgumentOutOfRangeException("searchPosition");
            }

            if (searchPosition.Compare(GetCounterTotal(), cookie) > 0)
            {
                throw new ArgumentOutOfRangeException("searchPosition", String.Format("{0} out of range {1}", searchPosition, GetCounterTotal()));
            }

            if (this.Root == null)
            {
                return(null);
            }
            else
            {
                // find node
                ITreeTableNode    currentNode         = this.Root;
                ITreeTableCounter currentNodePosition = start;
                return(GetEntryAtCounterPosition(currentNode, start, searchPosition, cookie, preferLeftMost, out currentNodePosition));
            }
        }
        /// <summary>
        /// Returns the cumulative counter position object of a child node with all counter values.
        /// </summary>
        /// <param name="node">The node.</param>
        /// <returns></returns>
        public ITreeTableCounter GetCounterPositionOfChild(ITreeTableNode node)
        {
            ITreeTableCounter pos = GetCounterPosition();

            if (Object.ReferenceEquals(node, Right))
            {
                return(pos.Combine(GetLeftC().GetCounterTotal(), TreeTableCounterCookies.CountAll));
            }

            else if (Object.ReferenceEquals(node, Left))
            {
                return(pos);
            }

            throw new ArgumentException("must be a child node", "node");
        }
        TreeTableWithCounterEntry GetEntryAtCounterPosition(ITreeTableNode currentNode, ITreeTableCounter start, ITreeTableCounter searchPosition, int cookie, bool preferLeftMost, out ITreeTableCounter currentNodePosition)
        {
            TreeTableWithCounterBranch savedBranch   = null;
            ITreeTableCounter          savedPosition = null;

            currentNodePosition = start;
            while (!currentNode.IsEntry())
            {
                var branch = (TreeTableWithCounterBranch)currentNode;
                var leftB  = (ITreeTableCounterNode)branch.Left;
                ITreeTableCounter rightNodePosition = currentNodePosition.Combine(leftB.GetCounterTotal(), cookie);

                if (searchPosition.Compare(rightNodePosition, cookie) < 0)
                {
                    currentNode = branch.Left;
                }
                else if (preferLeftMost && searchPosition.Compare(currentNodePosition, cookie) == 0)
                {
                    while (!currentNode.IsEntry())
                    {
                        branch      = (TreeTableWithCounterBranch)currentNode;
                        currentNode = branch.Left;
                    }
                }
                else
                {
                    // When the right node matches the searchPosition, there might be entries
                    // with the same position in the left branch. For example, there might be
                    // several subsequent tokens on a line in a text editor. Each token will
                    // have the same line index. When searching for the first token in a line,
                    // the method will at that time also check the rightmost nodes in the left
                    // branch.
                    //
                    // When preferLeftMost is False, the last token in the line will be returned.
                    // When preferLeftMost is True, the first last token in the line will be returned.
                    //
                    // Note: This only works for "direct hits", that means when the search position
                    // matches the right node's position. If you search for the "greatest counter
                    // smaller or equal than searchPosition", the latest node will be returned no
                    // matter if there were nodes with the same counter before.
                    //
                    // Take the YAmountCounter in a TextEditor for example. If you search
                    // for a YAmount between lines, the last token of the line will be returned.
                    // In the TextBuffer class special consideration is taken into account for
                    // this scenario. A generic solution would be too costly in this method.
                    if (preferLeftMost && searchPosition.Compare(rightNodePosition, cookie) == 0)
                    {
                        ITreeTableCounter currentNode2Position = null;
                        ITreeTableNode    currentNode2         = GetEntryAtCounterPosition(branch.Left, currentNodePosition, searchPosition, cookie, preferLeftMost, out currentNode2Position);
                        if (rightNodePosition.Compare(currentNode2Position, cookie) == 0)
                        {
                            currentNode         = currentNode2;
                            currentNodePosition = currentNode2Position;
                        }
                        else
                        {
                            currentNodePosition = rightNodePosition;
                            currentNode         = branch.Right;
                        }
                    }
                    else
                    {
                        if (savedBranch == null)
                        {
                            savedBranch   = branch;
                            savedPosition = currentNodePosition;
                        }
                        currentNodePosition = rightNodePosition;
                        currentNode         = branch.Right;
                    }
                }
            }

            //			if (preferLeftMost && savedBranch != null)
            //			{
            //				ITreeTableCounter currentNode2Position = null;
            //				ITreeTableNode currentNode2 = GetEntryAtCounterPosition(savedBranch.Left, savedPosition, searchPosition, cookie, preferLeftMost, out currentNode2Position);
            //				if (currentNodePosition.Compare(currentNode2Position, cookie) == 0)
            //					currentNode = currentNode2;
            //
            //				while (!currentNode.IsEntry())
            //				{
            //					TreeTableWithCounterBranch branch = (TreeTableWithCounterBranch) currentNode;
            //					currentNode = branch.Left;
            //				}
            //			}
            return((TreeTableWithCounterEntry)currentNode);
        }