1.1 --- a/imiptools/period.py Sat Aug 15 22:57:17 2015 +0200
1.2 +++ b/imiptools/period.py Sat Aug 15 22:58:59 2015 +0200
1.3 @@ -348,6 +348,20 @@
1.4
1.5 found += 1
1.6
1.7 +def periods_from(freebusy, period):
1.8 +
1.9 + "Return the entries in 'freebusy' at or after 'period'."
1.10 +
1.11 + first = bisect_left(freebusy, period)
1.12 + return freebusy[first:]
1.13 +
1.14 +def periods_until(freebusy, period):
1.15 +
1.16 + "Return the entries in 'freebusy' before 'period'."
1.17 +
1.18 + last = bisect_right(freebusy, Period(period.get_end(), period.get_end(), period.get_tzid()))
1.19 + return freebusy[:last]
1.20 +
1.21 def get_overlapping(freebusy, period):
1.22
1.23 """
1.24 @@ -358,8 +372,7 @@
1.25 # Find the range of periods potentially overlapping the period in the
1.26 # free/busy collection.
1.27
1.28 - last = bisect_right(freebusy, Period(period.get_end(), period.get_end(), period.tzid))
1.29 - startpoints = freebusy[:last]
1.30 + startpoints = periods_until(freebusy, period)
1.31
1.32 # Find the range of periods potentially overlapping the period in a version
1.33 # of the free/busy collection sorted according to end datetimes.
1.34 @@ -415,6 +428,62 @@
1.35 for replacement in replacements:
1.36 insert_period(freebusy, replacement)
1.37
1.38 +def get_free_periods(freebusy, period, overlapping=False):
1.39 +
1.40 + """
1.41 + Return periods from 'freebusy' within which the given 'period' could be
1.42 + inserted. If 'overlapping' is true, only return free periods that overlap
1.43 + 'period'.
1.44 + """
1.45 +
1.46 + free = invert_freebusy(freebusy)
1.47 + if not free:
1.48 + return None
1.49 +
1.50 + if overlapping:
1.51 + return get_overlapping(free, period)
1.52 + else:
1.53 + return free
1.54 +
1.55 +def coalesce_freebusy(freebusy):
1.56 +
1.57 + "Coalesce the periods in 'freebusy'."
1.58 +
1.59 + if not freebusy:
1.60 + return freebusy
1.61 +
1.62 + fb = []
1.63 + start = freebusy[0].get_start_point()
1.64 + end = freebusy[0].get_end_point()
1.65 +
1.66 + for period in freebusy[1:]:
1.67 + if period.get_start_point() > end:
1.68 + fb.append(FreeBusyPeriod(start, end))
1.69 + start = period.get_start_point()
1.70 + end = period.get_end_point()
1.71 + else:
1.72 + end = max(end, period.get_end_point())
1.73 +
1.74 + fb.append(FreeBusyPeriod(start, end))
1.75 + return fb
1.76 +
1.77 +def invert_freebusy(freebusy):
1.78 +
1.79 + "Return the free periods from 'freebusy'."
1.80 +
1.81 + if not freebusy:
1.82 + return None
1.83 +
1.84 + fb = coalesce_freebusy(freebusy)
1.85 + free = []
1.86 + start = fb[0].get_end_point()
1.87 +
1.88 + for period in fb[1:]:
1.89 + free.append(FreeBusyPeriod(start, period.get_start_point()))
1.90 + start = period.get_end_point()
1.91 +
1.92 + return free
1.93 +
1.94 # Period layout.
1.95
1.96 def get_scale(periods, tzid):