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