class CouponONCompoundedDiscountingMethod {

  public MultipleCurrencyMulticurveSensitivity presentValueCurveSensitivity(final CouponONCompounded coupon, final MulticurveProviderInterface multicurve) {
    ArgumentChecker.notNull(coupon, "Coupon");
    ArgumentChecker.notNull(multicurve, "Multi-curves");
    final double df = multicurve.getDiscountFactor(coupon.getCurrency(), coupon.getPaymentTime());
    double ratio = 1.0;
    final double[] forward = new double[coupon.getFixingPeriodAccrualFactors().length];
    for (int i = 0; i < coupon.getFixingPeriodAccrualFactors().length; i++) {
      forward[i] = multicurve.getAnnuallyCompoundForwardRate(coupon.getIndex(), coupon.getFixingPeriodStartTimes()[i], coupon.getFixingPeriodEndTimes()[i], coupon.getFixingPeriodAccrualFactors()[i]);
      ratio *= Math.pow(1 + forward[i], coupon.getFixingPeriodAccrualFactors()[i]);
    }
    // Backward sweep
    final double pvBar = 1.0;
    final double ratioBar = coupon.getNotionalAccrued() * df * pvBar;
    final double[] forwardBar = new double[coupon.getFixingPeriodAccrualFactors().length];
    for (int i = 0; i < coupon.getFixingPeriodAccrualFactors().length; i++) {
      forwardBar[i] = ratioBar * ratio * coupon.getFixingPeriodAccrualFactors()[i] / (1 + forward[i]);
    }
    final double dfBar = coupon.getNotionalAccrued() * ratio * pvBar;
    final Map<String, List<DoublesPair>> mapDsc = new HashMap<>();
    final List<DoublesPair> listDiscounting = new ArrayList<>();
    listDiscounting.add(DoublesPair.of(coupon.getPaymentTime(), -coupon.getPaymentTime() * df * dfBar));
    mapDsc.put(multicurve.getName(coupon.getCurrency()), listDiscounting);
    final Map<String, List<ForwardSensitivity>> mapFwd = new HashMap<>();
    final List<ForwardSensitivity> listForward = new ArrayList<>();
    for (int i = 0; i < coupon.getFixingPeriodAccrualFactors().length; i++) {
      listForward.add(new AnnuallyCompoundedForwardSensitivity(coupon.getFixingPeriodStartTimes()[i], coupon.getFixingPeriodEndTimes()[i], coupon.getFixingPeriodAccrualFactors()[i], forwardBar[i]));
    }
    mapFwd.put(multicurve.getName(coupon.getIndex()), listForward);
    final MultipleCurrencyMulticurveSensitivity result = MultipleCurrencyMulticurveSensitivity.of(coupon.getCurrency(), MulticurveSensitivity.of(mapDsc, mapFwd));
    return result;
  }

  private  CouponONCompoundedDiscountingMethod();

}