// returns true if a positioning <node> element is needed in diffgram
        private bool OnAdd( DiffgramParentOperation parent, int sourceBorderIndex, int targetBorderIndex )
        {
            EditScriptAdd addOp = _editScript as EditScriptAdd;

            Debug.Assert( addOp._endTargetIndex == _curTargetIndex );
            XmlDiffNode targetRoot = _targetNodes[ addOp._endTargetIndex ];

            // add subtree or leaf node and no descendant node matches (= has been moved from somewhere else)
            if ( addOp._startTargetIndex <= targetRoot.Left &&
             !targetRoot._bSomeDescendantMatches )
            {
            switch ( targetRoot.NodeType )
            {
                case XmlDiffNodeType.ShrankNode:
                    XmlDiffShrankNode shrankNode = (XmlDiffShrankNode)targetRoot;

                    if ( shrankNode.MoveOperationId == 0 )
                        shrankNode.MoveOperationId = GenerateOperationID( XmlDiffDescriptorType.Move );

                    parent.InsertAtBeginning( new DiffgramCopy( shrankNode.MatchingShrankNode, true, shrankNode.MoveOperationId ) );
                    break;

                case XmlDiffNodeType.XmlDeclaration:
                case XmlDiffNodeType.DocumentType:
                case XmlDiffNodeType.EntityReference:
                    parent.InsertAtBeginning( new DiffgramAddNode( targetRoot, 0 ) );
                    break;

                default:
                    if ( !parent.MergeAddSubtreeAtBeginning( targetRoot ) )
                    {
                        parent.InsertAtBeginning( new DiffgramAddSubtrees( targetRoot, 0, !_xmlDiff.IgnoreChildOrder ) );
                    }
                    break;
            }
            // adjust current position
            _curTargetIndex = targetRoot.Left - 1;

            // adjust boundaries in the edit script or move to next edit script operation
            addOp._endTargetIndex = targetRoot.Left - 1;
            if ( addOp._startTargetIndex > addOp._endTargetIndex )
                _editScript = _editScript._nextEditScript;
            }
            // add single but non-leaf node, or some descendant matches (= has been moved from somewhere else )
            // -> recursively process diffgram subtree
            else
            {
            Debug.Assert( !( targetRoot is XmlDiffShrankNode) );
            DiffgramAddNode addNode = new DiffgramAddNode( targetRoot, 0 );

            // adjust current position
            _curTargetIndex--;

            // adjust boundaries in the edit script or move to next edit script operation
            addOp._endTargetIndex--;
            if ( addOp._startTargetIndex > addOp._endTargetIndex )
                _editScript = _editScript._nextEditScript;

            if ( _bBuildingAddTree )
            {
                GenerateDiffgramAdd( addNode, sourceBorderIndex, targetRoot.Left );
            }
            else
            {
                // switch to 'building add-tree' mode
                _postponedEditScript.Reset();
                _bBuildingAddTree = true;

                // generate new tree
                GenerateDiffgramAdd( addNode, sourceBorderIndex, targetRoot.Left );

                _bBuildingAddTree = false;

                // attach postponed edit script to _editScript for futher processing
                if ( _postponedEditScript._firstES != null )
                {
                    Debug.Assert( _postponedEditScript._lastES != null );
                    Debug.Assert( _postponedEditScript._startSourceIndex != 0 );
                    Debug.Assert( _postponedEditScript._endSourceIndex != 0 );
                    _curSourceIndex = _postponedEditScript._endSourceIndex;
                    _postponedEditScript._lastES._nextEditScript = _editScript;
                    _editScript = _postponedEditScript._firstES;
                }
            }

            // add attributes
            if ( targetRoot.NodeType == XmlDiffNodeType.Element )
                GenerateAddDiffgramForAttributes( addNode, (XmlDiffElement)targetRoot );

            parent.InsertAtBeginning( addNode );
            }

            // return true if positioning <node> element is needed in diffgram
            if ( _bChildOrderSignificant ) {
            return !_bBuildingAddTree;
            }
            else {
            return false;
            }
        }
        // produces <change> element in diffgram
        private void OnChange( DiffgramParentOperation parent )
        {
            EditScriptChange chOp = _editScript as EditScriptChange;

            Debug.Assert( chOp._targetIndex == _curTargetIndex );
            Debug.Assert( chOp._sourceIndex == _curSourceIndex );

            XmlDiffNode sourceRoot = _sourceNodes[ chOp._sourceIndex ];
            XmlDiffNode targetRoot = _targetNodes[ chOp._targetIndex ];

            Debug.Assert( !( sourceRoot is XmlDiffShrankNode) );
            Debug.Assert( !( targetRoot is XmlDiffShrankNode) );

            // adjust current position
            _curSourceIndex--;
            _curTargetIndex--;

            // move to next edit script operation
            _editScript = _editScript._nextEditScript;

            DiffgramOperation diffgramNode = null;

            if ( _bBuildingAddTree )
            {
            // <add> changed node to the new location
            if ( targetRoot.NodeType == XmlDiffNodeType.Element )
                diffgramNode = new DiffgramAddNode( targetRoot, 0 );
            else
                diffgramNode = new DiffgramAddSubtrees( targetRoot, 0, !_xmlDiff.IgnoreChildOrder );

            // <remove> old node from old location -> add to postponed operations
            bool bSubtree = sourceRoot.NodeType != XmlDiffNodeType.Element;
            PostponedRemoveNode( sourceRoot, bSubtree, 0,
            //AddToPosponedOperations( new DiffgramRemoveNode( sourceRoot, bSubtree, 0 ),
                chOp._sourceIndex, chOp._sourceIndex );

            // recursively process children
            if ( sourceRoot.Left < chOp._sourceIndex ||
                targetRoot.Left < chOp._targetIndex )
            {
                Debug.Assert( targetRoot.NodeType == XmlDiffNodeType.Element );
                GenerateDiffgramAdd( (DiffgramParentOperation)diffgramNode, sourceRoot.Left, targetRoot.Left );
            }

            // add attributes, if element
            if ( targetRoot.NodeType == XmlDiffNodeType.Element )
                GenerateAddDiffgramForAttributes( (DiffgramParentOperation)diffgramNode, (XmlDiffElement)targetRoot );
            }
            else
            {
            ulong opid = 0;

            // change of namespace or prefix -> get the appropriate operation id
            if ( !_xmlDiff.IgnoreNamespaces &&
                 sourceRoot.NodeType == XmlDiffNodeType.Element )
            {
                XmlDiffElement sourceEl = (XmlDiffElement)sourceRoot;
                XmlDiffElement targetEl = (XmlDiffElement)targetRoot;

                if ( sourceEl.LocalName == targetEl.LocalName )
                {
                    opid = GetNamespaceChangeOpid( sourceEl.NamespaceURI, sourceEl.Prefix,
                                                   targetEl.NamespaceURI, targetEl.Prefix );
                }
            }

            if ( sourceRoot.NodeType == XmlDiffNodeType.Element )
            {
                if ( XmlDiff.IsChangeOperationOnAttributesOnly( chOp._changeOp ) )
                    diffgramNode = new DiffgramPosition( sourceRoot );
                else
                {
                    Debug.Assert( (int)chOp._changeOp == (int)XmlDiffOperation.ChangeElementName ||
                                  ( (int)chOp._changeOp >= (int)XmlDiffOperation.ChangeElementNameAndAttr1 &&
                                    (int)chOp._changeOp <= (int)XmlDiffOperation.ChangeElementNameAndAttr2 ) );

                    diffgramNode = new DiffgramChangeNode( sourceRoot, targetRoot, XmlDiffOperation.ChangeElementName, opid );
                }

                // recursively process children
                if ( sourceRoot.Left < chOp._sourceIndex ||
                    targetRoot.Left < chOp._targetIndex )
                {
                    GenerateDiffgramMatch( (DiffgramParentOperation) diffgramNode, sourceRoot.Left, targetRoot.Left );
                }

                GenerateChangeDiffgramForAttributes( (DiffgramParentOperation)diffgramNode, (XmlDiffElement)sourceRoot, (XmlDiffElement)targetRoot );
            }
            else
            {
                // '<change>'
                diffgramNode = new DiffgramChangeNode( sourceRoot, targetRoot, chOp._changeOp, opid );
                Debug.Assert( !sourceRoot.HasChildNodes );
            }
            }

            parent.InsertAtBeginning( diffgramNode );
        }
        private DiffgramOperation GenerateDiffgramAddWhenDescendantMatches( XmlDiffNode targetParent )
        {
            Debug.Assert( targetParent.HasChildNodes );
            Debug.Assert( targetParent._bSomeDescendantMatches );
            Debug.Assert( targetParent.NodeType != XmlDiffNodeType.ShrankNode );

            DiffgramParentOperation diffOp = new DiffgramAddNode( targetParent, 0 );
            if ( targetParent.NodeType == XmlDiffNodeType.Element ) {
            XmlDiffAttributeOrNamespace attr = ((XmlDiffElement)targetParent)._attributes;
            while ( attr != null ) {
                diffOp.InsertAtEnd( new DiffgramAddNode( attr, 0 ) );
                attr = (XmlDiffAttributeOrNamespace) attr._nextSibling;
            }
            }

            XmlDiffNode child = ((XmlDiffParentNode)targetParent)._firstChildNode;
            while ( child != null )
            {
            if ( child.NodeType == XmlDiffNodeType.ShrankNode )
            {
                XmlDiffShrankNode shrankNode = (XmlDiffShrankNode) child;

                if ( shrankNode.MoveOperationId == 0 )
                    shrankNode.MoveOperationId = GenerateOperationID( XmlDiffDescriptorType.Move );

                diffOp.InsertAtEnd( new DiffgramCopy( shrankNode.MatchingShrankNode, true, shrankNode.MoveOperationId ) );
            }
            else if ( child.HasChildNodes && child._bSomeDescendantMatches )
            {
                diffOp.InsertAtEnd( GenerateDiffgramAddWhenDescendantMatches( (XmlDiffParentNode)child ) );
            }
            else
            {
                if ( !diffOp.MergeAddSubtreeAtEnd( child ) )
                    diffOp.InsertAtEnd( new DiffgramAddSubtrees( child, 0, !_xmlDiff.IgnoreChildOrder ) );
            }

            child = child._nextSibling;
            }
            return diffOp;
        }