private void OnRemove( DiffgramParentOperation parent )
        {
            EditScriptRemove remOp = _editScript as EditScriptRemove;

            Debug.Assert( remOp._endSourceIndex == _curSourceIndex );
            XmlDiffNode sourceRoot = _sourceNodes[ remOp._endSourceIndex ];

            // remove subtree or leaf node and no descendant node matches (=has been moved somewhere else)
            if ( remOp._startSourceIndex <= sourceRoot.Left )
            {
            bool bShrankNode = sourceRoot is XmlDiffShrankNode;

            if ( sourceRoot._bSomeDescendantMatches && !bShrankNode )
            {
                DiffgramOperation newDiffOp = GenerateDiffgramRemoveWhenDescendantMatches( (XmlDiffParentNode)sourceRoot );
                if ( _bBuildingAddTree )
                {
                    PostponedOperation( newDiffOp, sourceRoot.Left, remOp._endSourceIndex );
                }
                else
                {
                    parent.InsertAtBeginning( newDiffOp );
                }
            }
            else
            {
                ulong opid = 0;
                // shrank node -> output as 'move' operation
                if ( bShrankNode )
                {
                    XmlDiffShrankNode shrankNode = (XmlDiffShrankNode) sourceRoot;
                    if ( shrankNode.MoveOperationId == 0 )
                        shrankNode.MoveOperationId = GenerateOperationID( XmlDiffDescriptorType.Move );
                    opid = shrankNode.MoveOperationId;

                    Debug.Assert( sourceRoot == _sourceNodes[ sourceRoot.Left ] );
                }

                // insert 'remove' operation
                if ( _bBuildingAddTree )
                {
                    PostponedRemoveSubtrees( sourceRoot, opid,
                    //AddToPosponedOperations( new DiffgramRemoveSubtrees( sourceRoot, opid ),
                        sourceRoot.Left, remOp._endSourceIndex );
                }
                else
                {
                    if ( opid != 0 ||
                        !parent.MergeRemoveSubtreeAtBeginning( sourceRoot ) )
                    {
                        parent.InsertAtBeginning( new DiffgramRemoveSubtrees( sourceRoot, opid, !_xmlDiff.IgnoreChildOrder ) );
                    }
                }
            }

            // adjust current position
            _curSourceIndex = sourceRoot.Left - 1;

            // adjust boundaries in the edit script or move to next edit script operation
            remOp._endSourceIndex = sourceRoot.Left - 1;
            if ( remOp._startSourceIndex > remOp._endSourceIndex )
                _editScript = _editScript._nextEditScript;
            }
            // remove single but non-leaf node or some descendant matches (=has been moved somewhere else)
            // -> recursively process diffgram subtree
            else
            {
            Debug.Assert( !( sourceRoot is XmlDiffShrankNode) );

            // adjust current position
            _curSourceIndex--;

            // adjust boundaries in the edit script or move to next edit script operation
            remOp._endSourceIndex--;
            if ( remOp._startSourceIndex > remOp._endSourceIndex )
                _editScript = _editScript._nextEditScript;

            bool bRemoveSubtree = sourceRoot.NodeType != XmlDiffNodeType.Element;

            if ( _bBuildingAddTree )
            {
                // add 'remove' to postponed operations
                PostponedRemoveNode( sourceRoot, bRemoveSubtree, 0,
                //AddToPosponedOperations( new DiffgramRemoveNode( sourceRoot, bRemoveSubtree, 0 ),
                    remOp._endSourceIndex + 1, remOp._endSourceIndex + 1 );

                // recursively parse subtree
                GenerateDiffgramAdd( parent, sourceRoot.Left, _targetNodes[ _curTargetIndex ].Left );
            }
            else
            {
                // 'remove' operation
                DiffgramRemoveNode remNode = new DiffgramRemoveNode( sourceRoot, bRemoveSubtree, 0 );

                // parse subtree
                GenerateDiffgramMatch( remNode, sourceRoot.Left, _targetNodes[ _curTargetIndex ].Left );

                parent.InsertAtBeginning( remNode );
            }
            }
        }
        void OnEditScriptPostponed( DiffgramParentOperation parent, int targetBorderIndex )
        {
            EditScriptPostponed esp = (EditScriptPostponed)_editScript;
            Debug.Assert( _curSourceIndex == esp._endSourceIndex );

            DiffgramOperation diffOp = esp._diffOperation;
            int sourceStartIndex = esp._startSourceIndex;
            int sourceLeft = _sourceNodes[ esp._endSourceIndex ].Left;

            // adjust current source index
            _curSourceIndex = esp._startSourceIndex - 1;

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

            // not a subtree or leaf node operation -> process child operations
            if ( sourceStartIndex > sourceLeft ) {
            GenerateDiffgramPostponed( (DiffgramParentOperation)diffOp, ref _editScript, sourceLeft, targetBorderIndex );
            }

            parent.InsertAtBeginning( diffOp );
        }
        private void OnMatch( DiffgramParentOperation parent, bool bNeedPosition )
        {
            EditScriptMatch matchOp = _editScript as EditScriptMatch;

            Debug.Assert( _curSourceIndex == matchOp._firstSourceIndex + matchOp._length - 1 );
            Debug.Assert( _curTargetIndex == matchOp._firstTargetIndex + matchOp._length - 1 );

            // cache
            int endTargetIndex = matchOp._firstTargetIndex + matchOp._length - 1;
            int endSourceIndex = matchOp._firstSourceIndex + matchOp._length - 1;
            XmlDiffNode targetRoot = _targetNodes[ endTargetIndex ];
            XmlDiffNode sourceRoot = _sourceNodes[ endSourceIndex ];

            // a subtree or leaf node matches
            if ( matchOp._firstTargetIndex <= targetRoot.Left  &&
             matchOp._firstSourceIndex <= sourceRoot.Left )
            {
            if ( _bBuildingAddTree )
            {
                Debug.Assert( !bNeedPosition );

                ulong opid = GenerateOperationID( XmlDiffDescriptorType.Move );

                // output <add match=" "> to diffgram and "remove" to substitute script
                parent.InsertAtBeginning( new DiffgramCopy( sourceRoot, true, opid ) );

                // add 'remove' operation to postponed operations
                PostponedRemoveSubtrees( sourceRoot, opid,
                //AddToPosponedOperations( new DiffgramRemoveSubtrees( sourceRoot, opid ),
                                        sourceRoot.Left,
                                        endSourceIndex );
            }
            else
            {
                // matched element -> check attributes if they really match (hash values of attributes matches)
                if ( sourceRoot.NodeType == XmlDiffNodeType.Element )
                {
                    DiffgramPosition diffPos = _cachedDiffgramPosition;
                    diffPos._sourceNode = sourceRoot;

                    GenerateChangeDiffgramForAttributes( diffPos, (XmlDiffElement)sourceRoot, (XmlDiffElement)targetRoot );

                    if ( diffPos._firstChildOp != null || bNeedPosition )
                    {
                        parent.InsertAtBeginning( diffPos );
                        _cachedDiffgramPosition = new DiffgramPosition( null );
                        bNeedPosition = false;
                    }
                }
                // otherwise output <node> - only if we need the position (<=> preceding operation was 'add')
                else
                {
                    if ( bNeedPosition )
                    {
                        parent.InsertAtBeginning( new DiffgramPosition( sourceRoot ) );
                        bNeedPosition = false;
                    }
                    // xml declaration, DTD
                    else if ( !_bChildOrderSignificant && (int)sourceRoot.NodeType < 0 ) {
                        DiffgramOperation op = parent._firstChildOp;
                        if ( op is DiffgramAddNode || op is DiffgramAddSubtrees || op is DiffgramCopy ) {
                            parent.InsertAtBeginning( new DiffgramPosition( sourceRoot ) );
                        }
                    }
                }
            }

            // adjust current position
            _curSourceIndex = sourceRoot.Left - 1;
            _curTargetIndex = targetRoot.Left - 1;

            // adjust boundaries in the edit script or move to next edit script operation
            matchOp._length -= endTargetIndex - targetRoot.Left + 1;
            if ( matchOp._length <= 0 )
                _editScript = _editScript._nextEditScript;
            }
            // single but non-leaf node matches (-> recursively generate the diffgram subtree)
            else
            {
            // adjust current position
            _curSourceIndex--;
            _curTargetIndex--;

            // adjust boundaries in the edit script or move to next edit script operation
            matchOp._length--;
            if ( matchOp._length <= 0 )
                _editScript = _editScript._nextEditScript;

            DiffgramParentOperation diffgramNode;
            if ( _bBuildingAddTree )
            {
                Debug.Assert( !bNeedPosition );

                ulong opid = GenerateOperationID( XmlDiffDescriptorType.Move );
                bool bCopySubtree = sourceRoot.NodeType != XmlDiffNodeType.Element;

                // output <add match=".." subtree="no">
                diffgramNode = new DiffgramCopy( sourceRoot, bCopySubtree, opid );
                // add 'remove' operation to postponed operations
                PostponedRemoveNode( sourceRoot, bCopySubtree, opid,
                                     endSourceIndex,
                                     endSourceIndex );

                // recursively generate the diffgram subtree
                GenerateDiffgramAdd( diffgramNode, sourceRoot.Left, targetRoot.Left );

                // insert to diffgram tree
                parent.InsertAtBeginning( diffgramNode );
            }
            else
            {
                // output <node>
                diffgramNode = new DiffgramPosition( sourceRoot );

                // recursively generate the diffgram subtree
                GenerateDiffgramMatch( diffgramNode, sourceRoot.Left, targetRoot.Left );

                // insert to diffgram tree
                if ( diffgramNode._firstChildOp != null )
                    parent.InsertAtBeginning( diffgramNode );
            }
            }
        }
        // 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 void GenerateDiffgramMatch( DiffgramParentOperation parent, int sourceBorderIndex, int targetBorderIndex )
        {
            bool bNeedPosition = false;

            while ( _curSourceIndex >= sourceBorderIndex  ||
                _curTargetIndex >= targetBorderIndex )
            {
            Debug.Assert( _editScript != null );

            switch ( _editScript.Operation )
            {
                case EditScriptOperation.Match:
                    OnMatch( parent, bNeedPosition );
                    bNeedPosition = false;
                    break;
                case EditScriptOperation.Add:
                    bNeedPosition = OnAdd( parent, sourceBorderIndex, targetBorderIndex );
                    break;
                case EditScriptOperation.Remove:
                    if ( _curSourceIndex < sourceBorderIndex )
                        return;
                    OnRemove( parent );
                    break;
                case EditScriptOperation.ChangeNode:
                    if ( _curSourceIndex < sourceBorderIndex )
                        return;
                    OnChange( parent );
                    break;
                case EditScriptOperation.EditScriptPostponed:
                    if ( _curSourceIndex < sourceBorderIndex )
                        return;
                    OnEditScriptPostponed( parent, targetBorderIndex );
                    break;
                default:
                    Debug.Assert( false, "Invalid edit script operation type in final edit script." );
                    break;
            }
            }
        }
        private void GenerateDiffgramPostponed( DiffgramParentOperation parent, ref EditScript editScript, int sourceBorderIndex, int targetBorderIndex )
        {
            while ( _curSourceIndex >= sourceBorderIndex  &&  editScript != null )
            {
            EditScriptPostponed esp = editScript as EditScriptPostponed;
            if ( esp == null ) {
                GenerateDiffgramMatch( parent, sourceBorderIndex, targetBorderIndex );
                return;
            }

            Debug.Assert( esp._endSourceIndex == _curSourceIndex );

            int sourceStartIndex = esp._startSourceIndex;
            int sourceLeft = _sourceNodes[ esp._endSourceIndex ].Left;
            DiffgramOperation diffOp = esp._diffOperation;

            // adjust current source index
            _curSourceIndex = esp._startSourceIndex - 1;

            // move to next edit script
            editScript = esp._nextEditScript;

            // not a subtree or leaf node operation -> process child operations
            if ( sourceStartIndex > sourceLeft ) {
                GenerateDiffgramPostponed( (DiffgramParentOperation) diffOp, ref editScript, sourceLeft, targetBorderIndex );
            }

            // insert operation
            parent.InsertAtBeginning( diffOp );
            }
        }
        private void GenerateChangeDiffgramForAttributes( DiffgramParentOperation diffgramParent, 
            XmlDiffElement sourceElement,
            XmlDiffElement targetElement)
        {
            XmlDiffAttributeOrNamespace sourceAttr = sourceElement._attributes;
            XmlDiffAttributeOrNamespace targetAttr = targetElement._attributes;
            int nCompare;
            ulong opid;

            while ( sourceAttr != null && targetAttr != null )
            {
            opid = 0;

            if ( sourceAttr.NodeType == targetAttr.NodeType )
            {
                if ( sourceAttr.NodeType == XmlDiffNodeType.Attribute )
                {
                    if ( (nCompare = XmlDiffDocument.OrderStrings( sourceAttr.LocalName, targetAttr.LocalName )) == 0 )
                    {
                        if ( _xmlDiff.IgnoreNamespaces )
                        {
                            if ( XmlDiffDocument.OrderStrings( sourceAttr.Value, targetAttr.Value ) == 0 )
                            {
                                // attributes match
                                goto Next;
                            }
                        }
                        else
                        {
                            if ( XmlDiffDocument.OrderStrings( sourceAttr.NamespaceURI, targetAttr.NamespaceURI ) == 0  &&
                                 (_xmlDiff.IgnorePrefixes || XmlDiffDocument.OrderStrings( sourceAttr.Prefix, targetAttr.Prefix )  == 0 ) &&
                                XmlDiffDocument.OrderStrings( sourceAttr.Value, targetAttr.Value ) == 0 )
                            {
                                // attributes match
                                goto Next;
                            }
                        }

                        diffgramParent.InsertAtBeginning( new DiffgramChangeNode( sourceAttr, targetAttr, XmlDiffOperation.ChangeAttr, 0 ) );
                        goto Next;
                    }

                    goto AddRemove;
                }
                else // sourceAttr.NodeType != XmlDiffNodeType.Attribute
                {
                    if ( _xmlDiff.IgnorePrefixes ) {
                        if ( ( nCompare = XmlDiffDocument.OrderStrings( sourceAttr.NamespaceURI, targetAttr.NamespaceURI ) ) == 0 )
                            goto Next;
                        else
                            goto AddRemove;
                    }
                    else if ( ( nCompare = XmlDiffDocument.OrderStrings( sourceAttr.Prefix, targetAttr.Prefix ) ) == 0 ) {
                        if ( ( nCompare = XmlDiffDocument.OrderStrings( sourceAttr.NamespaceURI, targetAttr.NamespaceURI ) ) == 0 )
                            goto Next;
                        else {
                            // change of namespace
                            opid = GetNamespaceChangeOpid( sourceAttr.NamespaceURI, sourceAttr.Prefix,
                                                        targetAttr.NamespaceURI, targetAttr.Prefix );
                            goto AddRemoveBoth;
                        }
                    }
                    else {
                        if ( ( nCompare = XmlDiffDocument.OrderStrings( sourceAttr.NamespaceURI, targetAttr.NamespaceURI ) ) == 0 ) {
                            // change of prefix
                            opid = GetNamespaceChangeOpid( sourceAttr.NamespaceURI, sourceAttr.Prefix,
                                                        targetAttr.NamespaceURI, targetAttr.Prefix );
                            goto AddRemoveBoth;
                        }
                        else {
                            goto AddRemove;
                        }
                    }
                }
            }
            else // ( sourceAttr.NodeType != targetAttr.NodeType )
            {
                if ( sourceAttr.NodeType == XmlDiffNodeType.Namespace )
                    goto RemoveSource;
                else
                    goto AddTarget;
            }

            Next:
            sourceAttr = (XmlDiffAttributeOrNamespace)sourceAttr._nextSibling;
            targetAttr = (XmlDiffAttributeOrNamespace)targetAttr._nextSibling;
            continue;

            AddRemove:
            if ( nCompare == -1 )
                goto RemoveSource;
            else
            {
                Debug.Assert( nCompare == 1 );
                goto AddTarget;
            }

            AddRemoveBoth:
            if ( !diffgramParent.MergeRemoveAttributeAtBeginning( sourceAttr ) )
                diffgramParent.InsertAtBeginning( new DiffgramRemoveNode( sourceAttr, true, opid ) );
            sourceAttr = (XmlDiffAttributeOrNamespace)sourceAttr._nextSibling;

            diffgramParent.InsertAtBeginning( new DiffgramAddNode( targetAttr, opid ) );
            targetAttr = (XmlDiffAttributeOrNamespace)targetAttr._nextSibling;
            continue;

            RemoveSource:
            if ( !diffgramParent.MergeRemoveAttributeAtBeginning( sourceAttr ) )
                diffgramParent.InsertAtBeginning( new DiffgramRemoveNode( sourceAttr, true, opid ) );
            sourceAttr = (XmlDiffAttributeOrNamespace)sourceAttr._nextSibling;
            continue;

            AddTarget:
            diffgramParent.InsertAtBeginning( new DiffgramAddNode( targetAttr, opid ) );
            targetAttr = (XmlDiffAttributeOrNamespace)targetAttr._nextSibling;
            continue;
            }

            while ( sourceAttr != null )
            {
            if ( !diffgramParent.MergeRemoveAttributeAtBeginning( sourceAttr ) )
                diffgramParent.InsertAtBeginning( new DiffgramRemoveNode( sourceAttr, true, 0 ) );
            sourceAttr = (XmlDiffAttributeOrNamespace)sourceAttr._nextSibling;
            }

            while ( targetAttr != null )
            {
            diffgramParent.InsertAtBeginning( new DiffgramAddNode( targetAttr, 0 ) );
            targetAttr = (XmlDiffAttributeOrNamespace)targetAttr._nextSibling;
            }
        }
        private void GenerateDiffgramAdd( DiffgramParentOperation parent, int sourceBorderIndex, int targetBorderIndex )
        {
            while ( _curTargetIndex >= targetBorderIndex )
            {
            Debug.Assert( _editScript != null );

            switch ( _editScript.Operation )
            {
                case EditScriptOperation.Match:
                    OnMatch( parent, false );
                    break;
                case EditScriptOperation.Add:
                    OnAdd( parent, sourceBorderIndex, targetBorderIndex );
                    break;
                case EditScriptOperation.Remove:
                    OnRemove( parent );
                    break;
                case EditScriptOperation.ChangeNode:
                    OnChange( parent );
                    break;
                case EditScriptOperation.EditScriptPostponed:
                    OnEditScriptPostponed( parent, targetBorderIndex );
                    break;
                default:
                    Debug.Assert( false, "Invalid edit script operation type in final edit script." );
                    break;
            }
            }
        }
        private void WalkTreeOnRemoveNode( DiffgramParentOperation diffParent, XmlDiffNode sourceNode )
        {
            bool bShrankNode = sourceNode is XmlDiffShrankNode;

            if ( sourceNode._bSomeDescendantMatches && !bShrankNode )
            {
            DiffgramOperation removeOp = GenerateDiffgramRemoveWhenDescendantMatches( (XmlDiffParentNode)sourceNode );
            diffParent.InsertAtEnd( removeOp );
            }
            else
            {
            ulong opid = 0;
            // shrank node -> output as 'move' operation
            if ( bShrankNode )
            {
                XmlDiffShrankNode shrankNode = (XmlDiffShrankNode) sourceNode;
                if ( shrankNode.MoveOperationId == 0 )
                    shrankNode.MoveOperationId = GenerateOperationID( XmlDiffDescriptorType.Move );
                opid = shrankNode.MoveOperationId;
            }

            if ( opid != 0 ||
                !diffParent.MergeRemoveSubtreeAtEnd( sourceNode ) )
            {
                diffParent.InsertAtEnd( new DiffgramRemoveSubtrees( sourceNode, opid, !_xmlDiff.IgnoreChildOrder ) );
            }
            }
        }
 private void GenerateAddDiffgramForAttributes( DiffgramParentOperation diffgramParent, XmlDiffElement targetElement )
 {
     XmlDiffAttributeOrNamespace attr = targetElement._attributes;
     while ( attr != null )
     {
     diffgramParent.InsertAtBeginning( new DiffgramAddNode( attr, 0 ) );
     attr = (XmlDiffAttributeOrNamespace)attr._nextSibling;
     }
 }
 private void WalkTreeOnMatchNode( DiffgramParentOperation diffParent, XmlDiffNode sourceNode, XmlDiffNode targetNode, ref XmlDiffNode needPositionSourceNode )
 {
     if ( sourceNode.HasChildNodes || targetNode.HasChildNodes ) {
     DiffgramPosition diffMatch = new DiffgramPosition( sourceNode );
     WalkTreeGenerateDiffgramMatch( diffMatch, (XmlDiffParentNode)sourceNode, (XmlDiffParentNode)targetNode );
     diffParent.InsertAtEnd( diffMatch );
     needPositionSourceNode = null;
     }
     else {
     if ( sourceNode.NodeType == XmlDiffNodeType.ShrankNode ) {
         needPositionSourceNode = ((XmlDiffShrankNode)sourceNode)._lastNode;
     }
     else {
         needPositionSourceNode = sourceNode;
     }
     }
 }
        private void WalkTreeOnChangeNode( DiffgramParentOperation diffParent, XmlDiffNode sourceNode, XmlDiffNode targetNode, XmlDiffOperation op )
        {
            Debug.Assert( sourceNode.NodeType != XmlDiffNodeType.Element && targetNode.NodeType != XmlDiffNodeType.Element );

            DiffgramChangeNode changeOp = new DiffgramChangeNode( sourceNode, targetNode, op, 0 );
            if ( sourceNode.HasChildNodes || targetNode.HasChildNodes ) {
            WalkTreeGenerateDiffgramMatch( changeOp, (XmlDiffParentNode) sourceNode, (XmlDiffParentNode) targetNode );
            }
            diffParent.InsertAtEnd( changeOp );
        }
        private void WalkTreeOnChangeElement( DiffgramParentOperation diffParent, XmlDiffElement sourceElement, XmlDiffElement targetElement, XmlDiffOperation op )
        {
            DiffgramParentOperation diffOp;

            if ( XmlDiff.IsChangeOperationOnAttributesOnly( op ) ) {
            diffOp = new DiffgramPosition( sourceElement );
            }
            else
            {
            ulong opid = 0;
            if ( !_xmlDiff.IgnoreNamespaces && sourceElement.LocalName == targetElement.LocalName)
            {
                opid = GetNamespaceChangeOpid( sourceElement.NamespaceURI, sourceElement.Prefix,
                                               targetElement.NamespaceURI, targetElement.Prefix );
            }

            Debug.Assert( (int)op >= (int)XmlDiffOperation.ChangeElementName &&
                          (int)op <= (int)XmlDiffOperation.ChangeElementNameAndAttr3 );

            diffOp = new DiffgramChangeNode( sourceElement, targetElement, XmlDiffOperation.ChangeElementName, opid );
            }

            GenerateChangeDiffgramForAttributes( diffOp, sourceElement, targetElement );

            if ( sourceElement.HasChildNodes || targetElement.HasChildNodes ) {
            WalkTreeGenerateDiffgramMatch( diffOp, sourceElement, targetElement );
            }

            diffParent.InsertAtEnd( diffOp );
        }
        private void WalkTreeOnAddNode( DiffgramParentOperation diffParent, XmlDiffNode targetNode, XmlDiffNode sourcePositionNode )
        {
            bool bShrankNode = targetNode is XmlDiffShrankNode;

            if ( _bChildOrderSignificant ) {
            if ( sourcePositionNode != null ) {
                diffParent.InsertAtEnd( new DiffgramPosition( sourcePositionNode ) );
            }
            }
            else {
            if ( diffParent._firstChildOp == null && diffParent is Diffgram ) {
                diffParent.InsertAtEnd( new DiffgramPosition( sourcePositionNode ) );
            }
            }

            if ( targetNode._bSomeDescendantMatches && !bShrankNode ) {
            DiffgramOperation addOp = GenerateDiffgramAddWhenDescendantMatches( (XmlDiffParentNode)targetNode );
            diffParent.InsertAtEnd( addOp );
            }
            else {
            // shrank node -> output as 'move' operation
            if ( bShrankNode ) {
                ulong opid = 0;
                XmlDiffShrankNode shrankNode = (XmlDiffShrankNode) targetNode;
                if ( shrankNode.MoveOperationId == 0 )
                    shrankNode.MoveOperationId = GenerateOperationID( XmlDiffDescriptorType.Move );
                opid = shrankNode.MoveOperationId;

                diffParent.InsertAtEnd( new DiffgramCopy( shrankNode.MatchingShrankNode, true, opid ) );
            }
            else {
                switch ( targetNode.NodeType ) {
                    case XmlDiffNodeType.XmlDeclaration:
                    case XmlDiffNodeType.DocumentType:
                    case XmlDiffNodeType.EntityReference:
                        diffParent.InsertAtEnd( new DiffgramAddNode( targetNode, 0 ) );
                        break;
                    default:
                        if ( !diffParent.MergeAddSubtreeAtEnd( targetNode ) ) {
                            diffParent.InsertAtEnd( new DiffgramAddSubtrees( targetNode, 0, !_xmlDiff.IgnoreChildOrder ) );
                        }
                        break;
                }
            }
            }
        }
        private void WalkTreeGenerateDiffgramMatch( DiffgramParentOperation diffParent, XmlDiffParentNode sourceParent, XmlDiffParentNode targetParent )
        {
            XmlDiffNode sourceNode = sourceParent.FirstChildNode;
            XmlDiffNode targetNode = targetParent.FirstChildNode;
            XmlDiffNode needPositionSourceNode = null;

            while ( sourceNode != null || targetNode != null ) {
            if ( sourceNode != null ) {
                if ( targetNode != null ) {
                    XmlDiffOperation op = sourceNode.GetDiffOperation( targetNode, _xmlDiff );
                    // match
                    if ( op == XmlDiffOperation.Match ) {
                        WalkTreeOnMatchNode( diffParent, sourceNode, targetNode, ref needPositionSourceNode );
                    }
                    // no match
                    else {
                        int walkNodesCount = ( sourceNode._parent.ChildNodesCount + targetNode._parent.ChildNodesCount ) / 2;
                        walkNodesCount = (int)( LogMultiplier * Math.Log( (double)walkNodesCount ) + 1 );

                        XmlDiffNode sourceClosestMatchNode = targetNode;
                        XmlDiffNode targetClosestMatchNode = sourceNode;
                        XmlDiffOperation sourceOp = op;
                        XmlDiffOperation targetOp = op;
                        int sourceNodesToAddCount = targetNode.NodesCount;
                        int targetNodesToRemoveCount = sourceNode.NodesCount;

                        XmlDiffNode nextSourceNode = sourceNode._nextSibling;
                        XmlDiffNode nextTargetNode = targetNode._nextSibling;

                        // walk limited number of siblings to find the closest matching node
                        for ( int i = 0; i < walkNodesCount && ( nextTargetNode != null || nextSourceNode != null ); i++ ) {
                            if ( nextTargetNode != null && sourceOp != XmlDiffOperation.Match ) {
                                XmlDiffOperation o = sourceNode.GetDiffOperation( nextTargetNode, _xmlDiff );
                                if ( MinimalTreeDistanceAlgo.OperationCost[(int)o] < MinimalTreeDistanceAlgo.OperationCost[(int)sourceOp] ) {
                                    sourceOp = o;
                                    sourceClosestMatchNode = nextTargetNode;
                                }
                                else {
                                    sourceNodesToAddCount += nextTargetNode.NodesCount;
                                    nextTargetNode = nextTargetNode._nextSibling;
                                }
                            }

                            if ( nextSourceNode != null && targetOp != XmlDiffOperation.Match ) {
                                XmlDiffOperation o = targetNode.GetDiffOperation( nextSourceNode, _xmlDiff );
                                if ( MinimalTreeDistanceAlgo.OperationCost[(int)o] < MinimalTreeDistanceAlgo.OperationCost[(int)targetOp] ) {
                                    targetOp = o;
                                    targetClosestMatchNode = nextSourceNode;
                                }
                                else {
                                    targetNodesToRemoveCount += nextSourceNode.NodesCount;
                                    nextSourceNode = nextSourceNode._nextSibling;
                                }
                            }

                            if ( sourceOp == XmlDiffOperation.Match || targetOp == XmlDiffOperation.Match ) {
                                break;
                            }

                            if ( _xmlDiff.IgnoreChildOrder ) {
                                if ( nextTargetNode != null ) {
                                    if ( XmlDiffDocument.OrderChildren( sourceNode, nextTargetNode ) < 0 ) {
                                        nextTargetNode = null;
                                    }
                                }
                                if ( nextSourceNode != null ) {
                                    if ( XmlDiffDocument.OrderChildren( targetNode, nextSourceNode ) < 0 ) {
                                        nextSourceNode = null;
                                    }
                                }
                            }
                        }

                        // source match exists and is better
                        if ( sourceOp == XmlDiffOperation.Match ) {
                            if ( targetOp != XmlDiffOperation.Match || sourceNodesToAddCount < targetNodesToRemoveCount ) {
                                while ( targetNode != sourceClosestMatchNode ) {
                                    WalkTreeOnAddNode( diffParent, targetNode, needPositionSourceNode );
                                    needPositionSourceNode = null;
                                    targetNode = targetNode._nextSibling;
                                }
                                WalkTreeOnMatchNode( diffParent, sourceNode, targetNode, ref needPositionSourceNode );
                                goto MoveToNextPair;
                            }
                        }
                        // target match exists and is better
                        else if ( targetOp == XmlDiffOperation.Match ) {
                            while ( sourceNode != targetClosestMatchNode ) {
                                WalkTreeOnRemoveNode( diffParent, sourceNode );
                                sourceNode = sourceNode._nextSibling;
                            }
                            needPositionSourceNode = null;
                            WalkTreeOnMatchNode( diffParent, sourceNode, targetNode, ref needPositionSourceNode );
                            goto MoveToNextPair;
                        }
                        // partial match
                        else {
                            Debug.Assert( sourceOp != XmlDiffOperation.Match && targetOp != XmlDiffOperation.Match );

                            int sourceOpCost = MinimalTreeDistanceAlgo.OperationCost[ (int)sourceOp ];
                            int targetOpCost = MinimalTreeDistanceAlgo.OperationCost[ (int)targetOp ];

                            if ( sourceOpCost < targetOpCost || ( sourceOpCost == targetOpCost && sourceNodesToAddCount < targetNodesToRemoveCount ) ) {
                                while ( targetNode != sourceClosestMatchNode ) {
                                    WalkTreeOnAddNode( diffParent, targetNode, needPositionSourceNode );
                                    needPositionSourceNode = null;
                                    targetNode = targetNode._nextSibling;
                                }
                                op = sourceOp;
                            }
                            else {
                                while ( sourceNode != targetClosestMatchNode ) {
                                    WalkTreeOnRemoveNode( diffParent, sourceNode );
                                    sourceNode = sourceNode._nextSibling;
                                }
                                op = targetOp;
                            }
                        }

                        // decide whether do 'change' or 'add / delete'
                        switch ( op ) {
                            case XmlDiffOperation.ChangeElementName:
                                WalkTreeOnChangeElement( diffParent, (XmlDiffElement)sourceNode, (XmlDiffElement)targetNode, op );
                                needPositionSourceNode = null;
                                break;
                            case XmlDiffOperation.ChangeElementAttr1:
                            case XmlDiffOperation.ChangeElementAttr2:
                            case XmlDiffOperation.ChangeElementAttr3:
                            case XmlDiffOperation.ChangeElementNameAndAttr1:
                            case XmlDiffOperation.ChangeElementNameAndAttr2:
                            case XmlDiffOperation.ChangeElementNameAndAttr3:
                                if ( GoForElementChange( (XmlDiffElement)sourceNode, (XmlDiffElement)targetNode ) ) {
                                    WalkTreeOnChangeElement( diffParent, (XmlDiffElement) sourceNode, (XmlDiffElement)targetNode, op );
                                    needPositionSourceNode = null;
                                }
                                else {
                                    goto case XmlDiffOperation.Undefined;
                                }
                                break;
                            case XmlDiffOperation.ChangePI:
                            case XmlDiffOperation.ChangeER:
                            case XmlDiffOperation.ChangeCharacterData:
                            case XmlDiffOperation.ChangeXmlDeclaration:
                            case XmlDiffOperation.ChangeDTD:
                                diffParent.InsertAtEnd( new DiffgramChangeNode( sourceNode, targetNode, op, 0 ) );
                                needPositionSourceNode = null;
                                break;

                            case XmlDiffOperation.Undefined:
                                // Prefer inserts against removes
                                WalkTreeOnAddNode( diffParent, targetNode, needPositionSourceNode );
                                needPositionSourceNode = null;
                                targetNode = targetNode._nextSibling;
                                continue;
                            default:
                                Debug.Assert( false );
                                break;
                        }
                    }

                MoveToNextPair:
                    sourceNode = sourceNode._nextSibling;
                    targetNode = targetNode._nextSibling;
                }
                else { // targetNode == null
                    do {
                        WalkTreeOnRemoveNode( diffParent, sourceNode );
                        sourceNode = sourceNode._nextSibling;
                    } while ( sourceNode != null );
                }
            }
            else { // sourceNode == null
                Debug.Assert( targetNode != null );

                while ( targetNode != null ) {
                    WalkTreeOnAddNode( diffParent, targetNode, needPositionSourceNode );
                    needPositionSourceNode = null;
                    targetNode = targetNode._nextSibling;
                }
            }
            }
        }