2 Copyright (C) 2004-2005 SKYRIX Software AG
4 This file is part of SOPE.
6 SOPE is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with SOPE; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22 #include "iCalRecurrenceCalculator.h"
24 @interface iCalWeeklyRecurrenceCalculator : iCalRecurrenceCalculator
27 #include <NGExtensions/NGCalendarDateRange.h>
28 #include "iCalRecurrenceRule.h"
29 #include "NSCalendarDate+ICal.h"
32 @interface iCalRecurrenceCalculator (PrivateAPI)
34 - (NSCalendarDate *)lastInstanceStartDate;
36 - (unsigned)offsetFromSundayForJulianNumber:(long)_jn;
37 - (unsigned)offsetFromSundayForWeekDay:(iCalWeekDay)_weekDay;
38 - (unsigned)offsetFromSundayForCurrentWeekStart;
40 - (iCalWeekDay)weekDayForJulianNumber:(long)_jn;
45 TODO: If BYDAY is specified, lastInstanceStartDate and recurrences will
48 @implementation iCalWeeklyRecurrenceCalculator
50 - (NSArray *)recurrenceRangesWithinCalendarDateRange:(NGCalendarDateRange *)_r {
51 NSMutableArray *ranges;
52 NSCalendarDate *firStart;
53 long i, jnFirst, jnStart, jnEnd, startEndCount;
54 unsigned interval, byDayMask;
56 firStart = [self->firstRange startDate];
57 jnFirst = [firStart julianNumber];
58 jnEnd = [[_r endDate] julianNumber];
63 jnStart = [[_r startDate] julianNumber];
64 interval = [self->rrule repeatInterval];
66 /* if rule is bound, check the bounds */
67 if (![self->rrule isInfinite]) {
68 NSCalendarDate *until;
71 until = [self->rrule untilDate];
73 if ([until compare:[_r startDate]] == NSOrderedAscending)
75 jnRuleLast = [until julianNumber];
78 jnRuleLast = (interval * [self->rrule repeatCount] * 7)
80 if (jnRuleLast < jnStart)
83 /* jnStart < jnRuleLast < jnEnd ? */
84 if (jnEnd > jnRuleLast)
88 startEndCount = (jnEnd - jnStart) + 1;
89 ranges = [NSMutableArray arrayWithCapacity:startEndCount];
90 byDayMask = [self->rrule byDayMask];
92 for (i = 0 ; i < startEndCount; i++) {
95 jnCurrent = jnStart + i;
96 if (jnCurrent >= jnFirst) {
99 jnDiff = jnCurrent - jnFirst; /* difference in days */
100 if ((jnDiff % (interval * 7)) == 0) {
101 NSCalendarDate *start, *end;
102 NGCalendarDateRange *r;
104 start = [NSCalendarDate dateForJulianNumber:jnCurrent];
105 [start setTimeZone:[firStart timeZone]];
106 start = [start hour: [firStart hourOfDay]
107 minute:[firStart minuteOfHour]
108 second:[firStart secondOfMinute]];
109 end = [start addTimeInterval:[self->firstRange duration]];
110 r = [NGCalendarDateRange calendarDateRangeWithStartDate:start
112 if ([_r containsDateRange:r])
113 [ranges addObject:r];
119 long jnFirstWeekStart, weekStartOffset;
121 /* calculate jnFirst's week start - this depends on our setting of week
123 weekStartOffset = [self offsetFromSundayForJulianNumber:jnFirst] -
124 [self offsetFromSundayForCurrentWeekStart];
126 jnFirstWeekStart = jnFirst - weekStartOffset;
128 for (i = 0 ; i < startEndCount; i++) {
131 jnCurrent = jnStart + i;
132 if (jnCurrent >= jnFirst) {
135 /* we need to calculate a difference in weeks */
136 jnDiff = (jnCurrent - jnFirstWeekStart) % 7;
137 if ((jnDiff % interval) == 0) {
138 BOOL isRecurrence = NO;
140 if (jnCurrent == jnFirst) {
146 weekDay = [self weekDayForJulianNumber:jnCurrent];
147 isRecurrence = (weekDay & [self->rrule byDayMask]) ? YES : NO;
150 NSCalendarDate *start, *end;
151 NGCalendarDateRange *r;
153 start = [NSCalendarDate dateForJulianNumber:jnCurrent];
154 [start setTimeZone:[firStart timeZone]];
155 start = [start hour: [firStart hourOfDay]
156 minute:[firStart minuteOfHour]
157 second:[firStart secondOfMinute]];
158 end = [start addTimeInterval:[self->firstRange duration]];
159 r = [NGCalendarDateRange calendarDateRangeWithStartDate:start
161 if ([_r containsDateRange:r])
162 [ranges addObject:r];
171 - (NSCalendarDate *)lastInstanceStartDate {
172 if ([self->rrule repeatCount] > 0) {
173 long jnFirst, jnRuleLast;
174 NSCalendarDate *firStart, *until;
176 firStart = [self->firstRange startDate];
177 jnFirst = [firStart julianNumber];
178 jnRuleLast = ([self->rrule repeatInterval] *
179 [self->rrule repeatCount] * 7) +
181 until = [NSCalendarDate dateForJulianNumber:jnRuleLast];
182 until = [until hour: [firStart hourOfDay]
183 minute:[firStart minuteOfHour]
184 second:[firStart secondOfMinute]];
187 return [super lastInstanceStartDate];
190 @end /* iCalWeeklyRecurrenceCalculator */