}
// calendar needed for endOfMonth adjustment
Calendar nullCalendar = new NullCalendar();
int periods = 1;
Date seed, exitDate;
switch (rule) {
case ZERO:
tenor = new Period(0, TimeUnit.DAYS);
dates.add(effectiveDate);
dates.add(terminationDate);
isRegular.add(true);
break;
case BACKWARD:
dates.add(terminationDate);
seed = terminationDate;
if (nextToLastDate != Date.NULL_DATE && nextToLastDate != null) {
// Add it after 1'st element
dates.add(1, nextToLastDate);
Date temp = nullCalendar.advance(seed, new Period(-periods * tenor.getLength(), tenor.getUnits()), convention,
endOfMonth);
if (!temp.equals(nextToLastDate))
isRegular.add(0, false);
else
isRegular.add(0, true);
seed = nextToLastDate;
}
exitDate = effectiveDate;
if (firstDate != Date.NULL_DATE && firstDate != null)
exitDate = firstDate;
while (true) {
Date temp = nullCalendar.advance(seed, new Period(-periods * tenor.getLength(), tenor.getUnits()), convention,
endOfMonth);
if (temp.lt(exitDate))
break;
else {
dates.add(0, temp);
isRegular.add(0, true);
++periods;
}
}
if (endOfMonth && calendar.isEndOfMonth(seed))
convention = BusinessDayConvention.PRECEDING;
if (!calendar.adjust(dates.get(0), convention).eq(calendar.adjust(effectiveDate, convention))) {
dates.add(0, effectiveDate);
isRegular.add(0, false);
}
break;
case THIRD_WEDNESDAY:
if (endOfMonth)
throw new IllegalStateException("endOfMonth convention incompatible with " + rule + " date generation rule");
// fall through
case FORWARD:
dates.add(effectiveDate);
seed = effectiveDate;
if (firstDate != Date.NULL_DATE && firstDate != null) {
dates.add(firstDate);
Date temp = nullCalendar.advance(seed, new Period(periods * tenor.getLength(), tenor.getUnits()), convention,
endOfMonth);
if (temp != firstDate)
isRegular.add(false);
else
isRegular.add(true);
seed = firstDate;
}
exitDate = terminationDate;
if (nextToLastDate != Date.NULL_DATE && nextToLastDate != null)
exitDate = nextToLastDate;
while (true) {
Date temp = nullCalendar.advance(seed, new Period(periods * tenor.getLength(), tenor.getUnits()), convention,
endOfMonth);
if (temp.gt(exitDate))
break;
else {
dates.add(temp);
isRegular.add(true);
++periods;
}
}
if (endOfMonth && calendar.isEndOfMonth(seed))
convention = BusinessDayConvention.PRECEDING;
if (!calendar.adjust(dates.get(dates.size() - 1), terminationDateConvention).equals(
calendar.adjust(terminationDate, terminationDateConvention))) {
dates.add(terminationDate);
isRegular.add(false);
}
break;
default:
throw new IllegalStateException("unknown DateGeneration::Rule (" + rule + ")");
}
// adjustments
if (rule == DateGenerationRule.THIRD_WEDNESDAY)
for (int i = 1; i < dates.size() - 1; ++i) {
Date d = dates.get(i);
Date adjDate = d.getNthWeekday(3, Weekday.WEDNESDAY);
d.getUpdatable().update(adjDate);
}
for (int i = 0; i < dates.size() - 1; ++i) {
dates.get(i).getUpdatable().update(calendar.adjust(dates.get(i), convention));