/// <summary>
        /// Creates ADD operations for the node and ALL of its children.
        /// </summary>
        /// <param name="node">The node.</param>
        /// <param name="idGenerator">The temporary ID generator for new nodes.</param>
        /// <returns>A list of operation pair for the specified operation and nodes.
        /// </returns>
        private List <OperationPair> CreateAddOperations(ProductPartitionNode node,
                                                         TemporaryIdGenerator idGenerator)
        {
            AdGroupCriterionOperation addOp = new AdGroupCriterionOperation();

            addOp.@operator = Operator.ADD;

            // Overwrite the ID set by the user when doing ADD operations. This
            // minimizes the chances of a malformed tree.
            node.ProductPartitionId = idGenerator.Next;

            addOp.operand = ProductPartitionNodeAdapter.CreateCriterionForAdd(node, adGroupId,
                                                                              idGenerator);

            List <OperationPair> operationsList = new List <OperationPair>();

            operationsList.Add(new OperationPair(node, addOp));

            // Recursively add all of this node's children to the operations list.
            foreach (ProductPartitionNode child in node.Children)
            {
                operationsList.AddRange(CreateAddOperations(child, idGenerator));
            }
            return(operationsList);
        }
        /// <summary>
        /// Creates a REMOVE operation for the specified node.
        /// </summary>
        /// <param name="node">The node to be removed.</param>
        /// <returns>An operation pair for the node and the REMOVE operation.
        /// </returns>
        private OperationPair CreateRemoveOperation(ProductPartitionNode node)
        {
            PreconditionUtilities.CheckArgument(node.ProductPartitionId >= NEW_ROOT_ID,
                                                string.Format(ShoppingMessages.NodeForRemoveCannotHaveNegativeId,
                                                              node.ProductPartitionId));

            AdGroupCriterionOperation removeOp = new AdGroupCriterionOperation();

            removeOp.@operator = Operator.REMOVE;
            removeOp.operand   = ProductPartitionNodeAdapter.CreateCriterionForRemove(node, adGroupId);

            return(new OperationPair(node, removeOp));
        }
        /// <summary>
        /// Creates a SET operation for the specified node.
        /// </summary>
        /// <param name="node">The node.</param>
        /// <returns>An operation pair for the specified operation and node.
        /// </returns>
        private OperationPair CreateSetBidOperation(ProductPartitionNode node)
        {
            // TODO(user): This check is dangerous, since we should only depend on parent-child
            // relationships, not ID relationships.
            PreconditionUtilities.CheckArgument(node.ProductPartitionId >= NEW_ROOT_ID,
                                                string.Format(ShoppingMessages.NodeForSetCannotHaveNegativeId, node));
            AdGroupCriterionOperation setOp = new AdGroupCriterionOperation();

            setOp.@operator = Operator.SET;
            setOp.operand   = ProductPartitionNodeAdapter.CreateCriterionForSetBid(node, adGroupId);

            return(new OperationPair(node, setOp));
        }