/// <summary>
      /// Creates a subdivision node.
      /// </summary>
      /// <param name="parent">The node that should be this node's parent.
      /// </param>
      /// <param name="value">The value being paritioned on.</param>
      /// <returns>A new subdivision node.</returns>
      public ProductPartition CreateSubdivision(ProductPartition parent, ProductDimension value) {
        ProductPartition division = new ProductPartition();
        division.partitionType = ProductPartitionType.SUBDIVISION;
        division.id = this.nextId--;

        // The root node has neither a parent nor a value.
        if (parent != null) {
          division.parentCriterionId = parent.id;
          division.caseValue = value;
        }

        BiddableAdGroupCriterion criterion = new BiddableAdGroupCriterion();
        criterion.adGroupId = this.adGroupId;
        criterion.criterion = division;

        this.CreateAddOperation(criterion);
        return division;
      }
    /// <summary>
    /// Displays the product partition tree.
    /// </summary>
    /// <param name="node">The root node.</param>
    /// <param name="children">The child node.</param>
    /// <param name="level">The tree level.</param>
    /// <param name="writer">The stream to write output to.</param>
    private void DisplayTree(ProductPartition node, Dictionary<long,
        List<ProductPartition>> children, int level, StringWriter writer) {
      // Recursively display a node and each of its children.
      object value = null;
      string type = "";

      if (node.caseValue != null) {
        type = node.caseValue.ProductDimensionType;
        switch (type) {
          case "ProductCanonicalCondition":
            value = (node.caseValue as ProductCanonicalCondition).condition.ToString();
            break;

          case "ProductBiddingCategory":
            value = (node.caseValue as ProductBiddingCategory).type.ToString() + "(" +
                (node.caseValue as ProductBiddingCategory).value + ")";
            break;

          default:
            value = node.caseValue.GetType().GetProperty("value").GetValue(node.caseValue, null);
            break;
        }
      }

      writer.WriteLine("{0}id: {1}, type: {2}, value: {3}", "".PadLeft(level, ' '), node.id,
          type, value);
      foreach (ProductPartition childNode in children[node.id]) {
        DisplayTree(childNode, children, level + 1, writer);
      }
    }
      /// <summary>
      /// Creates the unit.
      /// </summary>
      /// <param name="parent">The node that should be this node's parent.
      /// </param>
      /// <param name="value">The value being paritioned on.</param>
      /// <param name="bidAmount">The amount to bid for matching products,
      /// in micros.</param>
      /// <param name="isNegative">True, if this is negative criterion, false
      /// otherwise.</param>
      /// <returns>A new unit node.</returns>
      public ProductPartition CreateUnit(ProductPartition parent, ProductDimension value,
          long bidAmount, bool isNegative) {
        ProductPartition unit = new ProductPartition();
        unit.partitionType = ProductPartitionType.UNIT;

        // The root node has neither a parent nor a value.
        if (parent != null) {
          unit.parentCriterionId = parent.id;
          unit.caseValue = value;
        }

        AdGroupCriterion criterion;

        if (isNegative) {
          criterion = new NegativeAdGroupCriterion();
        } else {
          BiddingStrategyConfiguration biddingStrategyConfiguration =
              new BiddingStrategyConfiguration();

          CpcBid cpcBid = new CpcBid();
          cpcBid.bid = new Money();
          cpcBid.bid.microAmount = bidAmount;
          biddingStrategyConfiguration.bids = new Bids[] { cpcBid };

          criterion = new BiddableAdGroupCriterion();
          (criterion as BiddableAdGroupCriterion).biddingStrategyConfiguration =
              biddingStrategyConfiguration;
        }

        criterion.adGroupId = this.adGroupId;
        criterion.criterion = unit;

        this.CreateAddOperation(criterion);

        return unit;
      }