class ScheduleCalculator {

  public static ZonedDateTime[] getUnadjustedDateSchedule(final ZonedDateTime startDate, final ZonedDateTime endDate, final Period tenorPeriod, final StubType stub) {
    ArgumentChecker.notNull(startDate, "Start date");
    ArgumentChecker.notNull(endDate, "End date");
    ArgumentChecker.notNull(tenorPeriod, "Period tenor");
    ArgumentChecker.isTrue(startDate.isBefore(endDate), "Start date should be strictly before end date");
    final boolean stubShort = stub.equals(StubType.SHORT_END) || stub.equals(StubType.SHORT_START) || stub.equals(StubType.NONE) || stub.equals(StubType.BOTH);
    final boolean fromEnd = isGenerateFromEnd(stub); //  || stub.equals(StubType.NONE); // Implementation note: dates computed from the end.
    final List<ZonedDateTime> dates = new ArrayList<>();
    int nbPeriod = 0;
    if (!fromEnd) { // Add the periods from the start date
      ZonedDateTime date = startDate.plus(tenorPeriod);
      while (date.isBefore(endDate)) { // date is strictly before endDate
        dates.add(date);
        nbPeriod++;
        date = startDate.plus(tenorPeriod.multipliedBy(nbPeriod + 1));
      }
      if (!stubShort && !date.equals(endDate) && nbPeriod >= 1) { // For long stub the last date before end date, if any, is removed.
        dates.remove(nbPeriod - 1);
      }
      dates.add(endDate);
      return dates.toArray(EMPTY_ARRAY);
    }
    // From end - Subtract the periods from the end date
    ZonedDateTime date = endDate;
    while (date.isAfter(startDate)) { // date is strictly after startDate
      dates.add(date);
      nbPeriod++;
      date = endDate.minus(tenorPeriod.multipliedBy(nbPeriod));
    }
    if (!stubShort && !date.equals(startDate) && nbPeriod > 1) { // For long stub the last date before end date, if any, is removed.
      dates.remove(nbPeriod - 1);
    }
    Collections.sort(dates); // To obtain the dates in chronological order.
    return dates.toArray(EMPTY_ARRAY);
  }

  private  ScheduleCalculator();

}