class CouponIborCompoundingSimpleSpreadDiscountingMethod {

  public MultipleCurrencyMulticurveSensitivity presentValueCurveSensitivity(final CouponIborCompoundingSimpleSpread coupon, final MulticurveProviderInterface multicurve) {
    ArgumentChecker.notNull(coupon, "coupon");
    ArgumentChecker.notNull(multicurve, "multicurve");
    int nbSubPeriod = coupon.getFixingTimes().length;
    double cpa = coupon.getCompoundingPeriodAmountAccumulated();
    double[] investFactor = new double[nbSubPeriod];
    for (int loopsub = 0; loopsub < nbSubPeriod; loopsub++) {
      final double forward = multicurve.getSimplyCompoundForwardRate(coupon.getIndex(), coupon.getFixingPeriodStartTimes()[loopsub],
          coupon.getFixingPeriodEndTimes()[loopsub], coupon.getFixingPeriodAccrualFactors()[loopsub]);
      investFactor[loopsub] = 1.0d + forward * coupon.getPaymentPeriodAccrualFactors()[loopsub];
      cpa *= investFactor[loopsub];
    }
    final double df = multicurve.getDiscountFactor(coupon.getCurrency(), coupon.getPaymentTime());
    // Backward sweep
    double pvBar = 1.0;
    double dfBar = (cpa - coupon.getNotional() + coupon.getNotional() * coupon.getPaymentYearFraction() * coupon.getSpread()) * pvBar;
    double cpaBar = df * pvBar;
    final double[] forwardBar = new double[nbSubPeriod];
    for (int loopsub = nbSubPeriod - 1; loopsub >= 0; loopsub--) {
      forwardBar[loopsub] = cpa / investFactor[loopsub] * coupon.getPaymentPeriodAccrualFactors()[loopsub] * cpaBar;
    }
    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 loopsub = 0; loopsub < nbSubPeriod; loopsub++) {
      listForward.add(new SimplyCompoundedForwardSensitivity(coupon.getFixingPeriodStartTimes()[loopsub], coupon.getFixingPeriodEndTimes()[loopsub],
          coupon.getFixingPeriodAccrualFactors()[loopsub],
          forwardBar[loopsub]));
    }
    mapFwd.put(multicurve.getName(coupon.getIndex()), listForward);
    return MultipleCurrencyMulticurveSensitivity.of(coupon.getCurrency(), MulticurveSensitivity.of(mapDsc, mapFwd));
  }

  private  CouponIborCompoundingSimpleSpreadDiscountingMethod();

}