class EmrPricingHelper extends AwsHelper {

    List<EmrClusterPriceDto> getEmrClusterPricesWithinLowestCoreInstancePriceThreshold(final List<EmrClusterPriceDto> emrClusterPrices,
        final BigDecimal lowestCoreInstancePriceThresholdPercentage)
    {
        // Builds a tree map that has the core instance price as the key, and the list of pricing with the same core instance price as the value. The tree map
        // is automatically sorted, so it is easy to find the lowest core instance price range.
        TreeMap<BigDecimal, List<EmrClusterPriceDto>> emrClusterPriceMapKeyedByCoreInstancePrice = new TreeMap<>();
        for (final EmrClusterPriceDto emrClusterPriceDto : emrClusterPrices)
        {
            final BigDecimal coreInstancePrice = getEmrClusterCoreInstancePrice(emrClusterPriceDto);
            if (coreInstancePrice != null)
            {
                if (emrClusterPriceMapKeyedByCoreInstancePrice.containsKey(coreInstancePrice))
                {
                    emrClusterPriceMapKeyedByCoreInstancePrice.get(coreInstancePrice).add(emrClusterPriceDto);
                }
                else
                {
                    List<EmrClusterPriceDto> emrClusterPriceList = new ArrayList<>();
                    emrClusterPriceList.add(emrClusterPriceDto);
                    emrClusterPriceMapKeyedByCoreInstancePrice.put(coreInstancePrice, emrClusterPriceList);
                }
            }
        }

        // Log all the information in the tree map
        LOGGER.info("All available EMR clusters keyed by core instance price: availableEmrClusters={}",
            jsonHelper.objectToJson(emrClusterPriceMapKeyedByCoreInstancePrice));

        // Finds the list of pricing in the range of the lowest core instance price
        List<EmrClusterPriceDto> lowestCoreInstancePriceEmrClusters = new ArrayList<>();
        if (!emrClusterPriceMapKeyedByCoreInstancePrice.isEmpty())
        {
            // calculate the lowest core instance price range
            final BigDecimal lowestCoreInstancePriceLowerBound = emrClusterPriceMapKeyedByCoreInstancePrice.firstEntry().getKey();
            final BigDecimal lowestCoreInstancePriceUpperBound =
                lowestCoreInstancePriceLowerBound.multiply(BigDecimal.ONE.add(lowestCoreInstancePriceThresholdPercentage));

            LOGGER.info("emrClusterLowestCoreInstancePriceRange={}",
                jsonHelper.objectToJson(Arrays.asList(lowestCoreInstancePriceLowerBound, lowestCoreInstancePriceUpperBound)));

            for (final Map.Entry<BigDecimal, List<EmrClusterPriceDto>> entry : emrClusterPriceMapKeyedByCoreInstancePrice.entrySet())
            {
                final BigDecimal coreInstancePrice = entry.getKey();
                // Fall into the lowest price range? add it to the list.
                // There is no need to check the lower bound here, since the tree map is sorted, and lower bound is the lowest core price in the tree map.
                if (coreInstancePrice.compareTo(lowestCoreInstancePriceUpperBound) <= 0)
                {
                    lowestCoreInstancePriceEmrClusters.addAll(entry.getValue());
                }
                else
                {
                    // since the tree map is sorted in ascending order, we do not need to check the rest of entries in the map
                    break;
                }
            }
        }
        return lowestCoreInstancePriceEmrClusters;
    }

}