/** Returns the criterion-level bid, or null if no such bid exists. */
 private static Money getBid(BiddableAdGroupCriterion biddableCriterion) {
   BiddingStrategyConfiguration biddingConfig =
       biddableCriterion.getBiddingStrategyConfiguration();
   Money cpcBidAmount = null;
   if (biddingConfig.getBids() != null) {
     for (Bids bid : biddingConfig.getBids()) {
       if (bid instanceof CpcBid) {
         CpcBid cpcBid = (CpcBid) bid;
         if (BidSource.CRITERION.equals(cpcBid.getCpcBidSource())) {
           cpcBidAmount = cpcBid.getBid();
           break;
         }
       }
     }
   }
   return cpcBidAmount;
 }
  /**
   * Returns a new tree based on a non-empty collection of ad group criteria. All parameters
   * required.
   *
   * @param adGroupId the ID of the ad group
   * @param parentIdMap the multimap from parent product partition ID to child criteria
   * @return a new ProductPartitionTree
   */
  private static ProductPartitionTree createNonEmptyAdGroupTree(
      Long adGroupId, ListMultimap<Long, AdGroupCriterion> parentIdMap) {
    Preconditions.checkNotNull(adGroupId, "Null ad group ID");
    Preconditions.checkArgument(
        !parentIdMap.isEmpty(), "parentIdMap passed for ad group ID %s is empty", adGroupId);
    Preconditions.checkArgument(
        parentIdMap.containsKey(null),
        "No root criterion found in the list of ad group criteria for ad group ID %s",
        adGroupId);

    AdGroupCriterion rootCriterion = Iterables.getOnlyElement(parentIdMap.get(null));

    Preconditions.checkState(
        rootCriterion instanceof BiddableAdGroupCriterion,
        "Root criterion for ad group ID %s is not a BiddableAdGroupCriterion",
        adGroupId);
    BiddableAdGroupCriterion biddableRootCriterion = (BiddableAdGroupCriterion) rootCriterion;

    BiddingStrategyConfiguration biddingStrategyConfig =
        biddableRootCriterion.getBiddingStrategyConfiguration();
    Preconditions.checkState(
        biddingStrategyConfig != null,
        "Null bidding strategy config on the root node of ad group ID %s",
        adGroupId);
    ProductPartitionNode rootNode =
        new ProductPartitionNode(
            null,
            (ProductDimension) null,
            rootCriterion.getCriterion().getId(),
            new ProductDimensionComparator());

    // Set the root's bid if a bid exists on the BiddableAdGroupCriterion.
    Money rootNodeBid = getBid(biddableRootCriterion);
    if (rootNodeBid != null) {
      rootNode = rootNode.asBiddableUnit().setBid(rootNodeBid.getMicroAmount());
    }

    addChildNodes(rootNode, parentIdMap);

    return new ProductPartitionTree(adGroupId, biddingStrategyConfig, rootNode);
  }