/** Finds the product combinations of numItems items with $1 of the totalPrice */
  private void findProductCombination(
      ArrayList<Product> productList, double target, ArrayList<Product> partial) {
    // Keeping +-2 dollar as the price search window.
    int priceBuffer = 2;

    // if partial size > numItems, you already have too many items, so stop
    if (partial.size() > itemCount) {
      return;
    }

    double sum = 0;
    for (Product x : partial) sum += x.getPrice();

    if (Math.abs(sum - target) < priceBuffer
        && partial.size() == itemCount
        && desiredProductList.size() < 25) {
      // if no price combos yet, just add it on
      if (desiredProductList.size() == 0) {
        desiredProductList.add(new Combination(partial, totalPrice));
      }
      // otherwise, check it against the most recent product combo to make sure you're not repeating
      // TODO: check all product combos
      else {
        Combination testerCombo = desiredProductList.get(desiredProductList.size() - 1);
        Combination partialCombo = new Combination(partial, totalPrice);
        if (!partialCombo.equals(testerCombo)) {
          desiredProductList.add(partialCombo);
        }
      }
    }
    // if sum is at or within $1 of target, then stop - done!
    if (sum >= target + priceBuffer) {
      return;
    }

    // otherwise, recursively continue adding another product to combo and test it
    for (int i = 0; i < productList.size() && !(partial.size() == itemCount && sum < target); i++) {
      ArrayList<Product> remaining = new ArrayList<Product>();
      Product n = productList.get(i);
      for (int j = i + 1; j < productList.size(); j++) {
        remaining.add(productList.get(j));
      }
      ArrayList<Product> partial_rec = new ArrayList<Product>(partial);
      partial_rec.add(n);
      findProductCombination(remaining, target, partial_rec);
    }
  }
  /** Returns the gift combinations that are closest to the total dollar amount */
  @SuppressWarnings("unchecked")
  public String getGiftCombos() throws IOException, ParseException {
    // get products from API
    System.out.println("Searching Zappos...");
    this.findProducts();

    // find combinations that work
    this.findProductCombination(allProductList, totalPrice, new ArrayList<Product>());

    Collections.sort(desiredProductList);

    // see if you have any combos
    if (desiredProductList.size() != 0) {
      String toPrint = "\nDone!\n";
      for (Combination x : desiredProductList) {
        toPrint += x.toString() + "\n";
      }
      return toPrint;
    } else {
      return "No items matching your criteria. Try fewer items or higher price range.";
    }
  }