/// <summary>
        /// Performs a <em>shallow</em> copy of properties from
        /// <paramref name="fromNode"/> to <paramref name="toNode"/>.
        /// </summary>
        /// <param name="fromNode">The node to copy from.</param>
        /// <param name="toNode">The node to copy to.</param>
        /// <returns><paramref name="toNode"/>, with its properties updated.</returns>
        /// <remarks>Does <em>not</em> change the parent node of
        /// <paramref name="toNode"/>.</remarks>
        public static ProductPartitionNode CopyProperties(ProductPartitionNode fromNode,
                                                          ProductPartitionNode toNode)
        {
            switch (fromNode.nodeState.NodeType)
            {
            case NodeType.BIDDABLE_UNIT:
                toNode        = toNode.AsBiddableUnit();
                toNode.CpcBid = fromNode.CpcBid;
                break;

            case NodeType.EXCLUDED_UNIT:
                toNode = toNode.AsExcludedUnit();
                break;

            case NodeType.SUBDIVISION:
                toNode = toNode.AsSubdivision();
                break;

            default:
                throw new InvalidOperationException(
                          "Unrecognized node state: " + fromNode.nodeState.NodeType);
            }

            toNode.ProductPartitionId = fromNode.ProductPartitionId;
            return(toNode);
        }
        /// <summary>
        /// Using the criteria in <paramref name="parentIdMap"/>, recursively adds
        /// all children under the partition ID of <paramref name="parentNode"/> to
        /// <paramref name="parentNode"/>.
        /// </summary>
        /// <param name="parentNode">The parent node.</param>
        /// <param name="parentIdMap">The multimap from parent partition ID to list
        /// of child criteria</param>
        private static void AddChildNodes(ProductPartitionNode parentNode,
                                          Dictionary <long, List <AdGroupCriterion> > parentIdMap)
        {
            List <AdGroupCriterion> childCriteria = null;

            if (parentIdMap.ContainsKey(parentNode.ProductPartitionId))
            {
                childCriteria = parentIdMap[parentNode.ProductPartitionId];
            }

            // no children, return.
            if (childCriteria == null || childCriteria.Count == 0)
            {
                return;
            }

            // Ensure that the parent is a subdivision.
            parentNode.AsSubdivision();

            foreach (AdGroupCriterion childCriterion in childCriteria)
            {
                ProductPartition     partition = (ProductPartition)childCriterion.criterion;
                ProductPartitionNode childNode = parentNode.AddChild(partition.caseValue);
                childNode.ProductPartitionId = partition.id;

                if (childCriterion is BiddableAdGroupCriterion)
                {
                    childNode = childNode.AsBiddableUnit();
                    Money cpcBidAmount = GetBid((BiddableAdGroupCriterion)childCriterion);
                    if (cpcBidAmount != null)
                    {
                        childNode.CpcBid = cpcBidAmount.microAmount;
                    }
                }
                else
                {
                    childNode = childNode.AsExcludedUnit();
                }

                AddChildNodes(childNode, parentIdMap);
            }
        }
        /// <summary>
        /// Using the criteria in <paramref name="parentIdMap"/>, recursively adds
        /// all children under the partition ID of <paramref name="parentNode"/> to
        /// <paramref name="parentNode"/>.
        /// </summary>
        /// <param name="parentNode">The parent node.</param>
        /// <param name="parentIdMap">The multimap from parent partition ID to list
        /// of child criteria</param>
        private static void AddChildNodes(ProductPartitionNode parentNode,
        Dictionary<long, List<AdGroupCriterion>> parentIdMap)
        {
            List<AdGroupCriterion> childCriteria = null;
              if (parentIdMap.ContainsKey(parentNode.ProductPartitionId)) {
            childCriteria = parentIdMap[parentNode.ProductPartitionId];
              }

              // no children, return.
              if (childCriteria == null || childCriteria.Count == 0) {
            return;
              }

              // Ensure that the parent is a subdivision.
              parentNode.AsSubdivision();

              foreach (AdGroupCriterion childCriterion in childCriteria) {
            ProductPartition partition = (ProductPartition) childCriterion.criterion;
            ProductPartitionNode childNode = parentNode.AddChild(partition.caseValue);
            childNode.ProductPartitionId = partition.id;

            if (childCriterion is BiddableAdGroupCriterion) {
              childNode = childNode.AsBiddableUnit();
              Money cpcBidAmount = GetBid((BiddableAdGroupCriterion) childCriterion);
              if (cpcBidAmount != null) {
            childNode.CpcBid = cpcBidAmount.microAmount;
              }
            } else {
              childNode = childNode.AsExcludedUnit();
            }

            AddChildNodes(childNode, parentIdMap);
              }
        }
    /// <summary>
    /// Performs a <em>shallow</em> copy of properties from
    /// <paramref name="fromNode"/> to <paramref name="toNode"/>.
    /// </summary>
    /// <param name="fromNode">The node to copy from.</param>
    /// <param name="toNode">The node to copy to.</param>
    /// <returns><paramref name="toNode"/>, with its properties updated.</returns>
    /// <remarks>Does <em>not</em> change the parent node of
    /// <paramref name="toNode"/>.</remarks>
    public static ProductPartitionNode CopyProperties(ProductPartitionNode fromNode,
        ProductPartitionNode toNode) {
      switch (fromNode.nodeState.NodeType) {
        case NodeType.BIDDABLE_UNIT:
          toNode = toNode.AsBiddableUnit();
          toNode.CpcBid = fromNode.CpcBid;
          break;

        case NodeType.EXCLUDED_UNIT:
          toNode = toNode.AsExcludedUnit();
          break;

        case NodeType.SUBDIVISION:
          toNode = toNode.AsSubdivision();
          break;

        default:
          throw new InvalidOperationException(
              "Unrecognized node state: " + fromNode.nodeState.NodeType);
      }

      toNode.ProductPartitionId = fromNode.ProductPartitionId;
      return toNode;
    }