/// <summary>
        /// given the TextNode sees if there is text and if so
        /// collapses and writes the TextNode Record.
        /// return true if a textNode was added,
        /// the stripNextTextNodesLeadingWhitespace is set
        /// based on the Text. if no text its value is set
        /// to whatever the textFlow was set to previously.
        /// </summary>
        bool CollapseAndAddTextNode(TextFlowStackData textFlowData, bool stripAllRightWhitespace)
        {

            bool addedText = false;

            if (null != textFlowData.TextNode && textFlowData.TextNode.Text.Length > 0)
            {
                string collapsedText;
                bool endedWithWhitespace;

                collapsedText = CollapseText(textFlowData.TextNode.Text,
                    textFlowData.StripLeadingSpaces,
                    stripAllRightWhitespace, textFlowData.XmlSpaceIsPreserve, out endedWithWhitespace);

                // if got any text back write it out.
                textFlowData.TextNode.UpdateText(collapsedText);
                if (collapsedText.Length > 0)
                {
                    TokenReaderNodeCollection.Add(textFlowData.TextNode);
                    textFlowData.TextNode = null;
                    addedText = true;
                }

                // update StripLeadingSpaces based on if this
                // string ending with whitespace.
                textFlowData.StripLeadingSpaces = endedWithWhitespace;
            }

            return addedText;
        }
        void AddNodeToCollection(XamlNode xamlNode, bool insert, bool insertAtStart)
        {

            bool addNodeToBuffer = true; // set to false if need to do TextProcessing.
            bool textNodeAdded = false; // need to track if the textNode passed in is going to be in the baml or not

            // if there is a preCount we currently only allow
            // text within,
            bool preserveText = false;

            // Do any text Node handling for cached text of if this is
            // a textNode
            // !! should always be something on the stack since we push the Root.
            TextFlowStackData textFlowData = (TextFlowStackData)_textFlowStack.Peek();
            Debug.Assert(null != textFlowData, "No data for TextFlow");

            // do any processing for Text whitespace.
            switch (xamlNode.TokenType)
            {
                // possible that top-level text may not have been processed yet so
                // if get an EndDocument check the buffer

                case XamlNodeType.DocumentEnd:
                    {
                        // possible to have Text in the Buffer for the
                        // EndDocument if there is text at the root.
                        textNodeAdded = CollapseAndAddTextNode(textFlowData, true /* stripAllRightWhitespace */);
                        break;
                    }

                // process as begin tag
                // could be start of a new flow or inline.
                case XamlNodeType.ElementStart:
                    {
                        XamlElementStartNode elementNode = (XamlElementStartNode)xamlNode;
                        Type typeRightTag = elementNode.ElementType;
                        Debug.Assert(null != typeRightTag, "ElementType not yet assigned to Node");

                        // get whitespace type for tag
                        bool rightTagTrimSurroundingWhitespace = GetTrimSurroundingWhitespace(typeRightTag);
                        bool stripAllRightWhitespace = rightTagTrimSurroundingWhitespace;

                        // now have enough information on what to do with
                        // any textFlowData. If there isn't any
                        // text set the stripNextTextNodesLeadingWhitespace = to the current
                        // value.
                        // so inline the whitespace still gets stripped on the next
                        // tag <Button><B> This is Text </B> or should it be false?
                        // for block and inline block the stripNextTextNodesLeadingWhitespace
                        // will be updated based on if block or Inline.

                        textNodeAdded = CollapseAndAddTextNode(textFlowData, stripAllRightWhitespace);
                        textFlowData.StripLeadingSpaces = rightTagTrimSurroundingWhitespace;
                        TextFlowStackData flowData = new TextFlowStackData();
                        TextFlowStack.Push(flowData);

                        break;
                    }
                // process as text buffer
                case XamlNodeType.Text:
                {
                    // If we already have a text node, and we've encountered an ignorable element
                    // like a comment, then just append the new text to the existing text node
                    if (textFlowData.EncounteredIgnorableTag && textFlowData.TextNode != null)
                    {
                        textFlowData.TextNode.UpdateText(textFlowData.TextNode.Text +
                                                         ((XamlTextNode)xamlNode).Text);
                        textFlowData.EncounteredIgnorableTag = false;
                        addNodeToBuffer = false;
                    }
                    else
                    {
                        // !!! important set addNodeToBuffer to false so passed in text isn't added yet
                        // to the outputBuffer.
                        addNodeToBuffer = false;
                        textNodeAdded = CollapseAndAddTextNode(textFlowData, false /* stripAllRightWhitespace */);

                        // set the new text as the TextRun and update leading spaces
                        textFlowData.TextNode = (XamlTextNode)xamlNode;

                        // set the Prserve value check for if the xml:space = "preserve"
                        if (preserveText || (null != ParserContext.XmlSpace &&
                            ParserContext.XmlSpace.Equals("preserve")))
                        {
                            textFlowData.XmlSpaceIsPreserve = true;
                        }
                        else
                        {
                            textFlowData.XmlSpaceIsPreserve = false;
                        }
                    }
                }
                break;

                // process as end tag
                case XamlNodeType.ElementEnd:
                    {
                        // if this is not inline element then else it is
                        // okay to leave them.

                        // strip any trailing space unless this is an end to an inline tag.
                        bool stripAllRightWhitespace;
                        if (textFlowData.InlineCount > 0)
                        {
                            stripAllRightWhitespace = false;
                        }
                        else
                        {
                            stripAllRightWhitespace = true;
                        }

                        textNodeAdded = CollapseAndAddTextNode(textFlowData, stripAllRightWhitespace);

                        // if this is inline then decrement the inline count
                        // else pop the stack
                        if (textFlowData.InlineCount > 0)
                        {
                            textFlowData.InlineCount--;
                        }
                        else
                        {
                            TextFlowStack.Pop();
                        }
                    }
                    break;

                // treat as tags are not there but keep track for flows.
                // i.e. don't process text in buffer on either start tag.
                case XamlNodeType.PropertyComplexStart:
                case XamlNodeType.PropertyArrayStart:
                case XamlNodeType.PropertyIListStart:
                case XamlNodeType.PropertyIDictionaryStart:
                    {
                        // If we've accumulated whitespace text before the start of a
                        // property tag, then empty out that text, since property tags
                        // shouldn't cause whitespace text content to be realized.
                        if (textFlowData.TextNode != null)
                        {
                            if (IsWhitespace(textFlowData.TextNode.Text))
                            {
                                textFlowData.TextNode.UpdateText(string.Empty);
                            }
                            else
                            {
                                textNodeAdded = CollapseAndAddTextNode(textFlowData, /*stripAllRightWhitespace:*/true);
                            }
                        }
                        TextFlowStackData flowData = new TextFlowStackData();
                        TextFlowStack.Push(flowData);
                        break;
                    }

                // pop the stack shouldn't be any text to process.
                case XamlNodeType.PropertyComplexEnd:
                case XamlNodeType.PropertyArrayEnd:
                case XamlNodeType.PropertyIListEnd:
                case XamlNodeType.PropertyIDictionaryEnd:
                    Debug.Assert(0 == textFlowData.InlineCount, "Text stack still has an inline count");
                    textNodeAdded = CollapseAndAddTextNode(textFlowData, /*stripAllRightWhitespace:*/true);
                    _textFlowStack.Pop();
                    break;

                default:
                    break;
            }


            //If we aren't waiting to figure out when the textnode ends
            if (addNodeToBuffer)
            {
                //If a textnode was added to the baml (whitespace collapsing, etc... may cause textnodes to not be put into baml)
                //then we want to make sure that the parent of the textnode has the correct number of children.  The parent may either have
                //one or n children.  We also enforce that content can't be split up by property elements.
                if (textNodeAdded)
                {
                    bool isPropertyStartNode = false;

                    // ElementStart and Property*Start (which are XML Elements) each
                    // push a new context frame.  So for those, look in the parent.
                    ElementContextStackData textContext;
                    switch (xamlNode.TokenType)
                    {
                        case XamlNodeType.ElementStart:
                            textContext = ParentContext;
                            break;

                        case XamlNodeType.PropertyComplexStart:
                        case XamlNodeType.PropertyArrayStart:
                        case XamlNodeType.PropertyIListStart:
                        case XamlNodeType.PropertyIDictionaryStart:
                            textContext = ParentContext;
                            isPropertyStartNode = true;
                            break;
                        default:
                            textContext = CurrentContext;
                            break;
                    }

                    // Verify... "throw"s if we are "After" Content and
                    // returns false if there are multiple elements but
                    // the property is not a container.
                    if (!VerifyContentPropertySeesAnElement(textContext))
                    {
                        //only allow the 2nd (thru Nth) add if ContentPropertyInfo is a Collection (IList, etc...)
                        //Would be nicer to get real string here, but that would require more caching during the non-error cases.
                        throw new InvalidOperationException(SR.Get(SRID.ParserCanOnlyHaveOneChild,
                            textContext.ContextDataType.Name /* Parent */,
                            (textFlowData.TextNode == null ? "" : textFlowData.TextNode.Text) /* Child */));
                    }

                    if(isPropertyStartNode)
                        textContext.ContentParserState = ParsingContent.After;
                }

                if (insert)
                {
                    if (insertAtStart)
                    {
                        TokenReaderNodeCollection.InsertAtStartMark(xamlNode);
                    }
                    else
                    {
                        TokenReaderNodeCollection.InsertAtCurrentMark(xamlNode);
                    }
                }
                else
                {
                    TokenReaderNodeCollection.Add(xamlNode);
                }
            }
        }
        /// <summary>
        /// Constructor. Internal so only the XamlParser and select
        /// Avalon object parsers can call it.
        /// </summary>
        internal XamlReaderHelper(
            XamlParser xamlParser,
            ParserContext parserContext,
            XmlReader xmlReader)
        {

            Debug.Assert(xamlParser != null, "Cannot have null xaml parser");
            Debug.Assert(parserContext != null, "Cannot have null parser context");
            Debug.Assert(xmlReader != null, "Cannot have null xmlReader");

            // use the parser class for making resolution callbacks. for GetElementBaseType
            // probably should break that call + the XamlTypeMapper calls into an interface to
            // comletely abstract the resolution from the tokenizer.
            _xamlParser = xamlParser;
            _parserContext = parserContext;

            XmlReader = xmlReader;
            Normalization = true;

            _xamlNodeCollectionProcessor = new XamlNodeCollectionProcessor();

            // setup the _textFlow stack
            _textFlowStack = new Stack();

            // push a rootLevel stack
            // !! Todo. Need a way for caller of the parser to set how
            // the root text should be handled. For now always use InlineBlock.
            TextFlowStackData textFlowStackData = new TextFlowStackData();
            textFlowStackData.StripLeadingSpaces = true;

            TextFlowStack.Push(textFlowStackData);

            _extensionParser = new MarkupExtensionParser((IParserHelper)this, parserContext);

#if UseValidatingReader
            // turn on to setup validating Reader.
            XmlValidatingReader xmlValidatingReader = new XmlValidatingReader(xmlReader);
            xmlValidatingReader.ValidationType = ValidationType.None;
            XmlReader = xmlValidatingReader;

#endif // UseValidatingReader

        }