class CouponONArithmeticAverageDiscountingMethod {

  public MultipleCurrencyMulticurveSensitivity presentValueCurveSensitivity(final CouponONArithmeticAverage coupon, final MulticurveProviderInterface multicurve) {
    ArgumentChecker.notNull(coupon, "Coupon");
    ArgumentChecker.notNull(multicurve, "Multi-curve provider");
    // Forward sweep
    final double[] delta = coupon.getFixingPeriodAccrualFactors();
    final double[] startTimes = coupon.getFixingPeriodStartTimes();
    final double[] endTimes = coupon.getFixingPeriodEndTimes();
    ;
    final int nbFwd = delta.length;
    final double[] forwardON = new double[nbFwd];
    double rateAccrued = coupon.getRateAccrued();
    for (int loopfwd = 0; loopfwd < nbFwd; loopfwd++) {
      forwardON[loopfwd] = multicurve.getSimplyCompoundForwardRate(coupon.getIndex(), startTimes[loopfwd], endTimes[loopfwd], delta[loopfwd]);
      rateAccrued += forwardON[loopfwd] * delta[loopfwd];
    }
    final double df = multicurve.getDiscountFactor(coupon.getCurrency(), coupon.getPaymentTime());
    // Backward sweep
    final double pvBar = 1.0;
    final double dfBar = rateAccrued * coupon.getNotional() * pvBar;
    final double rateAccruedBar = df * coupon.getNotional() * pvBar;
    final double[] forwardONBar = new double[nbFwd];
    for (int loopfwd = 0; loopfwd < nbFwd; loopfwd++) {
      forwardONBar[loopfwd] = delta[loopfwd] * rateAccruedBar;
    }
    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 loopfwd = 0; loopfwd < nbFwd; loopfwd++) {
      listForward.add(new SimplyCompoundedForwardSensitivity(startTimes[loopfwd], endTimes[loopfwd], delta[loopfwd], forwardONBar[loopfwd]));
    }
    mapFwd.put(multicurve.getName(coupon.getIndex()), listForward);
    final MultipleCurrencyMulticurveSensitivity result = MultipleCurrencyMulticurveSensitivity.of(coupon.getCurrency(), MulticurveSensitivity.of(mapDsc, mapFwd));
    return result;
  }

  private  CouponONArithmeticAverageDiscountingMethod();

}