class CapFloorInflationYearOnYearInterpolationBlackNormalSmileMethod {

  public MultipleCurrencyInflationSensitivity presentValueCurveSensitivity(final CapFloorInflationYearOnYearInterpolation cap, final BlackSmileCapInflationYearOnYearProviderInterface black) {
    ArgumentChecker.notNull(cap, "The cap/floor shoud not be null");
    ArgumentChecker.notNull(black, "Black provider");
    final InflationProviderInterface inflation = black.getInflationProvider();
    final double timeToMaturity = cap.getReferenceEndTime()[1] - cap.getLastKnownFixingTime();
    final EuropeanVanillaOption option = new EuropeanVanillaOption(cap.getStrike(), timeToMaturity, cap.isCap());
    final double priceIndexStart0 = black.getInflationProvider().getPriceIndex(cap.getPriceIndex(), cap.getReferenceStartTime()[0]);
    final double priceIndexStart1 = black.getInflationProvider().getPriceIndex(cap.getPriceIndex(), cap.getReferenceStartTime()[1]);
    final double priceIndexStart = cap.getWeightStart() * priceIndexStart0 + (1 - cap.getWeightStart()) * priceIndexStart1;
    final double priceIndexEnd0 = black.getInflationProvider().getPriceIndex(cap.getPriceIndex(), cap.getReferenceEndTime()[0]);
    final double priceIndexEnd1 = black.getInflationProvider().getPriceIndex(cap.getPriceIndex(), cap.getReferenceEndTime()[1]);
    final double priceIndexEnd = cap.getWeightEnd() * priceIndexEnd0 + (1 - cap.getWeightEnd()) * priceIndexEnd1;
    final double forward = priceIndexEnd / priceIndexStart - 1;
    final double df = black.getMulticurveProvider().getDiscountFactor(cap.getCurrency(), cap.getPaymentTime());
    final Map<String, List<DoublesPair>> resultMapPrice = new HashMap<>();
    final List<DoublesPair> listPrice = new ArrayList<>();
    listPrice.add(DoublesPair.of(cap.getReferenceEndTime()[0], cap.getWeightEnd() / priceIndexStart));
    listPrice.add(DoublesPair.of(cap.getReferenceEndTime()[1], (1 - cap.getWeightEnd()) / priceIndexStart));
    listPrice.add(DoublesPair.of(cap.getReferenceStartTime()[0], -cap.getWeightStart() * priceIndexEnd / (priceIndexStart * priceIndexStart)));
    listPrice.add(DoublesPair.of(cap.getReferenceStartTime()[1], -(1 - cap.getWeightStart()) * priceIndexEnd / (priceIndexStart * priceIndexStart)));
    resultMapPrice.put(inflation.getName(cap.getPriceIndex()), listPrice);
    final InflationSensitivity forwardDi = InflationSensitivity.ofPriceIndex(resultMapPrice);
    final double dfDr = -cap.getPaymentTime() * df;
    final double volatility = black.getBlackParameters().getVolatility(cap.getReferenceEndTime()[1], cap.getStrike());
    final NormalFunctionData dataBlack = new NormalFunctionData(forward, 1.0, volatility);
    final double[] priceDerivatives = new double[3];
    final double bsAdjoint = NORMAL_FUNCTION.getPriceAdjoint(option, dataBlack, priceDerivatives);
    final List<DoublesPair> list = new ArrayList<>();
    list.add(DoublesPair.of(cap.getPaymentTime(), dfDr));
    final Map<String, List<DoublesPair>> resultMap = new HashMap<>();
    resultMap.put(inflation.getName(cap.getCurrency()), list);
    InflationSensitivity result = InflationSensitivity.ofYieldDiscounting(resultMap);
    result = result.multipliedBy(bsAdjoint);
    result = result.plus(forwardDi.multipliedBy(df * priceDerivatives[0]));
    result = result.multipliedBy(cap.getNotional() * cap.getPaymentYearFraction());
    return MultipleCurrencyInflationSensitivity.of(cap.getCurrency(), result);
  }

  private  CapFloorInflationYearOnYearInterpolationBlackNormalSmileMethod();

}