]> err.no Git - scalable-opengroupware.org/blob - SOGo/UI/Scheduler/UIxAppointmentProposal.m
git-svn-id: http://svn.opengroupware.org/SOGo/trunk@258 d1b88da0-ebda-0310-925b-ed51d...
[scalable-opengroupware.org] / SOGo / UI / Scheduler / UIxAppointmentProposal.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: UIxAppointmentEditor.m 181 2004-08-11 15:13:25Z helge $
22
23 #include <SOGoUI/UIxComponent.h>
24
25 @interface UIxAppointmentProposal : UIxComponent
26 {
27   id item;
28   id currentDay;
29
30   /* individual values */
31   id startDateHour;
32   id startDateMinute;
33   id endDateHour;
34   id endDateMinute;
35
36   id startDateDay;
37   id startDateMonth;
38   id startDateYear;
39   id endDateDay;
40   id endDateMonth;
41   id endDateYear;
42   
43   NSArray        *participants; /* array of iCalPerson's */
44   NSArray        *resources;    /* array of iCalPerson's */
45   id             duration;
46   
47   NSArray *blockedRanges;
48 }
49
50 @end
51
52 #include <SoObjects/Appointments/SOGoAppointmentFolder.h>
53 #include <NGExtensions/NGCalendarDateRange.h>
54 #include "common.h"
55
56 @implementation UIxAppointmentProposal
57
58 - (void)dealloc {
59   [self->blockedRanges   release];
60
61   [self->startDateHour   release];
62   [self->startDateMinute release];
63   [self->startDateDay    release];
64   [self->startDateMonth  release];
65   [self->startDateYear   release];
66
67   [self->endDateHour     release];
68   [self->endDateMinute   release];
69   [self->endDateDay      release];
70   [self->endDateMonth    release];
71   [self->endDateYear     release];
72   [self->duration        release];
73     
74   [self->participants    release];
75   [self->resources       release];
76   [super dealloc];
77 }
78
79 /* notifications */
80
81 - (void)sleep {
82   [self->currentDay release]; self->currentDay = nil;
83   [self->item       release]; self->item       = nil;
84   [super sleep];
85 }
86
87 /* accessors */
88
89 - (void)setItem:(id)_item {
90   ASSIGN(self->item, _item);
91 }
92 - (id)item {
93   return self->item;
94 }
95
96 - (void)setStartDateHour:(id)_startDateHour {
97   ASSIGN(self->startDateHour, _startDateHour);
98 }
99 - (id)startDateHour {
100   return self->startDateHour;
101 }
102 - (void)setStartDateMinute:(id)_startDateMinute {
103   ASSIGN(self->startDateMinute, _startDateMinute);
104 }
105 - (id)startDateMinute {
106   return self->startDateMinute;
107 }
108 - (void)setStartDateDay:(id)_startDateDay {
109   ASSIGN(self->startDateDay, _startDateDay);
110 }
111 - (id)startDateDay {
112   return self->startDateDay;
113 }
114 - (void)setStartDateMonth:(id)_startDateMonth {
115   ASSIGN(self->startDateMonth, _startDateMonth);
116 }
117 - (id)startDateMonth {
118   return self->startDateMonth;
119 }
120 - (void)setStartDateYear:(id)_startDateYear {
121   ASSIGN(self->startDateYear, _startDateYear);
122 }
123 - (id)startDateYear {
124   return self->startDateYear;
125 }
126 - (void)setEndDateHour:(id)_endDateHour {
127   ASSIGN(self->endDateHour, _endDateHour);
128 }
129 - (id)endDateHour {
130   return self->endDateHour;
131 }
132 - (void)setEndDateMinute:(id)_endDateMinute {
133   ASSIGN(self->endDateMinute, _endDateMinute);
134 }
135 - (id)endDateMinute {
136   return self->endDateMinute;
137 }
138 - (void)setEndDateDay:(id)_endDateDay {
139   ASSIGN(self->endDateDay, _endDateDay);
140 }
141 - (id)endDateDay {
142   return self->endDateDay;
143 }
144 - (void)setEndDateMonth:(id)_endDateMonth {
145   ASSIGN(self->endDateMonth, _endDateMonth);
146 }
147 - (id)endDateMonth {
148   return self->endDateMonth;
149 }
150 - (void)setEndDateYear:(id)_endDateYear {
151   ASSIGN(self->endDateYear, _endDateYear);
152 }
153 - (id)endDateYear {
154   return self->endDateYear;
155 }
156
157 - (void)setStartDate:(NSCalendarDate *)_date {
158   [self setStartDateHour:[NSNumber numberWithInt:[_date hourOfDay]]];
159   [self setStartDateMinute:[NSNumber numberWithInt:[_date minuteOfHour]]];
160   [self setStartDateDay:[NSNumber numberWithInt:[_date dayOfMonth]]];
161   [self setStartDateMonth:[NSNumber numberWithInt:[_date monthOfYear]]];
162   [self setStartDateYear:[NSNumber numberWithInt:[_date yearOfCommonEra]]];
163 }
164 - (NSCalendarDate *)startDate {
165   return [NSCalendarDate dateWithYear:[[self startDateYear] intValue]
166                          month:[[self startDateMonth] intValue]
167                          day:[[self startDateDay] intValue]
168                          hour:[[self startDateHour] intValue]
169                          minute:[[self startDateMinute] intValue]
170                          second:0
171                          timeZone:[self viewTimeZone]];
172 }
173 - (void)setEndDate:(NSCalendarDate *)_date {
174   [self setEndDateHour:[NSNumber numberWithInt:[_date hourOfDay]]];
175   [self setEndDateMinute:[NSNumber numberWithInt:[_date minuteOfHour]]];
176   [self setEndDateDay:[NSNumber numberWithInt:[_date dayOfMonth]]];
177   [self setEndDateMonth:[NSNumber numberWithInt:[_date monthOfYear]]];
178   [self setEndDateYear:[NSNumber numberWithInt:[_date yearOfCommonEra]]];
179 }
180 - (NSCalendarDate *)endDate {
181   return [NSCalendarDate dateWithYear:[[self endDateYear] intValue]
182                          month:[[self endDateMonth] intValue]
183                          day:[[self endDateDay] intValue]
184                          hour:[[self endDateHour] intValue]
185                          minute:[[self endDateMinute] intValue]
186                          second:59
187                          timeZone:[self viewTimeZone]];
188 }
189
190 - (void)setDuration:(id)_duration {
191   ASSIGN(self->duration, _duration);
192 }
193 - (id)duration {
194   return self->duration;
195 }
196 - (int)durationInMinutes {
197   return [[self duration] intValue];
198 }
199 - (NSTimeInterval)durationAsTimeInterval {
200   return [self durationInMinutes] * 60;
201 }
202
203 - (NSString *)itemDurationText {
204   // TODO: use a formatter
205   // TODO: localize
206   switch ([[self item] intValue]) {
207   case  30: return @"30 minutes";
208   case  60: return @"1 hour";
209   case 120: return @"2 hours";
210   case 240: return @"4 hours";
211   case 480: return @"8 hours";
212   default:
213     return [NSString stringWithFormat:@"%@ minutes", [self item]];
214   }
215 }
216
217 - (void)setParticipants:(NSArray *)_parts {
218   ASSIGN(self->participants, _parts);
219 }
220 - (NSArray *)participants {
221   return self->participants;
222 }
223 - (void)setResources:(NSArray *)_res {
224   ASSIGN(self->resources, _res);
225 }
226 - (NSArray *)resources {
227   return self->resources;
228 }
229
230 - (NSArray *)attendees {
231   NSArray *a, *b;
232   
233   a = [self participants];
234   b = [self resources];
235   if ([b count] == 0) return a;
236   if ([a count] == 0) return b;
237   return [a arrayByAddingObjectsFromArray:b];
238 }
239
240 - (void)setCurrentDay:(id)_day {
241   ASSIGN(self->currentDay, _day);
242 }
243 - (id)currentDay {
244   return self->currentDay;
245 }
246
247 - (NSArray *)hours {
248   // TODO: from 'earliest start' to 'latest endtime'
249   unsigned lStartHour = 9, lEndHour = 17, i;
250   NSMutableArray *ma;
251   
252   lStartHour = [[self startDateHour] intValue];
253   lEndHour   = [[self endDateHour]   intValue];
254   if (lStartHour < 1) lStartHour = 1;
255   if (lEndHour < lStartHour) lEndHour = lStartHour + 1;
256   
257   ma = [NSMutableArray arrayWithCapacity:lEndHour - lStartHour + 2];
258   for (i = lStartHour; i <= lEndHour; i++)
259     [ma addObject:[NSNumber numberWithInt:i]];
260   return ma;
261 }
262
263 - (NSArray *)days {
264   // TODO: from startdate to enddate
265   NSMutableArray *ma;
266   NSCalendarDate *base, *stop, *current;
267   
268   base = [NSCalendarDate dateWithYear:[[self startDateYear] intValue]
269                          month:[[self startDateMonth] intValue]
270                          day:[[self startDateDay] intValue]
271                          hour:12 minute:0 second:0
272                          timeZone:[self viewTimeZone]];
273   stop = [NSCalendarDate dateWithYear:[[self endDateYear] intValue]
274                          month:[[self endDateMonth] intValue]
275                          day:[[self endDateDay] intValue]
276                          hour:12 minute:0 second:0
277                          timeZone:[self viewTimeZone]];
278   
279   ma = [NSMutableArray arrayWithCapacity:16];
280   
281   current = base;
282   while ([current compare:stop] != NSOrderedDescending) {
283     [ma addObject:current];
284     
285     /* Note: remember the timezone behaviour of the method below! */
286     current = [current dateByAddingYears:0 months:0 days:1];
287   }
288   return ma;
289 }
290
291 - (NSArray *)durationSteps {
292   // TODO: make configurable
293   return [NSArray arrayWithObjects:
294                     @"30", @"60", @"120", @"240", @"480", nil];
295 }
296
297 /* slots */
298
299 - (BOOL)isRangeGreen:(NGCalendarDateRange *)_range {
300   unsigned idx;
301
302   idx = [self->blockedRanges indexOfFirstIntersectingDateRange:_range];
303   if (idx != NSNotFound)
304     return NO;
305   
306   return YES;
307 }
308
309 - (BOOL)isSlotRangeGreen:(NGCalendarDateRange *)_slotRange {
310   NGCalendarDateRange *aptRange;
311   NSCalendarDate *aptStartDate, *aptEndDate;
312
313   if (_slotRange == nil)
314     return NO;
315   
316   /* calculate the interval requested by the user (can be larger) */
317   
318   aptStartDate = [_slotRange startDate];
319   aptEndDate   = [[NSCalendarDate alloc] initWithTimeIntervalSince1970:
320                                            [aptStartDate timeIntervalSince1970]
321                                          + [self durationAsTimeInterval]];
322   [aptStartDate setTimeZone:[self viewTimeZone]];
323   [aptEndDate   setTimeZone:[self viewTimeZone]];
324   aptRange = [NGCalendarDateRange calendarDateRangeWithStartDate:aptStartDate
325                                   endDate:aptEndDate];
326   [aptEndDate release]; aptEndDate = nil;
327   
328   return [self isRangeGreen:aptRange];
329 }
330
331 - (BOOL)isFirstHalfGreen {
332   /* currentday is the date, self->item the hour */
333   NSCalendarDate *from, *to;
334   NGCalendarDateRange *range;
335
336   from  = [self->currentDay hour:[[self item] intValue] minute:0];
337   to    = [self->currentDay hour:[[self item] intValue] minute:30];
338   range = [NGCalendarDateRange calendarDateRangeWithStartDate:from endDate:to];
339   return [self isSlotRangeGreen:range];
340 }
341 - (BOOL)isSecondHalfGreen {
342   /* currentday is the date, self->item the hour */
343   NSCalendarDate *from, *to;
344   NGCalendarDateRange *range;
345
346   from  = [self->currentDay hour:[[self item] intValue] minute:30];
347   to    = [self->currentDay hour:[[self item] intValue] minute:59];
348   range = [NGCalendarDateRange calendarDateRangeWithStartDate:from endDate:to];
349   return [self isSlotRangeGreen:range];
350 }
351
352 - (BOOL)isFirstHalfBlocked {
353   return [self isFirstHalfGreen] ? NO : YES;
354 }
355 - (BOOL)isSecondHalfBlocked {
356   return [self isSecondHalfGreen] ? NO : YES;
357 }
358
359 /* actions */
360
361 - (BOOL)shouldTakeValuesFromRequest:(WORequest *)_rq inContext:(WOContext*)_c{
362   return YES;
363 }
364
365 - (id)defaultAction {
366   NSCalendarDate *now;
367   
368   now = [NSCalendarDate date];
369
370   [self setDuration:@"120"]; /* 1 hour as default */
371   [self setStartDate:[now hour:9 minute:0]];
372   [self setEndDate:[now hour:18 minute:0]];
373   
374   return self;
375 }
376
377 - (id)proposalSearchAction {
378   NSArray               *attendees, *uids;
379   SOGoAppointmentFolder *groupCalendar;
380   NSArray *coreInfos;
381   NSArray *ranges;
382   
383   [self logWithFormat:@"search from %@ to %@", 
384           [self startDate], [self endDate]];
385   
386   attendees = [self attendees];
387   uids      = [[self clientObject] uidsFromICalPersons:attendees];
388   if ([uids count] == 0) {
389     [self logWithFormat:@"Note: no UIDs selected."];
390     return self;
391   }
392   
393   groupCalendar = [[self clientObject] lookupGroupCalendarFolderForUIDs:uids
394                                        inContext:[self context]];
395   [self debugWithFormat:@"group calendar: %@", groupCalendar];
396   
397   if (![groupCalendar respondsToSelector:@selector(fetchCoreInfosFrom:to:)]) {
398     return [NSException exceptionWithHTTPStatus:500 /* Internal Error */
399                         reason:@"invalid folder to run proposal query on!"];
400   }
401   
402   // TODO: just query startdate and enddate ... (freebusy)
403   coreInfos = [groupCalendar fetchCoreInfosFrom:[self startDate]
404                              to:[self endDate]];
405   [self debugWithFormat:@"  process: %d events", [coreInfos count]];
406
407   ranges = [coreInfos arrayByCreatingDateRangesFromObjectsWithStartDateKey:
408                         @"startDate"
409                       andEndDateKey:@"endDate"];
410   ranges = [ranges arrayByCompactingContainedDateRanges];
411   [self debugWithFormat:@"  ranges: %@", ranges];
412   
413   ASSIGNCOPY(self->blockedRanges, ranges);
414   
415   return self;
416 }
417
418 @end /* UIxAppointmentProposal */