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 #import <NGExtensions/NSCalendarDate+misc.h>
24 #import "iCalRecurrenceCalculator.h"
26 @interface iCalWeeklyRecurrenceCalculator : iCalRecurrenceCalculator
29 #import <NGExtensions/NGCalendarDateRange.h>
30 #import "iCalRecurrenceRule.h"
31 #import "NSCalendarDate+ICal.h"
33 @interface iCalRecurrenceCalculator (PrivateAPI)
35 - (NSCalendarDate *)lastInstanceStartDate;
37 - (unsigned)offsetFromSundayForJulianNumber:(long)_jn;
38 - (unsigned)offsetFromSundayForWeekDay:(iCalWeekDay)_weekDay;
39 - (unsigned)offsetFromSundayForCurrentWeekStart;
41 - (iCalWeekDay)weekDayForJulianNumber:(long)_jn;
46 TODO: If BYDAY is specified, lastInstanceStartDate and recurrences will
49 @implementation iCalWeeklyRecurrenceCalculator
51 - (NSArray *)recurrenceRangesWithinCalendarDateRange:(NGCalendarDateRange *)_r {
52 NSMutableArray *ranges;
53 NSCalendarDate *firStart;
54 long i, jnFirst, jnStart, jnEnd, startEndCount;
55 unsigned interval, byDayMask;
57 firStart = [self->firstRange startDate];
58 jnFirst = [firStart julianNumber];
59 jnEnd = [[_r endDate] julianNumber];
64 jnStart = [[_r startDate] julianNumber];
65 interval = [self->rrule repeatInterval];
67 /* if rule is bound, check the bounds */
68 if (![self->rrule isInfinite]) {
69 NSCalendarDate *until;
72 until = [self->rrule untilDate];
74 if ([until compare:[_r startDate]] == NSOrderedAscending)
76 jnRuleLast = [until julianNumber];
79 jnRuleLast = (interval * [self->rrule repeatCount] * 7)
81 if (jnRuleLast < jnStart)
84 /* jnStart < jnRuleLast < jnEnd ? */
85 if (jnEnd > jnRuleLast)
89 startEndCount = (jnEnd - jnStart) + 1;
90 ranges = [NSMutableArray arrayWithCapacity:startEndCount];
91 byDayMask = [self->rrule byDayMask];
93 for (i = 0 ; i < startEndCount; i++) {
96 jnCurrent = jnStart + i;
97 if (jnCurrent >= jnFirst) {
100 jnDiff = jnCurrent - jnFirst; /* difference in days */
101 if ((jnDiff % (interval * 7)) == 0) {
102 NSCalendarDate *start, *end;
103 NGCalendarDateRange *r;
105 start = [NSCalendarDate dateForJulianNumber:jnCurrent];
106 [start setTimeZone:[firStart timeZone]];
107 start = [start hour: [firStart hourOfDay]
108 minute:[firStart minuteOfHour]
109 second:[firStart secondOfMinute]];
110 end = [start addTimeInterval:[self->firstRange duration]];
111 r = [NGCalendarDateRange calendarDateRangeWithStartDate:start
113 if ([_r containsDateRange:r])
114 [ranges addObject:r];
120 long jnFirstWeekStart, weekStartOffset;
122 /* calculate jnFirst's week start - this depends on our setting of week
124 weekStartOffset = [self offsetFromSundayForJulianNumber:jnFirst] -
125 [self offsetFromSundayForCurrentWeekStart];
127 jnFirstWeekStart = jnFirst - weekStartOffset;
129 for (i = 0 ; i < startEndCount; i++) {
132 jnCurrent = jnStart + i;
133 if (jnCurrent >= jnFirst) {
136 /* we need to calculate a difference in weeks */
137 jnDiff = (jnCurrent - jnFirstWeekStart) % 7;
138 if ((jnDiff % interval) == 0) {
139 BOOL isRecurrence = NO;
141 if (jnCurrent == jnFirst) {
147 weekDay = [self weekDayForJulianNumber:jnCurrent];
148 isRecurrence = (weekDay & [self->rrule byDayMask]) ? YES : NO;
151 NSCalendarDate *start, *end;
152 NGCalendarDateRange *r;
154 start = [NSCalendarDate dateForJulianNumber:jnCurrent];
155 [start setTimeZone:[firStart timeZone]];
156 start = [start hour: [firStart hourOfDay]
157 minute:[firStart minuteOfHour]
158 second:[firStart secondOfMinute]];
159 end = [start addTimeInterval:[self->firstRange duration]];
160 r = [NGCalendarDateRange calendarDateRangeWithStartDate:start
162 if ([_r containsDateRange:r])
163 [ranges addObject:r];
172 - (NSCalendarDate *)lastInstanceStartDate {
173 if ([self->rrule repeatCount] > 0) {
174 long jnFirst, jnRuleLast;
175 NSCalendarDate *firStart, *until;
177 firStart = [self->firstRange startDate];
178 jnFirst = [firStart julianNumber];
179 jnRuleLast = ([self->rrule repeatInterval] *
180 [self->rrule repeatCount] * 7) +
182 until = [NSCalendarDate dateForJulianNumber:jnRuleLast];
183 until = [until hour: [firStart hourOfDay]
184 minute:[firStart minuteOfHour]
185 second:[firStart secondOfMinute]];
188 return [super lastInstanceStartDate];
191 @end /* iCalWeeklyRecurrenceCalculator */