class AnnuityDefinitionBuilder {

  public static AnnuityDefinition<CouponIborDefinition> couponIborRollDateIndexAdjusted(final ZonedDateTime startDate, final int startNumberRollDate, final int endNumberRollDate,
      final RollDateAdjuster adjuster, final IborIndex index, final double notional, final boolean isPayer, final DayCount dayCount, final Calendar calendar, final StubType stub) {
    final long rollMonths = adjuster.getMonthsToAdjust();
    final long paymentMonths = index.getTenor().toTotalMonths();
    final int rollJump = Math.max(1, (int) (paymentMonths / rollMonths)); // The roll jumps is rounded (toward 0) and is at least 1.
    final int nbRoll = endNumberRollDate - startNumberRollDate;
    final List<ZonedDateTime> legDates = rollDateSchedule(startDate, startNumberRollDate, adjuster, calendar, stub, rollJump, nbRoll);
    final double sign = isPayer ? -1.0 : 1.0;
    final int nbCpn = legDates.size() - 1;
    final CouponIborDefinition[] coupons = new CouponIborDefinition[nbCpn];
    for (int loopcpn = 0; loopcpn < nbCpn; loopcpn++) {
      final ZonedDateTime fixingDate = ScheduleCalculator.getAdjustedDate(legDates.get(loopcpn), -index.getSpotLag(), calendar);
      final double af = dayCount.getDayCountFraction(legDates.get(loopcpn), legDates.get(loopcpn + 1), calendar);
      coupons[loopcpn] = new CouponIborDefinition(index.getCurrency(), legDates.get(loopcpn + 1), legDates.get(loopcpn), legDates.get(loopcpn + 1),
          af, sign * notional, fixingDate, legDates.get(loopcpn), legDates.get(loopcpn + 1), af, index, calendar);
    }
    return new AnnuityDefinition<>(coupons, calendar);
  }

}