# HG changeset patch # User Paul Boddie # Date 1439672339 -7200 # Node ID e43d62cc38328842e051624fc7b669e2fc677d39 # Parent 7a2cf3dead31215aa0c328657c0e661922cb2bd3 Added functions for coalescing and inverting free/busy information. Made separate functions for obtaining periods before and from a given point. diff -r 7a2cf3dead31 -r e43d62cc3832 imiptools/period.py --- a/imiptools/period.py Sat Aug 15 22:57:17 2015 +0200 +++ b/imiptools/period.py Sat Aug 15 22:58:59 2015 +0200 @@ -348,6 +348,20 @@ found += 1 +def periods_from(freebusy, period): + + "Return the entries in 'freebusy' at or after 'period'." + + first = bisect_left(freebusy, period) + return freebusy[first:] + +def periods_until(freebusy, period): + + "Return the entries in 'freebusy' before 'period'." + + last = bisect_right(freebusy, Period(period.get_end(), period.get_end(), period.get_tzid())) + return freebusy[:last] + def get_overlapping(freebusy, period): """ @@ -358,8 +372,7 @@ # Find the range of periods potentially overlapping the period in the # free/busy collection. - last = bisect_right(freebusy, Period(period.get_end(), period.get_end(), period.tzid)) - startpoints = freebusy[:last] + startpoints = periods_until(freebusy, period) # Find the range of periods potentially overlapping the period in a version # of the free/busy collection sorted according to end datetimes. @@ -415,6 +428,62 @@ for replacement in replacements: insert_period(freebusy, replacement) +def get_free_periods(freebusy, period, overlapping=False): + + """ + Return periods from 'freebusy' within which the given 'period' could be + inserted. If 'overlapping' is true, only return free periods that overlap + 'period'. + """ + + free = invert_freebusy(freebusy) + if not free: + return None + + if overlapping: + return get_overlapping(free, period) + else: + return free + +def coalesce_freebusy(freebusy): + + "Coalesce the periods in 'freebusy'." + + if not freebusy: + return freebusy + + fb = [] + start = freebusy[0].get_start_point() + end = freebusy[0].get_end_point() + + for period in freebusy[1:]: + if period.get_start_point() > end: + fb.append(FreeBusyPeriod(start, end)) + start = period.get_start_point() + end = period.get_end_point() + else: + end = max(end, period.get_end_point()) + + fb.append(FreeBusyPeriod(start, end)) + return fb + +def invert_freebusy(freebusy): + + "Return the free periods from 'freebusy'." + + if not freebusy: + return None + + fb = coalesce_freebusy(freebusy) + free = [] + start = fb[0].get_end_point() + + for period in fb[1:]: + free.append(FreeBusyPeriod(start, period.get_start_point())) + start = period.get_end_point() + + return free + # Period layout. def get_scale(periods, tzid):