2005-09-20 Helge Hess <helge.hess@opengroupware.org>
+ * iCalRecurrenceCalculator.m: moved cluster subclasses to own source
+ files (v4.5.63)
+
* iCalRecurrenceRule.m: added some parsing/gen support for BYDAY
(v4.5.62)
iCalRenderer.m \
iCalRecurrenceRule.m \
iCalRecurrenceCalculator.m \
+ iCalDailyRecurrenceCalculator.m \
+ iCalWeeklyRecurrenceCalculator.m\
+ iCalMonthlyRecurrenceCalculator.m \
+ iCalYearlyRecurrenceCalculator.m\
\
NGICalSaxHandler.m \
\
MAJOR_VERSION=4
MINOR_VERSION=5
-SUBMINOR_VERSION:=62
+SUBMINOR_VERSION:=63
# v4.5.40 requires NGExtensions v4.5.145
# v4.5.37 requires NGExtensions v4.5.140
--- /dev/null
+/*
+ Copyright (C) 2004-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#include "iCalRecurrenceCalculator.h"
+
+@interface iCalDailyRecurrenceCalculator : iCalRecurrenceCalculator
+@end
+
+#include <NGExtensions/NGCalendarDateRange.h>
+#include "iCalRecurrenceRule.h"
+#include "NSCalendarDate+ICal.h"
+#include "common.h"
+
+@interface iCalRecurrenceCalculator(PrivateAPI)
+- (NSCalendarDate *)lastInstanceStartDate;
+@end
+
+@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 */
--- /dev/null
+/*
+ Copyright (C) 2004-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#include "iCalRecurrenceCalculator.h"
+
+@interface iCalMonthlyRecurrenceCalculator : iCalRecurrenceCalculator
+@end
+
+#include <NGExtensions/NGCalendarDateRange.h>
+#include "iCalRecurrenceRule.h"
+#include "NSCalendarDate+ICal.h"
+#include "common.h"
+
+@interface iCalRecurrenceCalculator(PrivateAPI)
+- (NSCalendarDate *)lastInstanceStartDate;
+@end
+
+@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 */
/*
- Copyright (C) 2004-2005 SKYRIX Software AG
-
- This file is part of SOPE.
-
- SOPE is free software; you can redistribute it and/or modify it under
- the terms of the GNU Lesser General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any
- later version.
-
- SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
- License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with SOPE; see the file COPYING. If not, write to the
- Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA.
+ Copyright (C) 2004-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
*/
#include "iCalRecurrenceCalculator.h"
/* class cluster */
-@interface iCalDailyRecurrenceCalculator : iCalRecurrenceCalculator
-{
-}
-@end
-
-@interface iCalWeeklyRecurrenceCalculator : iCalRecurrenceCalculator
-{
-}
-@end
-
-@interface iCalMonthlyRecurrenceCalculator : iCalRecurrenceCalculator
-{
-}
-@end
-
-@interface iCalYearlyRecurrenceCalculator : iCalRecurrenceCalculator
-{
-}
-@end
/* Private */
NSCalendarDateClass = [NSCalendarDate class];
iCalRecurrenceRuleClass = [iCalRecurrenceRule class];
- dailyCalcClass = [iCalDailyRecurrenceCalculator class];
- weeklyCalcClass = [iCalWeeklyRecurrenceCalculator class];
- monthlyCalcClass = [iCalMonthlyRecurrenceCalculator class];
- yearlyCalcClass = [iCalYearlyRecurrenceCalculator class];
+ dailyCalcClass = NSClassFromString(@"iCalDailyRecurrenceCalculator");
+ weeklyCalcClass = NSClassFromString(@"iCalWeeklyRecurrenceCalculator");
+ monthlyCalcClass = NSClassFromString(@"iCalMonthlyRecurrenceCalculator");
+ yearlyCalcClass = NSClassFromString(@"iCalYearlyRecurrenceCalculator");
}
/* factory */
}
@end /* iCalRecurrenceCalculator */
-
-
-@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 */
--- /dev/null
+/*
+ Copyright (C) 2004-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#include "iCalRecurrenceCalculator.h"
+
+@interface iCalWeeklyRecurrenceCalculator : iCalRecurrenceCalculator
+@end
+
+#include <NGExtensions/NGCalendarDateRange.h>
+#include "iCalRecurrenceRule.h"
+#include "NSCalendarDate+ICal.h"
+#include "common.h"
+
+@interface iCalRecurrenceCalculator (PrivateAPI)
+
+- (NSCalendarDate *)lastInstanceStartDate;
+
+- (unsigned)offsetFromSundayForJulianNumber:(long)_jn;
+- (unsigned)offsetFromSundayForWeekDay:(iCalWeekDay)_weekDay;
+- (unsigned)offsetFromSundayForCurrentWeekStart;
+
+- (iCalWeekDay)weekDayForJulianNumber:(long)_jn;
+
+@end
+
+/*
+ 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 */
--- /dev/null
+/*
+ Copyright (C) 2004-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#include "iCalRecurrenceCalculator.h"
+
+@interface iCalYearlyRecurrenceCalculator : iCalRecurrenceCalculator
+@end
+
+#include <NGExtensions/NGCalendarDateRange.h>
+#include "iCalRecurrenceRule.h"
+#include "NSCalendarDate+ICal.h"
+#include "common.h"
+
+@interface iCalRecurrenceCalculator(PrivateAPI)
+- (NSCalendarDate *)lastInstanceStartDate;
+@end
+
+@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 */