internal override void EndProcessing()
        {
            // need to pop all the contexts, in case the transmission sequence
            // was interrupted
            while (true)
            {
                FormattingContextState ctx = contextManager.Peek();

                if (ctx == FormattingContextState.none)
                {
                    break; // we emerged and we are done
                }
                else if (ctx == FormattingContextState.group)
                {
                    PopGroup();
                }
                else if (ctx == FormattingContextState.document)
                {
                    // inject the end format information
                    FormatEndData endFormat = new FormatEndData();
                    this.WriteObject(endFormat);
                    contextManager.Pop();
                }
            } // while
        }
        /// <summary>
        /// compute the group transition, given an input object
        /// </summary>
        /// <param name="so">object received from the input pipeline</param>
        /// <returns>GroupTransition enumeration</returns>
        private GroupTransition ComputeGroupTransition(PSObject so)
        {
            // check if we have to start a group
            FormattingContextState ctx = contextManager.Peek();

            if (ctx == FormattingContextState.document)
            {
                // prime the grouping algorithm
                _viewManager.ViewGenerator.UpdateGroupingKeyValue(so);

                // need to start a group, but we are not in one
                return(GroupTransition.enter);
            }

            // check if we need to start another group and keep track
            // of the current value for the grouping property
            return(_viewManager.ViewGenerator.UpdateGroupingKeyValue(so) ? GroupTransition.startNew : GroupTransition.none);
        }
        /// <summary>
        /// execute formatting on a single object
        /// </summary>
        /// <param name="so">object to process</param>
        private void ProcessObject(PSObject so)
        {
            // we do protect against reentrancy, assuming
            // no fancy multiplexing
            if (_formatObjectDeserializer.IsFormatInfoData(so))
            {
                // we are already formatted...
                this.WriteObject(so);
                return;
            }

            // if objects have to be treated as out of band, just
            // bail now
            // this is the case of objects coming before the
            // context manager is properly set
            if (ProcessOutOfBandObjectOutsideDocumentSequence(so))
            {
                return;
            }

            // if we haven't started yet, need to do so
            FormattingContextState ctx = contextManager.Peek();

            if (ctx == FormattingContextState.none)
            {
                // initialize the view manager
                _viewManager.Initialize(this.TerminatingErrorContext, _expressionFactory, _typeInfoDataBase, so, _shape, _parameters);

                // add the start message to output queue
                WriteFormatStartData(so);

                // enter the document context
                contextManager.Push(FormattingContextState.document);
            }

            // if we are here, we are either in the document document, or in a group

            // since we have a view now, we check if objects should be treated as out of band
            if (ProcessOutOfBandObjectInsideDocumentSequence(so))
            {
                return;
            }

            // check if we have to enter or exit a group
            GroupTransition transition = ComputeGroupTransition(so);

            if (transition == GroupTransition.enter)
            {
                // insert the group start marker
                PushGroup(so);
                this.WritePayloadObject(so);
            }
            else if (transition == GroupTransition.exit)
            {
                this.WritePayloadObject(so);
                // insert the group end marker
                PopGroup();
            }
            else if (transition == GroupTransition.startNew)
            {
                // double transition
                PopGroup();    // exit the current one
                PushGroup(so); // start a sibling group
                this.WritePayloadObject(so);
            }
            else // none, we did not have any transitions, just push out the data
            {
                this.WritePayloadObject(so);
            }
        }