-
-
-@implementation iCalDailyRecurrenceCalculator
-
-- (NSArray *)recurrenceRangesWithinCalendarDateRange:(NGCalendarDateRange *)_r {
- NSMutableArray *ranges;
- NSCalendarDate *firStart;
- long i, jnFirst, jnStart, jnEnd, startEndCount;
- unsigned interval;
-
- firStart = [self->firstRange startDate];
- jnFirst = [firStart julianNumber];
- jnEnd = [[_r endDate] julianNumber];
-
- if (jnFirst > jnEnd)
- return nil;
-
- jnStart = [[_r startDate] julianNumber];
- interval = [self->rrule repeatInterval];
-
- /* if rule is bound, check the bounds */
- if (![self->rrule isInfinite]) {
- NSCalendarDate *until;
- long jnRuleLast;
-
- until = [self->rrule untilDate];
- if (until) {
- if ([until compare:[_r startDate]] == NSOrderedAscending)
- return nil;
- jnRuleLast = [until julianNumber];
- }
- else {
- jnRuleLast = (interval * [self->rrule repeatCount])
- + jnFirst;
- if (jnRuleLast < jnStart)
- return nil;
- }
- /* jnStart < jnRuleLast < jnEnd ? */
- if (jnEnd > jnRuleLast)
- jnEnd = jnRuleLast;
- }
-
- startEndCount = (jnEnd - jnStart) + 1;
- ranges = [NSMutableArray arrayWithCapacity:startEndCount];
- for (i = 0 ; i < startEndCount; i++) {
- long jnCurrent;
-
- jnCurrent = jnStart + i;
- if (jnCurrent >= jnFirst) {
- long jnTest;
-
- jnTest = jnCurrent - jnFirst;
- if ((jnTest % interval) == 0) {
- NSCalendarDate *start, *end;
- NGCalendarDateRange *r;
-
- start = [NSCalendarDate dateForJulianNumber:jnCurrent];
- [start setTimeZone:[firStart timeZone]];
- start = [start hour: [firStart hourOfDay]
- minute:[firStart minuteOfHour]
- second:[firStart secondOfMinute]];
- end = [start addTimeInterval:[self->firstRange duration]];
- r = [NGCalendarDateRange calendarDateRangeWithStartDate:start
- endDate:end];
- if ([_r containsDateRange:r])
- [ranges addObject:r];
- }
- }
- }
- return ranges;
-}
-
-- (NSCalendarDate *)lastInstanceStartDate {
- if ([self->rrule repeatCount] > 0) {
- long jnFirst, jnRuleLast;
- NSCalendarDate *firStart, *until;
-
- firStart = [self->firstRange startDate];
- jnFirst = [firStart julianNumber];
- jnRuleLast = ([self->rrule repeatInterval] *
- [self->rrule repeatCount]) +
- jnFirst;
- until = [NSCalendarDate dateForJulianNumber:jnRuleLast];
- until = [until hour: [firStart hourOfDay]
- minute:[firStart minuteOfHour]
- second:[firStart secondOfMinute]];
- return until;
- }
- return [super lastInstanceStartDate];
-}
-
-@end /* iCalDailyRecurrenceCalculator */
-
-
-/*
- TODO: If BYDAY is specified, lastInstanceStartDate and recurrences will
- differ significantly!
-*/
-@implementation iCalWeeklyRecurrenceCalculator
-
-- (NSArray *)recurrenceRangesWithinCalendarDateRange:(NGCalendarDateRange *)_r {
- NSMutableArray *ranges;
- NSCalendarDate *firStart;
- long i, jnFirst, jnStart, jnEnd, startEndCount;
- unsigned interval, byDayMask;
-
- firStart = [self->firstRange startDate];
- jnFirst = [firStart julianNumber];
- jnEnd = [[_r endDate] julianNumber];
-
- if (jnFirst > jnEnd)
- return nil;
-
- jnStart = [[_r startDate] julianNumber];
- interval = [self->rrule repeatInterval];
-
- /* if rule is bound, check the bounds */
- if (![self->rrule isInfinite]) {
- NSCalendarDate *until;
- long jnRuleLast;
-
- until = [self->rrule untilDate];
- if (until) {
- if ([until compare:[_r startDate]] == NSOrderedAscending)
- return nil;
- jnRuleLast = [until julianNumber];
- }
- else {
- jnRuleLast = (interval * [self->rrule repeatCount] * 7)
- + jnFirst;
- if (jnRuleLast < jnStart)
- return nil;
- }
- /* jnStart < jnRuleLast < jnEnd ? */
- if (jnEnd > jnRuleLast)
- jnEnd = jnRuleLast;
- }
-
- startEndCount = (jnEnd - jnStart) + 1;
- ranges = [NSMutableArray arrayWithCapacity:startEndCount];
- byDayMask = [self->rrule byDayMask];
- if (!byDayMask) {
- for (i = 0 ; i < startEndCount; i++) {
- long jnCurrent;
-
- jnCurrent = jnStart + i;
- if (jnCurrent >= jnFirst) {
- long jnDiff;
-
- jnDiff = jnCurrent - jnFirst; /* difference in days */
- if ((jnDiff % (interval * 7)) == 0) {
- NSCalendarDate *start, *end;
- NGCalendarDateRange *r;
-
- start = [NSCalendarDate dateForJulianNumber:jnCurrent];
- [start setTimeZone:[firStart timeZone]];
- start = [start hour: [firStart hourOfDay]
- minute:[firStart minuteOfHour]
- second:[firStart secondOfMinute]];
- end = [start addTimeInterval:[self->firstRange duration]];
- r = [NGCalendarDateRange calendarDateRangeWithStartDate:start
- endDate:end];
- if ([_r containsDateRange:r])
- [ranges addObject:r];
- }
- }
- }
- }
- else {
- long jnFirstWeekStart, weekStartOffset;
-
- /* calculate jnFirst's week start - this depends on our setting of week
- start */
- weekStartOffset = [self offsetFromSundayForJulianNumber:jnFirst] -
- [self offsetFromSundayForCurrentWeekStart];
-
- jnFirstWeekStart = jnFirst - weekStartOffset;
-
- for (i = 0 ; i < startEndCount; i++) {
- long jnCurrent;
-
- jnCurrent = jnStart + i;
- if (jnCurrent >= jnFirst) {
- long jnDiff;
-
- /* we need to calculate a difference in weeks */
- jnDiff = (jnCurrent - jnFirstWeekStart) % 7;
- if ((jnDiff % interval) == 0) {
- BOOL isRecurrence = NO;
-
- if (jnCurrent == jnFirst) {
- isRecurrence = YES;
- }
- else {
- iCalWeekDay weekDay;
-
- weekDay = [self weekDayForJulianNumber:jnCurrent];
- isRecurrence = (weekDay & [self->rrule byDayMask]) ? YES : NO;
- }
- if (isRecurrence) {
- NSCalendarDate *start, *end;
- NGCalendarDateRange *r;
-
- start = [NSCalendarDate dateForJulianNumber:jnCurrent];
- [start setTimeZone:[firStart timeZone]];
- start = [start hour: [firStart hourOfDay]
- minute:[firStart minuteOfHour]
- second:[firStart secondOfMinute]];
- end = [start addTimeInterval:[self->firstRange duration]];
- r = [NGCalendarDateRange calendarDateRangeWithStartDate:start
- endDate:end];
- if ([_r containsDateRange:r])
- [ranges addObject:r];
- }
- }
- }
- }
- }
- return ranges;
-}
-
-- (NSCalendarDate *)lastInstanceStartDate {
- if ([self->rrule repeatCount] > 0) {
- long jnFirst, jnRuleLast;
- NSCalendarDate *firStart, *until;
-
- firStart = [self->firstRange startDate];
- jnFirst = [firStart julianNumber];
- jnRuleLast = ([self->rrule repeatInterval] *
- [self->rrule repeatCount] * 7) +
- jnFirst;
- until = [NSCalendarDate dateForJulianNumber:jnRuleLast];
- until = [until hour: [firStart hourOfDay]
- minute:[firStart minuteOfHour]
- second:[firStart secondOfMinute]];
- return until;
- }
- return [super lastInstanceStartDate];
-}
-
-@end /* iCalWeeklyRecurrenceCalculator */
-
-@implementation iCalMonthlyRecurrenceCalculator
-
-- (NSArray *)recurrenceRangesWithinCalendarDateRange:(NGCalendarDateRange *)_r {
- NSMutableArray *ranges;
- NSCalendarDate *firStart, *rStart, *rEnd, *until;
- unsigned i, count, interval;
- int diff;
-
- firStart = [self->firstRange startDate];
- rStart = [_r startDate];
- rEnd = [_r endDate];
- interval = [self->rrule repeatInterval];
- until = [self lastInstanceStartDate];
-
- if (until) {
- if ([until compare:rStart] == NSOrderedAscending)
- return nil;
- if ([until compare:rEnd] == NSOrderedDescending)
- rEnd = until;
- }
-
- diff = [firStart monthsBetweenDate:rStart];
- if ((diff != 0) && [rStart compare:firStart] == NSOrderedAscending)
- diff = -diff;
-
- count = [rStart monthsBetweenDate:rEnd] + 1;
- ranges = [NSMutableArray arrayWithCapacity:count];
- for (i = 0 ; i < count; i++) {
- int test;
-
- test = diff + i;
- if ((test >= 0) && (test % interval) == 0) {
- NSCalendarDate *start, *end;
- NGCalendarDateRange *r;
-
- 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];
- if ([_r containsDateRange:r])
- [ranges addObject:r];
- }
- }
- return ranges;
-}
-
-- (NSCalendarDate *)lastInstanceStartDate {
- if ([self->rrule repeatCount] > 0) {
- NSCalendarDate *until;
- unsigned months, interval;
-
- interval = [self->rrule repeatInterval];
- months = [self->rrule repeatCount] * interval;
- until = [[self->firstRange startDate] dateByAddingYears:0
- months:months
- days:0];
- return until;
- }
- return [super lastInstanceStartDate];
-}
-
-@end /* iCalMonthlyRecurrenceCalculator */
-
-@implementation iCalYearlyRecurrenceCalculator
-
-- (NSArray *)recurrenceRangesWithinCalendarDateRange:(NGCalendarDateRange *)_r {
- NSMutableArray *ranges;
- NSCalendarDate *firStart, *rStart, *rEnd, *until;
- unsigned i, count, interval;
- int diff;
-
- firStart = [self->firstRange startDate];
- rStart = [_r startDate];
- rEnd = [_r endDate];
- interval = [self->rrule repeatInterval];
- until = [self lastInstanceStartDate];
-
- if (until) {
- if ([until compare:rStart] == NSOrderedAscending)
- return nil;
- if ([until compare:rEnd] == NSOrderedDescending)
- rEnd = until;
- }
-
- diff = [firStart yearsBetweenDate:rStart];
- if ((diff != 0) && [rStart compare:firStart] == NSOrderedAscending)
- diff = -diff;
-
- count = [rStart yearsBetweenDate:rEnd] + 1;
- ranges = [NSMutableArray arrayWithCapacity:count];
- for (i = 0 ; i < count; i++) {
- int test;
-
- test = diff + i;
- if ((test >= 0) && (test % interval) == 0) {
- NSCalendarDate *start, *end;
- NGCalendarDateRange *r;
-
- 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];
- if ([_r containsDateRange:r])
- [ranges addObject:r];
- }
- }
- return ranges;
-}
-
-- (NSCalendarDate *)lastInstanceStartDate {
- if ([self->rrule repeatCount] > 0) {
- NSCalendarDate *until;
- unsigned years, interval;
-
- interval = [self->rrule repeatInterval];
- years = [self->rrule repeatCount] * interval;
- until = [[self->firstRange startDate] dateByAddingYears:years
- months:0
- days:0];
- return until;
- }
- return [super lastInstanceStartDate];
-}
-
-@end /* iCalYearlyRecurrenceCalculator */