]> err.no Git - sope/commitdiff
work on recurrences
authorhelge <helge@e4a50df8-12e2-0310-a44c-efbce7f8a7e3>
Wed, 21 Sep 2005 14:03:18 +0000 (14:03 +0000)
committerhelge <helge@e4a50df8-12e2-0310-a44c-efbce7f8a7e3>
Wed, 21 Sep 2005 14:03:18 +0000 (14:03 +0000)
git-svn-id: http://svn.opengroupware.org/SOPE/trunk@1126 e4a50df8-12e2-0310-a44c-efbce7f8a7e3

sope-ical/NGiCal/ChangeLog
sope-ical/NGiCal/Version
sope-ical/NGiCal/iCalMonthlyRecurrenceCalculator.m
sope-ical/NGiCal/iCalRecurrenceRule.h
sope-ical/NGiCal/iCalRecurrenceRule.m

index 95123ffc22b9b8a23b186ac9e41d7fbc9eab7122..f19df928bfb7e90ceb249b6dc4b2734f73ebcb9b 100644 (file)
@@ -1,5 +1,13 @@
 2005-09-21  Helge Hess  <helge.hess@skyrix.com>
 
+       * v4.5.66
+
+       * iCalRecurrenceRule.m: temporarily expose byDayOccurence1 until the
+         API is fixed
+
+       * iCalMonthlyRecurrenceCalculator.m: prepared for byday/bymonthday
+         rule specs
+
        * v4.5.65
 
        * iCalMonthlyRecurrenceCalculator.m: fixed calculation of 'count' field
index 3e9a09867bfd8cae2d1f72d442f7e60efe48e7a3..59e5bbe07852a0e1804ee5f863d8ba0fc5c42bbb 100644 (file)
@@ -2,7 +2,7 @@
 
 MAJOR_VERSION=4
 MINOR_VERSION=5
-SUBMINOR_VERSION:=65
+SUBMINOR_VERSION:=66
 
 # v4.5.40 requires NGExtensions v4.5.145
 # v4.5.37 requires NGExtensions v4.5.140
index 7f04abb0ea233cb3d5601d021fd4fa181da66906..a9045ab38d8b8adf9ca859949fc98860f6e76ec4 100644 (file)
 
 @implementation iCalMonthlyRecurrenceCalculator
 
+typedef BOOL NGMonthSet[12];
+typedef BOOL NGMonthDaySet[31];
+
+static void NGMonthDaySet_clear(NGMonthDaySet *daySet) {
+  register unsigned i;
+  
+  for (i = 0; i < 31; i++)
+    (*daySet)[i] = NO;
+}
+
+static void NGMonthDaySet_copyOrUnion(NGMonthDaySet *base, NGMonthDaySet *new,
+                                      BOOL doCopy)
+{
+  register unsigned i;
+  
+  if (doCopy)
+    memcpy(base, new, sizeof(NGMonthDaySet));
+  else {
+    for (i = 0; i < 31; i++) {
+      if (!(*new)[i])
+        (*base)[i] = NO;
+    }
+  }
+}
+
+static void NGMonthDaySet_fillWithByMonthDay(NGMonthDaySet *daySet, 
+                                             NSArray *byMonthDay,
+                                             int numDaysInMonth)
+{
+  /* list of days in the month */
+  unsigned i, count;
+  
+  NGMonthDaySet_clear(daySet);
+
+  for (i = 0, count = [byMonthDay count]; i < count; i++) {
+    int dayInMonth; /* -31..-1 and 1..31 */
+        
+    if ((dayInMonth = [[byMonthDay objectAtIndex:i] intValue]) == 0)
+      continue; /* invalid value */
+    if (dayInMonth > numDaysInMonth)
+      continue; /* this month has less days */
+    if (dayInMonth < -numDaysInMonth)
+      continue; /* this month has less days */
+        
+    /* adjust negative days */
+        
+    if (dayInMonth < 0) {
+      /* eg: -1 == last day in month, 30 days => 30 */
+      dayInMonth = 32 - dayInMonth /* because we count from 1 */;
+    }
+    
+    (*daySet)[dayInMonth] = YES;
+  }
+}
+
+static void NGMonthDaySet_fillWithByDayX(NGMonthDaySet *daySet, 
+                                         unsigned dayMask,
+                                         int occurrence1)
+{
+  unsigned i, count;
+  
+  NGMonthDaySet_clear(daySet);
+  // TODO: complete me
+}
+
 - (NSArray *)recurrenceRangesWithinCalendarDateRange:(NGCalendarDateRange *)_r{
   /* main entry */
   NSMutableArray *ranges;
   NSTimeZone     *timeZone;
-  NSCalendarDate *firStart, *rStart, *rEnd, *until;
-  unsigned       i, count, interval;
+  NSCalendarDate *eventStartDate, *rStart, *rEnd, *until;
+  unsigned       monthIdxInRange, numberOfMonthsInRange, interval;
   int            diff;
-
-  firStart = [self->firstRange startDate];
-  timeZone = [firStart timeZone];
+  NGMonthSet byMonthList = { // TODO: fill from rrule, this is the default
+    YES, YES, YES, YES, YES, YES, 
+    YES, YES, YES, YES, YES, YES
+  };
+  NSArray *byMonthDay = nil; // array of ints (-31..-1 and 1..31)
+  
+  eventStartDate = [self->firstRange startDate];
+  timeZone = [eventStartDate timeZone];
   rStart   = [_r startDate];
   rEnd     = [_r endDate];
   interval = [self->rrule repeatInterval];
       rEnd = until; // TODO: why is that? end is _before_ until?
   }
   
-  // TODO: I think the diff is to skip recurrence which are before the
+  // TODO: I think the 'diff' is to skip recurrence which are before the
   //       requested range. Not sure whether this is actually possible, eg
   //       the repeatCount must be processed from the start.
-  diff = [firStart monthsBetweenDate:rStart];
-  if ((diff != 0) && [rStart compare:firStart] == NSOrderedAscending)
+  diff = [eventStartDate monthsBetweenDate:rStart];
+  if ((diff != 0) && [rStart compare:eventStartDate] == NSOrderedAscending)
     diff = -diff;
   
-  count  = [rStart monthsBetweenDate:rEnd] + 1;
-  ranges = [NSMutableArray arrayWithCapacity:count];
-  for (i = 0 ; i < count; i++) {
+  numberOfMonthsInRange  = [rStart monthsBetweenDate:rEnd] + 1;
+  ranges = [NSMutableArray arrayWithCapacity:numberOfMonthsInRange];
+  
+  /* 
+     Note: we do not add 'eventStartDate', this is intentional, the event date
+           itself is _not_ necessarily part of the sequence, eg with monthly
+           byday recurrences.
+  */
+  
+  for (monthIdxInRange = 0; monthIdxInRange < numberOfMonthsInRange; 
+       monthIdxInRange++) {
+    NSCalendarDate      *cursor;
     NSCalendarDate      *start, *end;
     NGCalendarDateRange *r;
-    int test;
+    unsigned            numDaysInMonth;
+    int                 monthIdxInRecurrence;
+    NGMonthDaySet monthDays;
+    BOOL          didByFill;
     
-    test = diff + i;
+    monthIdxInRecurrence = diff + monthIdxInRange;
     
-    if (test < 0)
+    if (monthIdxInRecurrence < 0)
       continue;
     
-    if ((test % interval) != 0)
+    /* first check whether we are in the interval */
+    
+    if ((monthIdxInRecurrence % interval) != 0)
       continue;
+
+    /*
+      Then the sequence is:
+      - check whether the month is in the BYMONTH list
+    */
+    
+    cursor = [eventStartDate dateByAddingYears:0
+                             months:(diff + monthIdxInRange)
+                             days:0];
+    [cursor setTimeZone:timeZone];
+    numDaysInMonth = [cursor numberOfDaysInMonth];
+    
+
+    /* check whether we match the bymonth specification */
+    
+    if (!byMonthList[[cursor monthOfYear] - 1])
+      continue;
+    
+    
+    /* check 'day level' byXYZ rules */
     
-    start = [firStart dateByAddingYears:0 months:(diff + i) days:0];
-    [start setTimeZone:timeZone];
+    didByFill = NO;
+    
+    if (byMonthDay != nil) { /* list of days in the month */
+      NGMonthDaySet ruleset;
+      
+      NGMonthDaySet_fillWithByMonthDay(&ruleset, byMonthDay, numDaysInMonth);
+      NGMonthDaySet_copyOrUnion(&monthDays, &ruleset, !didByFill);
+      didByFill = YES;
+    }
+    
+    if ([self->rrule byDayMask] != 0) { // TODO: replace the mask with an array
+      NGMonthDaySet ruleset;
+      
+      NGMonthDaySet_fillWithByDayX(&ruleset, 
+                                   [self->rrule byDayMask],
+                                   [self->rrule byDayOccurence1]);
+      NGMonthDaySet_copyOrUnion(&monthDays, &ruleset, !didByFill);
+      didByFill = YES;
+    }
+    
+    
+    // TODO: complete byday support
+    
+    /* set start date */
+    
+    start = cursor;
     
     /* check whether we are still in the limits */
     
     unsigned       months, interval;
     
     interval = [self->rrule repeatInterval];
-    months   = ([self->rrule repeatCount] - 1) * interval;
-    until    = [[self->firstRange startDate] dateByAddingYears:0
-                                             months:months
-                                             days:0];
+    months   = [self->rrule repeatCount] - 1 /* the first counts as one! */;
+    
+    if (interval > 0)
+      months *= interval;
+    
+    until = [[self->firstRange startDate] dateByAddingYears:0
+                                          months:months
+                                          days:0];
     return until;
   }
   return [super lastInstanceStartDate];
index 45d42b757d5a50899fe4ac7bed51bae25f5785bc..a36d67536ba58815e145b0595837709efc8267a6 100644 (file)
@@ -90,6 +90,7 @@ typedef enum {
 
 - (void)setByDayMask:(unsigned)_mask;
 - (unsigned)byDayMask;
+- (int)byDayOccurence1;
   
 /* count and untilDate are mutually exclusive */
 
index 3a32075cf74c35f85f0aa4171cc734601c6db5fb..f437738a57e707ab7083a3aa6ac7474aaba576f9 100644 (file)
 - (unsigned)byDayMask {
   return self->byDay.mask;
 }
+- (int)byDayOccurence1 {
+  return self->byDayOccurence1;
+}
 
 - (BOOL)isInfinite {
   return (self->repeatCount != 0 || self->untilDate) ? NO : YES;