class AnnuityDefinitionBuilder {

  public static AnnuityCouponFixedDefinition couponFixed(final Currency currency, final ZonedDateTime settlementDate, final ZonedDateTime maturityDate,
      final Period paymentPeriod, final Calendar calendar, final DayCount dayCount, final BusinessDayConvention businessDay, final boolean isEOM, final double notional,
      final double fixedRate, final boolean isPayer, final StubType stub, final int paymentLag) {
    ArgumentChecker.notNull(currency, "currency");
    ArgumentChecker.notNull(settlementDate, "settlement date");
    ArgumentChecker.notNull(maturityDate, "Maturity date");
    ArgumentChecker.notNull(paymentPeriod, "payment period");
    ArgumentChecker.notNull(calendar, "calendar");
    ArgumentChecker.notNull(dayCount, "day count");
    ArgumentChecker.notNull(businessDay, "business day convention");
    final double sign = isPayer ? -1.0 : 1.0;
    final ZonedDateTime[] adjustedEndAccrualDates = ScheduleCalculator.getAdjustedDateSchedule(settlementDate, maturityDate, paymentPeriod, stub,
        businessDay, calendar, isEOM);
    final ZonedDateTime[] paymentDates = ScheduleCalculator.getAdjustedDate(adjustedEndAccrualDates, paymentLag, calendar);
    final CouponFixedDefinition[] coupons = new CouponFixedDefinition[adjustedEndAccrualDates.length];
    //First coupon uses settlement date
    //TODO: only initial stub supported
    double accrualFactor = getDayCountFraction(paymentPeriod, calendar, dayCount, stub, StubType.NONE, settlementDate, adjustedEndAccrualDates[0], true, adjustedEndAccrualDates.length == 1);
    coupons[0] = new CouponFixedDefinition(currency, paymentDates[0], settlementDate, adjustedEndAccrualDates[0], accrualFactor, sign * notional, fixedRate);
    for (int loopcpn = 1; loopcpn < adjustedEndAccrualDates.length; loopcpn++) {
      boolean isMaturity = (adjustedEndAccrualDates.length - 1 == loopcpn);
      accrualFactor = getDayCountFraction(paymentPeriod, calendar, dayCount, stub, StubType.NONE, adjustedEndAccrualDates[loopcpn - 1], adjustedEndAccrualDates[loopcpn], false, isMaturity);
      coupons[loopcpn] = new CouponFixedDefinition(currency, paymentDates[loopcpn], adjustedEndAccrualDates[loopcpn - 1], adjustedEndAccrualDates[loopcpn], accrualFactor, sign * notional, fixedRate);
    }
    return new AnnuityCouponFixedDefinition(coupons, calendar);
  }

}