class CouponIborFxResetDiscountingMethod {

  public MultipleCurrencyMulticurveSensitivity presentValueCurveSensitivity(final CouponIborFxReset coupon,
      final MulticurveProviderInterface multicurves) {
    ArgumentChecker.notNull(coupon, "Coupon");
    ArgumentChecker.notNull(multicurves, "Multi-curves");

    double forward = multicurves.getSimplyCompoundForwardRate(coupon.getIndex(),
        coupon.getIborIndexFixingPeriodStartTime(), coupon.getIborIndexFixingPeriodEndTime(),
        coupon.getIborIndexFixingAccrualFactor());
    Currency ccyPayment = coupon.getCurrency();
    Currency ccyReference = coupon.getReferenceCurrency();
    double tp = coupon.getPaymentTime();
    double t0 = coupon.getFxDeliveryTime();
    double todayFxRate = multicurves.getFxRate(ccyReference, ccyPayment);
    double notional = todayFxRate * coupon.getNotional();
    double amount = notional * (forward + coupon.getSpread()) * coupon.getPaymentYearFraction();
    double dfCcyPaymentAtPayment = multicurves.getDiscountFactor(ccyPayment, tp);
    double dfCcyReferenceAtDelivery = multicurves.getDiscountFactor(ccyReference, t0);
    double dfCcyPaymentAtDelivery = multicurves.getDiscountFactor(ccyPayment, t0);
    double forwardBar = coupon.getPaymentYearFraction() * notional * dfCcyPaymentAtPayment *
        dfCcyReferenceAtDelivery / dfCcyPaymentAtDelivery;
    // Backward sweep.
    double pvBar = 1.0;
    double dfCcyPaymentAtDeliveryBar = -amount *
        dfCcyPaymentAtPayment * dfCcyReferenceAtDelivery / (dfCcyPaymentAtDelivery * dfCcyPaymentAtDelivery) * pvBar;
    double dfCcyReferenceAtDeliveryBar = amount * dfCcyPaymentAtPayment / dfCcyPaymentAtDelivery * pvBar;
    double dfCcyPaymentAtPaymentBar = amount * dfCcyReferenceAtDelivery / dfCcyPaymentAtDelivery * pvBar;
    MultipleCurrencyMulticurveSensitivity result = new MultipleCurrencyMulticurveSensitivity();
    final Map<String, List<DoublesPair>> mapDscCcyPayment = new HashMap<>();
    final List<DoublesPair> listDscCcyPayment = new ArrayList<>();
    listDscCcyPayment.add(DoublesPair.of(t0, -t0 * dfCcyPaymentAtDelivery * dfCcyPaymentAtDeliveryBar));
    listDscCcyPayment.add(DoublesPair.of(tp, -tp * dfCcyPaymentAtPayment * dfCcyPaymentAtPaymentBar));
    mapDscCcyPayment.put(multicurves.getName(ccyPayment), listDscCcyPayment);
    result = result.plus(ccyPayment, MulticurveSensitivity.ofYieldDiscounting(mapDscCcyPayment));
    final Map<String, List<DoublesPair>> mapDscCcyReference = new HashMap<>();
    final List<DoublesPair> listDscCcyReference = new ArrayList<>();
    listDscCcyReference.add(DoublesPair.of(t0, -t0 * dfCcyReferenceAtDelivery * dfCcyReferenceAtDeliveryBar));
    mapDscCcyReference.put(multicurves.getName(ccyReference), listDscCcyReference);
    result = result.plus(ccyPayment, MulticurveSensitivity.ofYieldDiscounting(mapDscCcyReference));
    final Map<String, List<ForwardSensitivity>> mapFwd = new HashMap<>();
    final List<ForwardSensitivity> listForward = new ArrayList<>();
    listForward.add(new SimplyCompoundedForwardSensitivity(coupon.getIborIndexFixingPeriodStartTime(), coupon
        .getIborIndexFixingPeriodEndTime(), coupon.getIborIndexFixingAccrualFactor(), forwardBar));
    mapFwd.put(multicurves.getName(coupon.getIndex()), listForward);
    result = result.plus(ccyPayment, MulticurveSensitivity.ofForward(mapFwd));
    return result;
  }

  private  CouponIborFxResetDiscountingMethod();

}