@implementation iCalRecurrenceCalculator
+static Class NSCalendarDateClass = Nil;
+static Class iCalRecurrenceRuleClass = Nil;
static Class dailyCalcClass = Nil;
static Class weeklyCalcClass = Nil;
static Class monthlyCalcClass = Nil;
if (didInit) return;
didInit = YES;
+ NSCalendarDateClass = [NSCalendarDate class];
+ iCalRecurrenceRuleClass = [iCalRecurrenceRule class];
+
dailyCalcClass = [iCalDailyRecurrenceCalculator class];
weeklyCalcClass = [iCalWeeklyRecurrenceCalculator class];
monthlyCalcClass = [iCalMonthlyRecurrenceCalculator class];
yearlyCalcClass = [iCalYearlyRecurrenceCalculator class];
}
+/* factory */
+
+ (id)recurrenceCalculatorForRecurrenceRule:(iCalRecurrenceRule *)_rrule
withFirstInstanceCalendarDateRange:(NGCalendarDateRange *)_range
{
firstInstanceCalendarDateRange:_range] autorelease];
}
+/* complex calculation convenience */
+
++ (NSArray *)recurrenceRangesWithinCalendarDateRange:(NGCalendarDateRange *)_r
+ firstInstanceCalendarDateRange:(NGCalendarDateRange *)_fir
+ recurrenceRules:(NSArray *)_rRules
+ exceptionRules:(NSArray *)_exRules
+ exceptionDates:(NSArray *)_exDates
+{
+ id rule;
+ iCalRecurrenceCalculator *calc;
+ NSMutableArray *ranges;
+ unsigned i, count, rCount;
+
+ ranges = [NSMutableArray array];
+ count = [_rRules count];
+ for (i = 0; i < count; i++) {
+ NSArray *rs;
+
+ rule = [_rRules objectAtIndex:i];
+ if (![rule isKindOfClass:iCalRecurrenceRuleClass])
+ rule = [iCalRecurrenceRule recurrenceRuleWithICalRepresentation:rule];
+
+ calc = [self recurrenceCalculatorForRecurrenceRule:rule
+ withFirstInstanceCalendarDateRange:_fir];
+ rs = [calc recurrenceRangesWithinCalendarDateRange:_r];
+ [ranges addObjectsFromArray:rs];
+ }
+
+ if (![ranges count])
+ return nil;
+
+ /* test if any exceptions do match */
+ count = [_exRules count];
+ for (i = 0; i < count; i++) {
+ NSArray *rs;
+
+ rule = [_exRules objectAtIndex:i];
+ if (![rule isKindOfClass:iCalRecurrenceRuleClass])
+ rule = [iCalRecurrenceRule recurrenceRuleWithICalRepresentation:rule];
+
+ calc = [self recurrenceCalculatorForRecurrenceRule:rule
+ withFirstInstanceCalendarDateRange:_fir];
+ rs = [calc recurrenceRangesWithinCalendarDateRange:_r];
+ [ranges removeObjectsInArray:rs];
+ }
+
+ if (![ranges count])
+ return nil;
+
+ /* exception dates are also possible */
+ rCount = [ranges count];
+ count = [_exDates count];
+ for (i = 0; i < count; i++) {
+ id exDate;
+ NGCalendarDateRange *r;
+ unsigned k;
+
+ exDate = [_exDates objectAtIndex:i];
+ if (![exDate isKindOfClass:NSCalendarDateClass]) {
+ exDate = [NSCalendarDate calendarDateWithICalRepresentation:exDate];
+ }
+ for (k = 0; k < rCount; k++) {
+ r = [ranges objectAtIndex:(rCount - k) - 1];
+ if ([r containsDate:exDate]) {
+ [ranges removeObjectAtIndex:k];
+ }
+ }
+ }
+ return ranges;
+}
+
+
+/* init */
+
- (id)initWithRecurrenceRule:(iCalRecurrenceRule *)_rrule
firstInstanceCalendarDateRange:(NGCalendarDateRange *)_range
{
NGCalendarDateRange *r;
start = [NSCalendarDate dateForJulianNumber:jnCurrent];
+ [start setTimeZone:[firStart timeZone]];
start = [start hour: [firStart hourOfDay]
minute:[firStart minuteOfHour]
second:[firStart secondOfMinute]];
NGCalendarDateRange *r;
start = [NSCalendarDate dateForJulianNumber:jnCurrent];
+ [start setTimeZone:[firStart timeZone]];
start = [start hour: [firStart hourOfDay]
minute:[firStart minuteOfHour]
second:[firStart secondOfMinute]];
NGCalendarDateRange *r;
start = [NSCalendarDate dateForJulianNumber:jnCurrent];
+ [start setTimeZone:[firStart timeZone]];
start = [start hour: [firStart hourOfDay]
minute:[firStart minuteOfHour]
second:[firStart secondOfMinute]];
start = [firStart dateByAddingYears:0
months:diff + i
days:0];
+ [start setTimeZone:[firStart timeZone]];
end = [start addTimeInterval:[self->firstRange duration]];
r = [NGCalendarDateRange calendarDateRangeWithStartDate:start
endDate:end];
start = [firStart dateByAddingYears:diff + i
months:0
days:0];
+ [start setTimeZone:[firStart timeZone]];
end = [start addTimeInterval:[self->firstRange duration]];
r = [NGCalendarDateRange calendarDateRangeWithStartDate:start
endDate:end];