1/* UIxCalDayTable.m - this file is part of SOGo
2 *
3 * Copyright (C) 2006-2016 Inverse inc.
4 *
5 * This file is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This file is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; see the file COPYING.  If not, write to
17 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
19 */
20
21#import <Foundation/NSDictionary.h>
22#import <Foundation/NSUserDefaults.h> /* for locale string constants */
23#import <Foundation/NSValue.h>
24
25#import <NGExtensions/NSCalendarDate+misc.h>
26
27#import <SOPE/NGCards/iCalRecurrenceRule.h>
28
29#import <SOGo/NSCalendarDate+SOGo.h>
30#import <SOGo/SOGoDateFormatter.h>
31#import <SOGo/SOGoUser.h>
32#import <SOGo/SOGoUserDefaults.h>
33#import <SOGo/WOResourceManager+SOGo.h>
34
35#import <SoObjects/Appointments/SOGoAppointmentFolder.h>
36#import <SoObjects/Appointments/SOGoAppointmentFolders.h>
37
38#import "UIxCalDayTable.h"
39
40@class SOGoAppointment;
41
42@implementation UIxCalDayTable
43
44- (id) init
45{
46  SOGoUser *user;
47  SOGoUserDefaults *ud;
48
49  if ((self = [super init]))
50    {
51      user = [context activeUser];
52      ud = [user userDefaults];
53      ASSIGN (timeFormat, [ud timeFormat]);
54
55      daysToDisplay = nil;
56      calendarsToDisplay = nil;
57      hoursToDisplay = nil;
58      numberOfDays = 1;
59      startDate = nil;
60      currentView = nil;
61      currentCalendar = nil;
62      currentTableDay = nil;
63      currentTableHour = nil;
64      weekDays = [locale objectForKey: NSWeekDayNameArray];
65      [weekDays retain];
66      dateFormatter = [user dateFormatterInContext: context];
67      [dateFormatter retain];
68    }
69
70  return self;
71}
72
73- (void) dealloc
74{
75//   if (allAppointments)
76//     [allAppointments release];
77  [weekDays release];
78  [daysToDisplay release];
79  [calendarsToDisplay release];
80  [currentView release];
81  [hoursToDisplay release];
82  [dateFormatter release];
83  [timeFormat release];
84  free(daysNumbersToDisplay);
85  [super dealloc];
86}
87
88- (void) setNumberOfDays: (NSNumber *) aNumber
89{
90  numberOfDays = [aNumber intValue];
91  [daysToDisplay release];
92  daysToDisplay = nil;
93}
94
95- (NSNumber *) numberOfDays
96{
97  return [NSNumber numberWithUnsignedInt: numberOfDays];
98}
99
100- (void) setStartDate: (NSCalendarDate *) aStartDate
101{
102  startDate = [aStartDate beginOfDay];
103  [daysToDisplay release];
104  daysToDisplay = nil;
105}
106
107- (NSCalendarDate *) startDate
108{
109  if (!startDate)
110    startDate = [[super startDate] beginOfDay];
111
112  return startDate;
113}
114
115- (NSCalendarDate *) endDate
116{
117  NSCalendarDate *endDate;
118
119  endDate = [[self startDate] dateByAddingYears: 0
120                              months: 0
121                              days: numberOfDays - 1];
122
123  return [endDate endOfDay];
124}
125
126- (void) setCurrentView: (NSString *) aView
127{
128  ASSIGN(currentView, aView);
129}
130
131- (NSString *) currentView
132{
133  return currentView;
134}
135
136- (NSArray *) hoursToDisplay
137{
138  unsigned int currentHour, lastHour;
139
140  if (!hoursToDisplay)
141    {
142      hoursToDisplay = [NSMutableArray new];
143      currentHour = [self dayStartHour];
144      lastHour = [self dayEndHour];
145      while (currentHour < lastHour)
146        {
147          [hoursToDisplay addObject: [NSNumber numberWithInt: currentHour]];
148          currentHour++;
149        }
150      [hoursToDisplay addObject: [NSNumber numberWithInt: currentHour]];
151    }
152
153  return hoursToDisplay;
154}
155
156- (NSString *) currentHourId
157{
158  return [NSString stringWithFormat: @"hour%d", [currentTableHour intValue]];
159}
160
161/**
162 * Return an array of NSCalendarDate instances matching the requested time period
163 * and the week days enabled in the user's defaults.
164 */
165- (NSArray *) daysToDisplay
166{
167  NSCalendarDate *currentDate;
168  NSString *weekDay;
169  int count, enabledCount;
170
171  if (!daysToDisplay)
172  {
173    daysToDisplay = [NSMutableArray new];
174    daysNumbersToDisplay = malloc (numberOfDays * sizeof (unsigned int));
175    currentDate = [[self startDate] hour: [self dayStartHour]
176                                  minute: 0];
177
178    for (count = 0, enabledCount = 0; count < numberOfDays; count++)
179    {
180      weekDay = iCalWeekDayString[[currentDate dayOfWeek]];
181      if ([enabledWeekDays count] == 0 || [enabledWeekDays containsObject: weekDay])
182        {
183          [daysToDisplay addObject: currentDate];
184          daysNumbersToDisplay[enabledCount] = count;
185          enabledCount++;
186        }
187      currentDate = [currentDate tomorrow];
188    }
189  }
190
191  return daysToDisplay;
192}
193
194- (NSArray *) calendarsToDisplay
195{
196  if (!calendarsToDisplay)
197  {
198    NSArray *folders;
199    SOGoAppointmentFolders *co;
200    SOGoAppointmentFolder *folder;
201    NSMutableDictionary *calendar;
202    unsigned int count, foldersCount;
203    NSString *folderName, *fDisplayName;
204    BOOL isActive;
205
206    co = [self clientObject];
207    folders = [co subFolders];
208    foldersCount = [folders count];
209    calendarsToDisplay = [[NSMutableArray alloc] initWithCapacity: foldersCount];
210    for (count = 0; count < foldersCount; count++)
211    {
212      folder = [folders objectAtIndex: count];
213      isActive = [folder isActive];
214      if (isActive != NO) {
215        calendar = [NSMutableDictionary dictionary];
216        folderName = [folder nameInContainer];
217        fDisplayName = [folder displayName];
218        if (fDisplayName == nil)
219          fDisplayName = @"";
220        if ([fDisplayName isEqualToString: [co defaultFolderName]])
221          fDisplayName = [self labelForKey: fDisplayName];
222        [calendar setObject: [NSString stringWithFormat: @"/%@", folderName]
223                     forKey: @"id"];
224        [calendar setObject: fDisplayName forKey: @"displayName"];
225        [calendar setObject: folderName forKey: @"folder"];
226        [calendar setObject: [folder calendarColor] forKey: @"color"];
227        [calendar setObject: [NSNumber numberWithBool:isActive] forKey: @"active"];
228        [calendar setObject: [folder ownerInContext: context]
229                     forKey: @"owner"];
230        [calendarsToDisplay addObject: calendar];
231      }
232    }
233  }
234
235  return calendarsToDisplay;
236}
237
238- (void) setCurrentTableDay: (NSCalendarDate *) aTableDay
239{
240  currentTableDay = aTableDay;
241}
242
243- (NSCalendarDate *) currentTableDay
244{
245  return currentTableDay;
246}
247
248- (void) setCurrentCalendar: (NSMutableDictionary *) aCalendar
249{
250  ASSIGN(currentCalendar, aCalendar);
251}
252
253- (NSMutableDictionary *) currentCalendar
254{
255  return currentCalendar;
256}
257
258- (void) setCurrentTableHour: (NSNumber *) aTableHour
259{
260  ASSIGN(currentTableHour, aTableHour);
261}
262
263- (NSNumber *) currentTableHour
264{
265  return currentTableHour;
266}
267
268- (NSString *) currentFormattedHour
269{
270  int hour;
271  NSCalendarDate *tmp;
272  NSString *formatted = [NSString stringWithFormat: @"%d", [currentTableHour intValue]], *parse;
273
274  hour = [currentTableHour intValue];
275  parse = [NSString stringWithFormat: @"2000-01-01 %02d:00", hour];
276
277  tmp = [NSCalendarDate dateWithString: parse
278                        calendarFormat: @"%Y-%m-%d %H:%M"];
279  if (tmp)
280    formatted = [tmp descriptionWithCalendarFormat: timeFormat
281                                            locale: locale];
282
283  return formatted;
284}
285
286- (NSString *) currentAllDayId
287{
288  return [NSString stringWithFormat: @"allDay%@", [currentTableDay shortDateString]];
289}
290
291- (NSString *) currentDayId
292{
293  return [NSString stringWithFormat: @"day%@", [currentTableDay shortDateString]];
294}
295
296- (int) currentDayNumber
297{
298  int i = [daysToDisplay indexOfObject: currentTableDay];
299
300  return daysNumbersToDisplay[i];
301}
302
303- (NSNumber *) currentAppointmentHour
304{
305  return [NSNumber numberWithInt: [currentTableHour intValue]];
306}
307
308- (NSString *) currentYear
309{
310  if (([currentTableDay dayOfMonth] == 1 && [currentTableDay monthOfYear] == 1) ||
311      [daysToDisplay indexOfObject: currentTableDay] == 0)
312    return [NSString stringWithFormat: @"%i", [currentTableDay yearOfCommonEra]];
313
314  return nil;
315}
316
317- (NSString *) labelForDay
318{
319  return [weekDays objectAtIndex: [currentTableDay dayOfWeek]];
320}
321
322- (NSString *) labelForMonth
323{
324  NSString *calendarFormat;
325  BOOL isFirstDay;
326
327  isFirstDay = NO;
328  calendarFormat = @"%b";
329
330  if ([currentView hasSuffix: @"dayview"])
331    {
332      isFirstDay = YES;
333      calendarFormat = @"%B";
334    }
335  else if ([currentTableDay dayOfMonth] == 1 || [daysToDisplay indexOfObject: currentTableDay] == 0)
336    {
337      isFirstDay = YES;
338    }
339
340  return isFirstDay? [currentTableDay descriptionWithCalendarFormat: calendarFormat locale: locale] : nil;
341}
342
343- (NSString *) labelForDate
344{
345  return [dateFormatter shortFormattedDate: currentTableDay];
346}
347
348- (NSString *) labelForCalendar
349{
350  return [currentCalendar objectForKey: @"displayName"];
351}
352
353- (NSString *) colorForCalendar
354{
355  return [currentCalendar objectForKey:@"color"];
356}
357
358// - (NSDictionary *) _adjustedAppointment: (NSDictionary *) anAppointment
359//                                forStart: (NSCalendarDate *) start
360//                                  andEnd: (NSCalendarDate *) end
361// {
362//   NSMutableDictionary *newMutableAppointment;
363//   NSDictionary *newAppointment;
364//   BOOL startIsEarlier, endIsLater;
365
366//   startIsEarlier
367//     = ([[anAppointment objectForKey: @"startDate"] laterDate: start] == start);
368//   endIsLater
369//     = ([[anAppointment objectForKey: @"endDate"] earlierDate: end] == end);
370
371//   if (startIsEarlier || endIsLater)
372//     {
373//       newMutableAppointment
374//         = [NSMutableDictionary dictionaryWithDictionary: anAppointment];
375
376//       if (startIsEarlier)
377//         [newMutableAppointment setObject: start
378//                                forKey: @"startDate"];
379//       if (endIsLater)
380//         [newMutableAppointment setObject: end
381//                                forKey: @"endDate"];
382
383//       newAppointment = newMutableAppointment;
384//     }
385//   else
386//     newAppointment = anAppointment;
387
388//   return newAppointment;
389// }
390
391// - (NSArray *) appointmentsForCurrentDay
392// {
393//   NSMutableArray *filteredAppointments;
394//   NSEnumerator *aptsEnumerator;
395//   NSDictionary *currentDayAppointment;
396//   NSCalendarDate *start, *end;
397//   int endHour;
398
399//   if (!allAppointments)
400//     {
401//       allAppointments = [self fetchCoreAppointmentsInfos];
402//       [allAppointments retain];
403//     }
404
405//   filteredAppointments = [NSMutableArray new];
406//   [filteredAppointments autorelease];
407
408//   start = [currentTableDay hour: [self dayStartHour] minute: 0];
409//   endHour = [self dayEndHour];
410//   if (endHour < 24)
411//     end = [currentTableDay hour: [self dayEndHour] minute: 59];
412//   else
413//     end = [[currentTableDay tomorrow] hour: 0 minute: 0];
414
415//   aptsEnumerator = [allAppointments objectEnumerator];
416//   currentDayAppointment = [aptsEnumerator nextObject];
417//   while (currentDayAppointment)
418//     {
419//       if (([end laterDate: [currentDayAppointment
420//                              valueForKey: @"startDate"]] == end)
421//           && ([start earlierDate: [currentDayAppointment
422//                                     valueForKey: @"endDate"]] == start))
423//         [filteredAppointments
424//           addObject: [self _adjustedAppointment: currentDayAppointment
425//                            forStart: start andEnd: end]];
426//       currentDayAppointment = [aptsEnumerator nextObject];
427//     }
428
429//   return filteredAppointments;
430// }
431
432// - (void) setCurrentAppointment: (NSDictionary *) newCurrentAppointment
433// {
434//   currentAppointment = newCurrentAppointment;
435// }
436
437// - (NSDictionary *) currentAppointment
438// {
439//   return currentAppointment;
440// }
441
442- (NSString *) appointmentsClasses
443{
444  return [NSString stringWithFormat: @"appointments appointmentsFor%dDays",
445                   numberOfDays];
446}
447
448// - (NSString *) daysViewClasses
449// {
450//   NSString *daysView;
451
452//   if ([currentView isEqualToString:@"multicolumndayview"])
453//     daysView = @"daysView daysViewForMultipleDays";
454
455//   else
456//     daysView = [NSString stringWithFormat: @"daysView daysViewFor%dDays", numberOfDays];
457
458//   return daysView;
459//}
460
461// - (NSString *) daysViewHeaderClasses
462// {
463//   return [NSString stringWithFormat: @"%@ daysHeader", [self daysViewClasses]];
464// }
465
466- (NSString *) dayClasses
467{
468  NSMutableString *classes;
469  unsigned int realDayOfWeek;
470
471  classes = [NSMutableString stringWithString: @"day"];
472  realDayOfWeek = [currentTableDay dayOfWeek];
473
474  if (numberOfDays > 1)
475    {
476      if (realDayOfWeek == 0 || realDayOfWeek == 6)
477        [classes appendString: @" weekEndDay"];
478      if ([currentTableDay isToday])
479        [classes appendString: @" dayOfToday"];
480    }
481
482  return classes;
483}
484
485- (NSString *) clickableHourCellClass
486{
487  NSMutableString *cellClass;
488  int hour;
489  SOGoUserDefaults *ud;
490
491  cellClass = [NSMutableString string];
492  hour = [currentTableHour intValue];
493  ud = [[context activeUser] userDefaults];
494  [cellClass appendFormat: @"clickableHourCell clickableHourCell%d", hour];
495  if (hour < [ud dayStartHour] || hour > [ud dayEndHour] - 1)
496    [cellClass appendString: @" outOfDay"];
497
498  return cellClass;
499}
500
501- (BOOL) isMultiColumnView
502{
503  if ([currentView isEqualToString:@"multicolumndayview"])
504    return YES;
505
506  return NO;
507}
508
509- (BOOL) isNotMultiColumnView
510{
511  if ([currentView isEqualToString:@"dayview"] || [currentView isEqualToString:@"weekview"])
512    return YES;
513
514  return NO;
515}
516
517- (BOOL) isWeekView
518{
519  return [currentView isEqualToString:@"weekview"];
520}
521
522@end
523