]> err.no Git - sope/blob - sope-ical/NGiCal/iCalRepeatableEntityObject.m
48ab00cc2f102f49d1f05d4555608fb19ab5469a
[sope] / sope-ical / NGiCal / iCalRepeatableEntityObject.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 "iCalRepeatableEntityObject.h"
23 #include <NGExtensions/NGCalendarDateRange.h>
24 #include "iCalRecurrenceRule.h"
25 #include "iCalRecurrenceCalculator.h"
26 #include "common.h"
27
28 @implementation iCalRepeatableEntityObject
29
30 - (void)dealloc {
31   [self->rRules  release];
32   [self->exRules release];
33   [self->exDates release];
34   [super dealloc];
35 }
36
37 /* Accessors */
38
39 - (void)removeAllRecurrenceRules {
40   [self->rRules removeAllObjects];
41 }
42 - (void)addToRecurrenceRules:(id)_rrule {
43   if (_rrule == nil) return;
44   if (self->rRules == nil)
45     self->rRules = [[NSMutableArray alloc] initWithCapacity:1];
46   [self->rRules addObject:_rrule];
47 }
48 - (void)setRecurrenceRules:(NSArray *)_rrules {
49   if (_rrules == self->rRules)
50     return;
51   [self->rRules release];
52   self->rRules = [_rrules mutableCopy];
53 }
54 - (BOOL)hasRecurrenceRules {
55   return [self->rRules count] > 0 ? YES : NO;
56 }
57 - (NSArray *)recurrenceRules {
58   return self->rRules;
59 }
60
61 - (void)removeAllExceptionRules {
62   [self->exRules removeAllObjects];
63 }
64 - (void)addToExceptionRules:(id)_rrule {
65   if (_rrule == nil) return;
66   if (self->exRules == nil)
67     self->exRules = [[NSMutableArray alloc] initWithCapacity:1];
68   [self->exRules addObject:_rrule];
69 }
70 - (void)setExceptionRules:(NSArray *)_rrules {
71   if (_rrules == self->exRules)
72     return;
73   [self->exRules release];
74   self->exRules = [_rrules mutableCopy];
75 }
76 - (BOOL)hasExceptionRules {
77   return [self->exRules count] > 0 ? YES : NO;
78 }
79 - (NSArray *)exceptionRules {
80   return self->exRules;
81 }
82
83 - (void)removeAllExceptionDates {
84   [self->exDates removeAllObjects];
85 }
86 - (void)setExceptionDates:(NSArray *)_exDates {
87   if (_exDates == self->exDates)
88     return;
89   [self->exDates release];
90   self->exDates = [_exDates mutableCopy];
91 }
92 - (void)addToExceptionDates:(id)_date {
93   if (_date == nil) return;
94   if (self->exDates == nil)
95     self->exDates = [[NSMutableArray alloc] initWithCapacity:4];
96   [self->exDates addObject:_date];
97 }
98 - (BOOL)hasExceptionDates {
99   return [self->exDates count] > 0 ? YES : NO;
100 }
101 - (NSArray *)exceptionDates {
102   return self->exDates;
103 }
104
105 /* Convenience */
106
107 - (BOOL)isRecurrent {
108   return [self hasRecurrenceRules] ? YES : NO;
109 }
110
111 /* Matching */
112
113 - (BOOL)isWithinCalendarDateRange:(NGCalendarDateRange *)_range
114   firstInstanceCalendarDateRange:(NGCalendarDateRange *)_fir
115 {
116   NSArray *ranges;
117   
118   ranges = [self recurrenceRangesWithinCalendarDateRange:_range
119                  firstInstanceCalendarDateRange:_fir];
120   return [ranges count] > 0;
121 }
122
123 - (NSArray *)recurrenceRangesWithinCalendarDateRange:(NGCalendarDateRange *)_r
124   firstInstanceCalendarDateRange:(NGCalendarDateRange *)_fir
125 {
126   iCalRecurrenceRule       *rule;
127   iCalRecurrenceCalculator *calc;
128   NSMutableArray           *ranges;
129   unsigned                 i, count, rCount;
130
131   ranges = [NSMutableArray array];
132   count  = [self->rRules count];
133   for (i = 0; i < count; i++) {
134     NSArray *rs;
135
136     rule = [self->rRules objectAtIndex:i];
137     calc = [iCalRecurrenceCalculator recurrenceCalculatorForRecurrenceRule:rule
138                                      withFirstInstanceCalendarDateRange:_fir];
139     rs   = [calc recurrenceRangesWithinCalendarDateRange:_r];
140     [ranges addObjectsFromArray:rs];
141   }
142   
143   if (![ranges count])
144     return nil;
145
146   /* test if any exceptions do match */
147   count = [self->exRules count];
148   for (i = 0; i < count; i++) {
149     NSArray *rs;
150
151     rule = [self->exRules objectAtIndex:i];
152     calc = [iCalRecurrenceCalculator recurrenceCalculatorForRecurrenceRule:rule
153                                      withFirstInstanceCalendarDateRange:_fir];
154     rs   = [calc recurrenceRangesWithinCalendarDateRange:_r];
155     [ranges removeObjectsInArray:rs];
156   }
157
158   if (![ranges count])
159     return nil;
160
161   /* exception dates are also possible */
162   rCount = [ranges count];
163   count  = [self->exDates count];
164   for (i = 0; i < count; i++) {
165     NSCalendarDate      *exDate;
166     NGCalendarDateRange *r;
167     unsigned            k;
168
169     exDate = [self->exDates objectAtIndex:i];
170     for (k = 0; k < rCount; k++) {
171       r = [ranges objectAtIndex:(rCount - k) - 1];
172       if ([r containsDate:exDate]) {
173         [ranges removeObjectAtIndex:k];
174       }
175     }
176   }
177   return ranges;
178 }
179
180
181 /* this is the outmost bound possible, not necessarily the real last date */
182 - (NSCalendarDate *)lastPossibleRecurrenceStartDateUsingFirstInstanceCalendarDateRange:(NGCalendarDateRange *)_r
183 {
184   NSCalendarDate *date;
185   unsigned       i, count;
186   
187   count = [self->rRules count];
188   if (!count)
189     return nil;
190
191   date  = nil;
192   for (i = 0; i < count; i++) {
193     iCalRecurrenceRule       *rule;
194     iCalRecurrenceCalculator *calc;
195     NSCalendarDate           *rdate;
196
197     rule = [self->rRules objectAtIndex:i];
198     if ([rule isInfinite])
199       return nil; /* rule is not bound, hence no limit */
200     calc  = [iCalRecurrenceCalculator recurrenceCalculatorForRecurrenceRule:rule
201                                       withFirstInstanceCalendarDateRange:_r];
202     rdate = [[calc lastInstanceCalendarDateRange] startDate];
203     if (date == nil || [date compare:rdate] == NSOrderedAscending)
204       date = rdate;
205   }
206   return date;
207 }
208
209 @end