class RatesCurveInputsMarketDataFunction implements MarketDataFunction<RatesCurveInputs, RatesCurveInputsId> {

  @Override
  public MarketDataBox<RatesCurveInputs> build(
      RatesCurveInputsId id,
      MarketDataConfig marketDataConfig,
      ScenarioMarketData marketData,
      ReferenceData refData) {

    CurveGroupName groupName = id.getCurveGroupName();
    CurveName curveName = id.getCurveName();
    RatesCurveGroupDefinition groupDefn = marketDataConfig.get(RatesCurveGroupDefinition.class, groupName);
    Optional<CurveDefinition> optionalDefinition = groupDefn.findCurveDefinition(id.getCurveName());

    if (!optionalDefinition.isPresent()) {
      throw new IllegalArgumentException(Messages.format("No curve named '{}' found in group '{}'", curveName, groupName));
    }
    CurveDefinition configuredDefn = optionalDefinition.get();
    // determine market data needs
    MarketDataBox<LocalDate> valuationDates = marketData.getValuationDate();
    boolean multipleValuationDates = valuationDates.isScenarioValue();
    // curve definition can vary for each valuation date
    if (multipleValuationDates) {
      List<CurveDefinition> curveDefns = IntStream.range(0, valuationDates.getScenarioCount())
          .mapToObj(valuationDates::getValue)
          .map((LocalDate valDate) -> configuredDefn.filtered(valDate, refData))
          .collect(toImmutableList());

      Set<MarketDataId<?>> requirements = nodeRequirements(curveDefns);
      Map<MarketDataId<?>, MarketDataBox<?>> marketDataValues =
          requirements.stream().collect(toImmutableMap(k -> k, k -> marketData.getValue(k)));
      return buildMultipleCurveInputs(MarketDataBox.ofScenarioValues(curveDefns), marketDataValues, valuationDates, refData);
    }
    // only one valuation date
    LocalDate valuationDate = valuationDates.getValue(0);
    CurveDefinition filteredDefn = configuredDefn.filtered(valuationDate, refData);
    Set<MarketDataId<?>> requirements = nodeRequirements(ImmutableList.of(filteredDefn));
    Map<MarketDataId<?>, MarketDataBox<?>> marketDataValues =
        requirements.stream().collect(toImmutableMap(k -> k, k -> marketData.getValue(k)));
    // Do any of the inputs contain values for multiple scenarios, or do they contain 1 value each?
    boolean multipleInputValues = marketDataValues.values().stream().anyMatch(MarketDataBox::isScenarioValue);

    return multipleInputValues || multipleValuationDates ?
        buildMultipleCurveInputs(MarketDataBox.ofSingleValue(filteredDefn), marketDataValues, valuationDates, refData) :
        buildSingleCurveInputs(filteredDefn, marketDataValues, valuationDate, refData);
  }

}