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 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;
                }
            }
            }
        }