/**
   * Returns a new AdGroupCriterion configured for an ADD operation.
   *
   * @param node the node whose criterion should be added
   * @param adGroupId the ad group ID of the criterion
   * @param biddingConfig the bidding strategy configuration of the criterion
   */
  static AdGroupCriterion createCriterionForAdd(
      ProductPartitionNode node, long adGroupId, BiddingStrategyConfiguration biddingConfig) {
    Preconditions.checkNotNull(node, "Null node");
    Preconditions.checkNotNull(biddingConfig, "Null bidding configuration");

    AdGroupCriterion adGroupCriterion;
    if (node.isExcludedUnit()) {
      adGroupCriterion = new NegativeAdGroupCriterion();
    } else {
      adGroupCriterion = new BiddableAdGroupCriterion();
      if (node.isUnit() && node.getBid() != null) {
        Money bidMoney = new Money();
        bidMoney.setMicroAmount(node.getBid());
        CpcBid cpcBid = new CpcBid();
        cpcBid.setBid(bidMoney);
        cpcBid.setCpcBidSource(BidSource.CRITERION);
        biddingConfig.setBids(new Bids[] {cpcBid});
        ((BiddableAdGroupCriterion) adGroupCriterion)
            .setBiddingStrategyConfiguration(biddingConfig);
      }
    }
    adGroupCriterion.setAdGroupId(adGroupId);

    ProductPartition partition = new ProductPartition();
    partition.setId(node.getProductPartitionId());
    if (node.getParent() != null) {
      partition.setParentCriterionId(node.getParent().getProductPartitionId());
    }
    partition.setCaseValue(node.getDimension());
    partition.setPartitionType(
        node.isUnit() ? ProductPartitionType.UNIT : ProductPartitionType.SUBDIVISION);
    adGroupCriterion.setCriterion(partition);
    return adGroupCriterion;
  }
  /**
   * Returns a new AdGroupCriterion configured for a SET operation that will set the criterion's
   * bid.
   *
   * @param node the node whose criterion should be updated
   * @param adGroupId the ad group ID of the criterion
   * @param biddingConfig the bidding strategy configuration of the criterion
   */
  static AdGroupCriterion createCriterionForSetBid(
      ProductPartitionNode node, long adGroupId, BiddingStrategyConfiguration biddingConfig) {
    Preconditions.checkNotNull(node, "Null node");
    Preconditions.checkNotNull(biddingConfig, "Null bidding configuration");
    Preconditions.checkArgument(node.isBiddableUnit(), "Node is not a biddable unit");

    BiddableAdGroupCriterion biddableCriterion = new BiddableAdGroupCriterion();
    biddableCriterion.setAdGroupId(adGroupId);

    ProductPartition partition = new ProductPartition();
    partition.setId(node.getProductPartitionId());
    if (node.getParent() != null) {
      partition.setParentCriterionId(node.getParent().getProductPartitionId());
    }
    partition.setCaseValue(node.getDimension());
    partition.setPartitionType(ProductPartitionType.UNIT);

    biddableCriterion.setCriterion(partition);

    if (node.getBid() != null) {
      Money bidMoney = new Money();
      bidMoney.setMicroAmount(node.getBid());
      CpcBid cpcBid = new CpcBid();
      cpcBid.setBid(bidMoney);
      biddingConfig.setBids(new Bids[] {cpcBid});
    } else {
      biddingConfig.setBids(new Bids[0]);
    }
    biddableCriterion.setBiddingStrategyConfiguration(biddingConfig);
    return biddableCriterion;
  }