/// <summary>
        /// Adds to the operations list all operations required to mutate
        /// <paramref name="originalNode"/> to the state* of
        /// <paramref name="newNode"/>.
        /// </summary>
        /// <param name="originalNode">The original node.</param>
        /// <param name="newNode">The new node.</param>
        /// <param name="ops">The operations list to add to.</param>
        /// <param name="idGenerator">The temporary ID generator for ADD operations.</param>
        /// <returns>The set of child product dimensions that require further
        /// processing.</returns>
        private void AddMutateOperations(ProductPartitionNode originalNode,
                                         ProductPartitionNode newNode, List <OperationPair> ops, TemporaryIdGenerator idGenerator)
        {
            NodeDifference nodeDifference = Diff(originalNode, newNode, dimensionComparator);
            bool           isProcessChildren;

            switch (nodeDifference)
            {
            case NodeDifference.NEW_NODE:
                ops.AddRange(CreateAddOperations(newNode, idGenerator));
                // No need to further process children. The ADD operations above will include operations
                // for all children of newNode.
                isProcessChildren = false;
                break;

            case NodeDifference.REMOVED_NODE:
                ops.Add(CreateRemoveOperation(originalNode));
                // No need to further process children. The REMOVE operation above will perform a
                // cascading delete of all children of newNode.
                isProcessChildren = false;
                break;

            case NodeDifference.PARTITION_TYPE_CHANGE:
            case NodeDifference.EXCLUDED_UNIT_CHANGE:
                ops.Add(CreateRemoveOperation(originalNode));
                ops.AddRange(CreateAddOperations(newNode, idGenerator));
                // No need to further process children. The ADD operations above will include operations
                // for all children of newNode.
                isProcessChildren = false;
                break;

            case NodeDifference.BID_CHANGE:
                // Ensure that the new node has the proper ID (this may have been lost if the node
                // was removed and then re-added).
                newNode.ProductPartitionId = originalNode.ProductPartitionId;
                ops.Add(CreateSetBidOperation(newNode));
                // Process the children of newNode. The SET operation above will only handle changes
                // made to newNode, not its children.
                isProcessChildren = true;
                break;

            case NodeDifference.NONE:
                // Ensure that the new node has the proper ID (this may have been lost if the node
                // was removed and then re-added).
                newNode.ProductPartitionId = originalNode.ProductPartitionId;
                // This node does not have changes, but its children may.
                isProcessChildren = true;
                break;

            default:
                throw new InvalidOperationException("Unrecognized difference: " + nodeDifference);
            }

            if (isProcessChildren)
            {
                // Try to match the children in new and original trees to identify the
                // matching dimensions.

                foreach (ProductPartitionNode newChild in newNode.Children)
                {
                    if (originalNode.HasChild(newChild.Dimension))
                    {
                        // this is probably an edit.
                        AddMutateOperations(originalNode.GetChild(newChild.Dimension), newChild, ops,
                                            idGenerator);
                    }
                    else
                    {
                        // this is a new node.
                        AddMutateOperations(null, newChild, ops, idGenerator);
                    }
                }

                foreach (ProductPartitionNode originalChild in originalNode.Children)
                {
                    if (newNode.HasChild(originalChild.Dimension))
                    {
                        // this is probably an edit. We dealt with it before
                        continue;
                    }
                    else
                    {
                        // this is a removed node.
                        AddMutateOperations(originalChild, null, ops, idGenerator);
                    }
                }
            }
        }