]> err.no Git - sope/blob - sope-ical/NGiCal/iCalRecurrenceCalculator.m
first sketch of recurrence rules and associated functionality
[sope] / sope-ical / NGiCal / iCalRecurrenceCalculator.m
1 /*
2  Copyright (C) 2004-2005 SKYRIX Software AG
3  
4  This file is part of SOPE.
5  
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
9  later version.
10  
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.
15  
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
19  02111-1307, USA.
20 */
21
22 #include "iCalRecurrenceCalculator.h"
23 #include <NGExtensions/NGCalendarDateRange.h>
24 #include "iCalRecurrenceRule.h"
25 #include "common.h"
26
27
28 /* class cluster */
29
30 @interface iCalDailyRecurrenceCalculator : iCalRecurrenceCalculator
31 {
32 }
33 - (unsigned)factor;
34 @end
35
36 @interface iCalWeeklyRecurrenceCalculator : iCalDailyRecurrenceCalculator
37 {
38 }
39 @end
40
41 @interface iCalMonthlyRecurrenceCalculator : iCalRecurrenceCalculator
42 {
43 }
44 @end
45
46 @interface iCalYearlyRecurrenceCalculator : iCalRecurrenceCalculator
47 {
48 }
49 @end
50
51 /* superclass */
52
53 @implementation iCalRecurrenceCalculator
54
55 static Class dailyCalcClass   = Nil;
56 static Class weeklyCalcClass  = Nil;
57 static Class monthlyCalcClass = Nil;
58 static Class yearlyCalcClass  = Nil;
59
60 + (void)initialize {
61   static BOOL didInit = NO;
62   
63   if (didInit) return;
64   didInit = YES;
65
66   dailyCalcClass   = [iCalDailyRecurrenceCalculator   class];
67   weeklyCalcClass  = [iCalWeeklyRecurrenceCalculator  class];
68   monthlyCalcClass = [iCalMonthlyRecurrenceCalculator class];
69   yearlyCalcClass  = [iCalYearlyRecurrenceCalculator  class];
70 }
71
72 + (id)recurrenceCalculatorForRecurrenceRule:(iCalRecurrenceRule *)_rrule
73          withFirstInstanceCalendarDateRange:(NGCalendarDateRange *)_range
74 {
75   return [[[self alloc] initWithRecurrenceRule:_rrule
76                         firstInstanceCalendarDateRange:_range] autorelease];
77 }
78
79 - (id)initWithRecurrenceRule:(iCalRecurrenceRule *)_rrule
80   firstInstanceCalendarDateRange:(NGCalendarDateRange *)_range
81 {
82   iCalRecurrenceFrequency freq;
83   Class calcClass = Nil;
84
85   freq = [_rrule frequency];
86   if (freq == iCalRecurrenceFrequenceDaily)
87     calcClass = dailyCalcClass;
88   else if (freq == iCalRecurrenceFrequenceWeekly)
89     calcClass = weeklyCalcClass;
90   else if (freq == iCalRecurrenceFrequenceMonthly)
91     calcClass = monthlyCalcClass;
92   else if (freq == iCalRecurrenceFrequenceYearly)
93     calcClass = yearlyCalcClass;
94
95   [self autorelease];
96   if (calcClass == Nil)
97     return nil;
98
99   self = [[calcClass alloc] init];
100   ASSIGN(self->rrule, _rrule);
101   ASSIGN(self->firstRange, _range);
102   return self;  
103 }
104
105
106 /* calculation */
107
108 - (NSArray *)recurrenceRangesWithinCalendarDateRange:(NGCalendarDateRange *)_r {
109   return nil; /* subclass responsibility */
110 }
111 - (BOOL)doesRecurrWithinCalendarDateRange:(NGCalendarDateRange *)_range {
112   return NO; /* subclass responsibility */
113 }
114
115 @end /* iCalRecurrenceCalculator */
116
117
118 /* ZNeK: NOTE
119 taeglich:
120 alle events
121 fuer all diese jeweils
122 differenz der julian numbers durch interval teilen, wenn ok, ...
123 */
124 @implementation iCalDailyRecurrenceCalculator
125
126 - (unsigned)factor {
127   return 1;
128 }
129
130 - (BOOL)doesRecurrWithinCalendarDateRange:(NGCalendarDateRange *)_range {
131   long     i, jnFirst, jnStart, jnEnd, startEndCount;
132   unsigned interval;
133
134   jnFirst  = [[self->firstRange startDate] julianNumber];
135   jnEnd    = [[_range endDate] julianNumber];
136
137   if (jnFirst > jnEnd)
138     return NO;
139
140   jnStart  = [[_range startDate] julianNumber];
141   interval = [self->rrule repeatInterval];
142
143   /* if rule is bound, check the bounds */
144   if (![self->rrule isInfinite]) {
145     NSCalendarDate *until;
146     long           jnRuleLast;
147
148     until = [self->rrule untilDate];
149     if (until) {
150       if ([until compare:[_range startDate]] == NSOrderedAscending)
151         return NO;
152       jnRuleLast = [until julianNumber];
153     }
154     else {
155       jnRuleLast = (interval * [self->rrule repeatCount] * [self factor])
156                    + jnFirst;
157       if (jnRuleLast < jnStart)
158         return NO;
159     }
160     /* jnStart < jnRuleLast < jnEnd ? */
161     if (jnEnd > jnRuleLast)
162       jnEnd = jnRuleLast;
163   }
164
165   startEndCount = (jnEnd - jnStart) + 1;
166   for (i = 0 ; i < startEndCount; i++) {
167     long jnTest;
168
169     jnTest = (jnStart + i) - jnFirst;
170     if ((jnTest % interval) == 0)
171       return YES;
172   }
173   return NO;
174 }
175
176 @end /* iCalDailyRecurrenceCalculator */
177
178 /*
179   ZNeK: NOTE
180   woechentlich:
181   wie taeglich, aber teilen durch interval*7
182 */
183 @implementation iCalWeeklyRecurrenceCalculator
184
185 - (unsigned)factor {
186   return 7;
187 }
188
189 @end /* iCalWeeklyRecurrenceCalculator */
190
191 /*
192   ZNeK: NOTE
193   monatlich:
194   monatlich: differenz der monate / interval
195   alle events mit korrektem tag.
196   dann differenz der monate durch interval teilen, wenn ok, ...
197   (diffrenz der monate = 12 * 'volle' jahre plus monate im start jahr und monate im ziel jahr
198  */
199 @implementation iCalMonthlyRecurrenceCalculator
200
201 - (BOOL)doesRecurrWithinCalendarDateRange:(NGCalendarDateRange *)_range {
202   return YES;
203 }
204
205 @end /* iCalMonthlyRecurrenceCalculator */
206
207 /*
208   ZNeK: NOTE
209   jaehrlich:
210   alle events mit dem korrekten tag und monat.
211   fuer all diese jeweils
212   differenz in jahren durch interval teilen, wenn ok, dann event fuer den tag.
213 */
214 @implementation iCalYearlyRecurrenceCalculator
215
216 - (BOOL)doesRecurrWithinCalendarDateRange:(NGCalendarDateRange *)_range {
217   return YES;
218 }
219
220 @end /* iCalYearlyRecurrenceCalculator */