1.1 --- a/imiptools/period.py Fri Jan 30 13:30:57 2015 +0100
1.2 +++ b/imiptools/period.py Fri Jan 30 16:00:15 2015 +0100
1.3 @@ -151,9 +151,10 @@
1.4 """
1.5 Return an ordered list of time slots from the given 'scale'.
1.6
1.7 - Each slot is a tuple containing a point in time for the start of the slot,
1.8 - together with a list of parallel event tuples, each tuple containing the
1.9 - original details of an event.
1.10 + Each slot is a tuple of the form (point, (endpoint, active)), where 'point'
1.11 + indicates the start of the slot, 'endpoint' the end of the slot (or None),
1.12 + and 'active' provides a list of parallel event tuples, with each tuple
1.13 + containing the original details of an event.
1.14 """
1.15
1.16 slots = []
1.17 @@ -162,6 +163,10 @@
1.18 points = scale.items()
1.19 points.sort()
1.20
1.21 + # Maintain a current slot so that the end can be added.
1.22 +
1.23 + current = None
1.24 +
1.25 for point, (starting, ending) in points:
1.26
1.27 # Discard all active events ending at or before this start time.
1.28 @@ -186,7 +191,14 @@
1.29 while active and active[-1] is None:
1.30 active.pop()
1.31
1.32 - slots.append((point, active[:]))
1.33 + if current:
1.34 + _point, _active = current
1.35 + slots.append((_point, (point, _active)))
1.36 + current = point, active[:]
1.37 +
1.38 + if current:
1.39 + _point, _active = current
1.40 + slots.append((_point, (None, _active)))
1.41
1.42 return slots
1.43
1.44 @@ -199,22 +211,22 @@
1.45
1.46 new_slots = []
1.47 current_date = None
1.48 - previously_active = None
1.49 + previously_active = []
1.50
1.51 - for point, active in slots:
1.52 + for point, (endpoint, active) in slots:
1.53 start_of_day = get_start_of_day(point)
1.54 this_date = point.date()
1.55
1.56 - # For each new day, add a slot for the start of the day where periods
1.57 - # are active and where no such slot already exists.
1.58 + # For each new day, add a slot for the start of the day where no such
1.59 + # slot already exists.
1.60
1.61 if this_date != current_date:
1.62 current_date = this_date
1.63
1.64 # Add any continuing periods.
1.65
1.66 - if point != start_of_day and previously_active:
1.67 - new_slots.append((start_of_day, previously_active))
1.68 + if point != start_of_day:
1.69 + new_slots.append((start_of_day, (point, previously_active)))
1.70
1.71 # Add the currently active periods at this point in time.
1.72
1.73 @@ -231,31 +243,46 @@
1.74 those added.
1.75 """
1.76
1.77 - new_slots = []
1.78 + for point in points:
1.79 + i = bisect_left(slots, (point, ()))
1.80
1.81 - for point in points:
1.82 - i = bisect_left(slots, (point, None))
1.83 + # Ignore points of time for which slots already exist.
1.84 +
1.85 if i < len(slots) and slots[i][0] == point:
1.86 continue
1.87
1.88 - new_slots.append((point, i > 0 and slots[i-1][1] or []))
1.89 + # Update the endpoint of any preceding slot to refer to this new point.
1.90 +
1.91 + if i > 0:
1.92 + _point, (_endpoint, previously_active) = slots[i-1]
1.93 + slots[i-1] = _point, (point, previously_active)
1.94 + else:
1.95 + previously_active = []
1.96
1.97 - for t in new_slots:
1.98 - insort_left(slots, t)
1.99 + # Either insert a new slot before any following ones.
1.100 +
1.101 + if i < len(slots):
1.102 + _point, (_endpoint, _active) = slots[i]
1.103 + slots.insert(i, (point, (_point, previously_active)))
1.104 +
1.105 + # Or add a new slot at the end of the list.
1.106 +
1.107 + else:
1.108 + slots.append((point, (None, previously_active)))
1.109
1.110 def partition_by_day(slots):
1.111
1.112 """
1.113 - Return a mapping from dates to time points provided by 'slots'.
1.114 + Return a mapping from dates to entries provided by 'slots'.
1.115 """
1.116
1.117 d = {}
1.118
1.119 - for point, value in slots:
1.120 + for point, (endpoint, value) in slots:
1.121 day = point.date()
1.122 if not d.has_key(day):
1.123 d[day] = []
1.124 - d[day].append((point, value))
1.125 + d[day].append((point, (endpoint, value)))
1.126
1.127 return d
1.128
1.129 @@ -263,10 +290,10 @@
1.130
1.131 "Inspect the given 'slots', returning a mapping of event uids to spans."
1.132
1.133 - points = [point for point, active in slots]
1.134 + points = [point for point, (endpoint, active) in slots]
1.135 spans = {}
1.136
1.137 - for point, active in slots:
1.138 + for point, (endpoint, active) in slots:
1.139 for t in active:
1.140 if t and len(t) >= 2:
1.141 start, end, uid, key = get_freebusy_details(t)