class CapFloorCMSSABRReplicationMethod extends CapFloorCMSSABRReplicationAbstractMethod {

  @Override
  public MultipleCurrencyAmount presentValue(final CapFloorCMS cmsCapFloor, final SABRSwaptionProviderInterface sabrData) {
    ArgumentChecker.notNull(cmsCapFloor, "CMA cap/floor");
    ArgumentChecker.notNull(sabrData, "SABR swaption provider");
    final Currency ccy = cmsCapFloor.getCurrency();
    final SABRInterestRateParameters sabrParameter = sabrData.getSABRParameter();
    final SwapFixedCoupon<? extends Payment> underlyingSwap = cmsCapFloor.getUnderlyingSwap();
    final double forward = underlyingSwap.accept(PRDC, sabrData.getMulticurveProvider());
    final double discountFactor = sabrData.getMulticurveProvider().getDiscountFactor(ccy, cmsCapFloor.getPaymentTime());
    final CMSIntegrant integrant = new CMSIntegrant(cmsCapFloor, sabrParameter, forward);
    final double strike = cmsCapFloor.getStrike();
    final double strikePart = discountFactor * integrant.g(forward) / integrant.h(forward) * integrant.k(strike) * integrant.bs(strike);
    final double absoluteTolerance = 0.1 / (discountFactor * Math.abs(cmsCapFloor.getNotional()) * cmsCapFloor.getPaymentYearFraction());
    // Implementation note: Each sub-integral has less than 0.1 currency unit error.
    final double relativeTolerance = 1.0E-6;
    final RungeKuttaIntegrator1D integrator = new RungeKuttaIntegrator1D(absoluteTolerance, relativeTolerance, getNbIteration());
    // TODO: replace the integrator by an integrator that does not used the limits (open end). Recorded as [PLAT-1679].
    // TODO: replace the integrator by an integrator that accept infinite interval (for the upper limit of cap).
    double integralPart;
    try {
      if (cmsCapFloor.isCap()) {
        integralPart = discountFactor * integrator.integrate(integrant, strike, strike + getIntegrationInterval());
      } else {
        integralPart = discountFactor * integrator.integrate(integrant, 0.0, strike);
      }
    } catch (final Exception e) {
      throw new MathException(e);
    }
    final double priceCMS = (strikePart + integralPart) * cmsCapFloor.getNotional() * cmsCapFloor.getPaymentYearFraction();
    return MultipleCurrencyAmount.of(cmsCapFloor.getCurrency(), priceCMS);
  }

  private  CapFloorCMSSABRReplicationMethod();
  public  CapFloorCMSSABRReplicationMethod(final double integrationInterval);

}