]> err.no Git - scalable-opengroupware.org/blob - SoObjects/Appointments/SOGoGroupAppointmentFolder.m
moved SOGo files up
[scalable-opengroupware.org] / SoObjects / Appointments / SOGoGroupAppointmentFolder.m
1 /*
2   Copyright (C) 2004-2005 SKYRIX Software AG
3
4   This file is part of OpenGroupware.org.
5
6   OGo 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   OGo 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 OGo; 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 "SOGoGroupAppointmentFolder.h"
23 #include "common.h"
24
25 @implementation SOGoGroupAppointmentFolder
26
27 + (int)version {
28   return [super version] + 0 /* v1 */;
29 }
30 + (void)initialize {
31   NSAssert2([super version] == 1,
32             @"invalid superclass (%@) version %i !",
33             NSStringFromClass([self superclass]), [super version]);
34 }
35
36 - (void)dealloc {
37   [self->uidToFolder release];
38   [super dealloc];
39 }
40
41 /* looking up shared objects */
42
43 - (SOGoGroupsFolder *)lookupGroupsFolder {
44   return [[self container] lookupGroupsFolder];
45 }
46
47 /* selection */
48
49 - (NSArray *)calendarUIDs {
50   return [[self container] valueForKey:@"uids"];
51 }
52
53 /* folders */
54
55 - (void)resetFolderCaches {
56   [self->uidToFolder release]; self->uidToFolder = nil;
57 }
58
59 - (SOGoAppointmentFolder *)folderForUID:(NSString *)_uid {
60   if (self->uidToFolder == nil) {
61     // TODO: can we trigger a fetch?
62     [self errorWithFormat:
63             @"called -folderForUID method before fetchCoreInfos .."];
64     return nil;
65   }
66   
67   return [self->uidToFolder objectForKey:_uid];
68 }
69
70 /* merging */
71
72 - (BOOL)doesRecord:(NSDictionary *)_rec conflictWith:(NSDictionary *)_other {
73   if (_rec == _other) 
74     return NO;
75   if ([_rec isEqual:_other])
76     return NO;
77   
78   return YES;
79 }
80
81 - (NSDictionary *)_registerConflictingRecord:(NSDictionary *)_other
82   inRecord:(NSDictionary *)_record
83 {
84   NSMutableArray *conflicts;
85   
86   if (_record == nil) return _other;
87   if (_other  == nil) return _record;
88   
89   if ((conflicts = [_record objectForKey:@"conflicts"]) == nil) {
90     NSMutableDictionary *md;
91     
92     md = [[_record mutableCopy] autorelease];
93     conflicts = [NSMutableArray arrayWithCapacity:4];
94     [md setObject:conflicts forKey:@"conflicts"];
95     _record = md;
96   }
97   [conflicts addObject:_other];
98   return _record;
99 }
100
101 /* functionality */
102
103 - (SOGoAppointmentFolder *)calendarFolderForMemberFolder:(id)_folder {
104   SOGoAppointmentFolder *aptFolder;
105   
106   if (![_folder isNotNull])
107     return nil;
108   
109   aptFolder = [_folder lookupName:@"Calendar" inContext:nil acquire:NO];
110   if (![aptFolder isNotNull])
111     return nil;
112   
113   if (![aptFolder respondsToSelector:@selector(fetchCoreInfosFrom:to:)]) {
114     [self errorWithFormat:@"folder does not implemented required API: %@",
115             _folder];
116     return nil;
117   }
118   return aptFolder;
119 }
120
121 /* overridden */
122 - (NSArray *)fetchFields:(NSArray *)_fields
123   from:(NSCalendarDate *)_startDate
124   to:(NSCalendarDate *)_endDate 
125 {
126   NSArray             *folders;
127   NSMutableArray      *result;
128   NSMutableDictionary *uidToRecord;
129   unsigned            i, count;
130
131   if ((folders = [[self container] valueForKey:@"memberFolders"]) == nil) {
132     [self errorWithFormat:@"calendar container has no 'memberFolders'?!"];
133     return nil;
134   }
135   
136   [self resetFolderCaches];
137   
138   if ((count = [folders count]) == 0)
139     return [NSArray array];
140   
141   if (self->uidToFolder == nil)
142     self->uidToFolder = [[NSMutableDictionary alloc] initWithCapacity:7*count];
143   else
144     [self->uidToFolder removeAllObjects];
145   
146   uidToRecord = [NSMutableDictionary dictionaryWithCapacity:(7 * count)];
147   result      = [NSMutableArray arrayWithCapacity:(7 * count)];
148   for (i = 0; i < count; i++) {
149     SOGoAppointmentFolder *aptFolder;
150     id                    results;
151     NSDictionary          *record;
152
153     aptFolder = [self calendarFolderForMemberFolder:
154                         [folders objectAtIndex:i]];
155     if (![aptFolder isNotNull]) {
156       [self debugWithFormat:@"did not find a Calendar folder in folder: %@",
157               [folders objectAtIndex:i]];
158       continue;
159     }
160     
161     results = [aptFolder fetchFields:_fields
162                          from:_startDate
163                          to:_endDate];
164     if (![results isNotNull]) continue;
165     
166     results = [results objectEnumerator];
167     while ((record = [results nextObject])) {
168       NSString     *uid;
169       NSDictionary *existingRecord;
170       
171       uid = [record objectForKey:@"uid"];
172       if (![uid isNotNull]) {
173         [self warnWithFormat:@"record without uid: %@", result];
174         [result addObject:record];
175         continue;
176       }
177       
178       if ((existingRecord = [uidToRecord objectForKey:uid]) == nil) {
179         /* record not yet in result set */
180         [uidToRecord setObject:record forKey:uid];
181         [result addObject:record];
182         
183         [self->uidToFolder setObject:aptFolder forKey:uid];
184       }
185       else if ([self doesRecord:existingRecord conflictWith:record]) {
186         /* record already registered and it conflicts (diff values) */
187         NSDictionary *newRecord;
188         int idx;
189         
190         newRecord = [self _registerConflictingRecord:record 
191                           inRecord:existingRecord];
192         [uidToRecord setObject:newRecord forKey:uid];
193         
194         if ((idx = [result indexOfObject:existingRecord]) != NSNotFound)
195           [result replaceObjectAtIndex:idx withObject:newRecord];
196       }
197       else {
198         /* record already registered, but values in sync, nothing to do */
199       }
200     }
201   }
202   return result;
203 }
204
205
206 /* URL generation */
207
208 - (NSString *)baseURLForAptWithUID:(NSString *)_uid inContext:(id)_ctx {
209   /* Note: fetchCore must have been called before this works */
210   SOGoAppointmentFolder *folder;
211   
212   if ([_uid length] == 0) {
213     [self errorWithFormat:@"got invalid UID."];
214     return nil;
215   }
216   
217   if ((folder = [self folderForUID:_uid]) == nil) {
218     [self errorWithFormat:@"did not find a folder containing UID: '%@'",
219             _uid];
220     return nil;
221   }
222   if (![folder respondsToSelector:_cmd]) {
223     [self errorWithFormat:@"found folder cannot construct UID URLs: %@",
224             folder];
225     return nil;
226   }
227   
228   [self debugWithFormat:@"found ID %@ in folder: %@", _uid, folder];
229   
230   return [folder baseURLForAptWithUID:_uid inContext:_ctx];
231 }
232
233 @end /* SOGoGroupAppointmentFolder */