1.1 --- a/imiptools/data.py Sat Aug 01 22:24:43 2015 +0200
1.2 +++ b/imiptools/data.py Sat Aug 01 23:06:48 2015 +0200
1.3 @@ -124,6 +124,9 @@
1.4 def get_date_value_items(self, name, tzid=None):
1.5 return get_date_value_items(self.details, name, tzid)
1.6
1.7 + def get_period_values(self, name, tzid=None, period_type=None):
1.8 + return get_period_values(self.details, name, tzid, period_type)
1.9 +
1.10 def get_datetime(self, name):
1.11 t = get_datetime_item(self.details, name)
1.12 if not t: return None
1.13 @@ -171,16 +174,50 @@
1.14
1.15 # Computed results.
1.16
1.17 - def get_periods(self, tzid, end):
1.18 + def get_periods(self, tzid, end=None):
1.19
1.20 """
1.21 Return periods defined by this object, employing the given 'tzid' where
1.22 no time zone information is defined, and limiting the collection to a
1.23 window of time with the given 'end'.
1.24 +
1.25 + If 'end' is omitted, only explicit recurrences and recurrences from
1.26 + explicitly-terminated rules will be returned.
1.27 """
1.28
1.29 return get_periods(self, tzid, end)
1.30
1.31 + def get_active_periods(self, recurrenceids, tzid, end=None):
1.32 +
1.33 + """
1.34 + Return all periods specified by this object that are not replaced by
1.35 + those defined by 'recurrenceids', using 'tzid' as a fallback time zone
1.36 + to convert floating dates and datetimes, and using 'end' to indicate the
1.37 + end of the time window within which periods are considered.
1.38 + """
1.39 +
1.40 + # Specific recurrences yield all specified periods.
1.41 +
1.42 + periods = self.get_periods(tzid, end)
1.43 +
1.44 + if self.get_recurrenceid():
1.45 + return periods
1.46 +
1.47 + # Parent objects need to have their periods tested against redefined
1.48 + # recurrences.
1.49 +
1.50 + active = []
1.51 +
1.52 + for p in periods:
1.53 +
1.54 + # Subtract any recurrences from the free/busy details of a
1.55 + # parent object.
1.56 +
1.57 + if not is_replaced(p, recurrenceids, tzid):
1.58 + active.append(p)
1.59 +
1.60 + return active
1.61 +
1.62 def get_tzid(self):
1.63
1.64 """
1.65 @@ -191,7 +228,10 @@
1.66 if not self.has_key("DTSTART"):
1.67 return None
1.68 dtstart, dtstart_attr = self.get_datetime_item("DTSTART")
1.69 - dtend, dtend_attr = self.get_datetime_item("DTEND")
1.70 + if self.has_key("DTEND"):
1.71 + dtend, dtend_attr = self.get_datetime_item("DTEND")
1.72 + else:
1.73 + dtend_attr = None
1.74 return get_tzid(dtstart_attr, dtend_attr)
1.75
1.76 def is_shared(self):
1.77 @@ -441,6 +481,22 @@
1.78 else:
1.79 return None
1.80
1.81 +def get_period_values(d, name, tzid=None, period_type=None):
1.82 +
1.83 + """
1.84 + Return period values from 'd' for the given property 'name', using 'tzid'
1.85 + where specified to indicate the time zone, and 'period_type' to indicate a
1.86 + particular period type to be used when creating period instances.
1.87 + """
1.88 +
1.89 + values = []
1.90 + for value, attr in get_items(d, name) or []:
1.91 + if not attr.has_key("TZID") and tzid:
1.92 + attr["TZID"] = tzid
1.93 + start, end = get_period(value, attr)
1.94 + values.append((period_type or Period)(start, end, tzid=tzid))
1.95 + return values
1.96 +
1.97 def get_utc_datetime(d, name, date_tzid=None):
1.98
1.99 """
1.100 @@ -524,15 +580,18 @@
1.101
1.102 return is_same_sequence and partstat_set or not is_old_sequence
1.103
1.104 -def get_periods(obj, tzid, window_end, inclusive=False):
1.105 +def get_periods(obj, tzid, end=None, inclusive=False):
1.106
1.107 """
1.108 Return periods for the given object 'obj', employing the given 'tzid' where
1.109 no time zone information is available (for whole day events, for example),
1.110 - confining materialised periods to before the given 'window_end' datetime.
1.111 + confining materialised periods to before the given 'end' datetime.
1.112
1.113 - If 'inclusive' is set to a true value, any period occurring at the
1.114 - 'window_end' will be included.
1.115 + If 'end' is omitted, only explicit recurrences and recurrences from
1.116 + explicitly-terminated rules will be returned.
1.117 +
1.118 + If 'inclusive' is set to a true value, any period occurring at the 'end'
1.119 + will be included.
1.120 """
1.121
1.122 rrule = obj.get_value("RRULE")
1.123 @@ -558,7 +617,9 @@
1.124
1.125 if not rrule:
1.126 periods = [RecurringPeriod(dtstart, dtend, tzid, "DTSTART", dtstart_attr, dtend_attr)]
1.127 - else:
1.128 +
1.129 + elif end or parameters.has_key("UNTIL") or parameters.has_key("COUNT"):
1.130 +
1.131 # Recurrence rules create multiple instances to be checked.
1.132 # Conflicts may only be assessed within a period defined by policy
1.133 # for the agent, with instances outside that period being considered
1.134 @@ -570,14 +631,14 @@
1.135
1.136 until = parameters.get("UNTIL")
1.137 if until:
1.138 - window_end = min(to_timezone(get_datetime(until, dtstart_attr), tzid), window_end)
1.139 + end = min(to_timezone(get_datetime(until, dtstart_attr), tzid), end)
1.140 inclusive = True
1.141
1.142 - for start in selector.materialise(dtstart, window_end, parameters.get("COUNT"), parameters.get("BYSETPOS"), inclusive):
1.143 - create = len(start) == 3 and date or datetime
1.144 - start = to_timezone(create(*start), tzid)
1.145 - end = start + duration
1.146 - periods.append(RecurringPeriod(start, end, tzid, "RRULE"))
1.147 + for recurrence_start in selector.materialise(dtstart, end, parameters.get("COUNT"), parameters.get("BYSETPOS"), inclusive):
1.148 + create = len(recurrence_start) == 3 and date or datetime
1.149 + recurrence_start = to_timezone(create(*recurrence_start), tzid)
1.150 + recurrence_end = recurrence_start + duration
1.151 + periods.append(RecurringPeriod(recurrence_start, recurrence_end, tzid, "RRULE"))
1.152
1.153 # Add recurrence dates.
1.154