1.1 --- a/imiptools/handlers/scheduling.py Tue Oct 27 00:05:46 2015 +0100
1.2 +++ b/imiptools/handlers/scheduling.py Tue Oct 27 00:26:59 2015 +0100
1.3 @@ -19,7 +19,8 @@
1.4 this program. If not, see <http://www.gnu.org/licenses/>.
1.5 """
1.6
1.7 -from imiptools.dates import ValidityError
1.8 +from imiptools.dates import ValidityError, to_timezone
1.9 +from imiptools.period import invert_freebusy, periods_from
1.10
1.11 def schedule_in_freebusy(handler):
1.12
1.13 @@ -80,11 +81,111 @@
1.14
1.15 return scheduled == "ACCEPTED" and (corrected and "COUNTER" or "ACCEPTED") or "DECLINED"
1.16
1.17 +def schedule_next_available_in_freebusy(handler):
1.18 +
1.19 + """
1.20 + Attempt to schedule the current object of the given 'handler', correcting
1.21 + specified datetimes according to the configuration of a resource, then
1.22 + suggesting the next available period in the free/busy records if scheduling
1.23 + cannot occur for the requested period, returning an indication of the kind
1.24 + of response to be returned.
1.25 + """
1.26 +
1.27 + scheduled = schedule_corrected_in_freebusy(handler)
1.28 +
1.29 + if scheduled in ("ACCEPTED", "COUNTER"):
1.30 + return scheduled
1.31 +
1.32 + # Find free periods, update the object with the details.
1.33 +
1.34 + freebusy = handler.store.get_freebusy(handler.user)
1.35 + free = invert_freebusy(freebusy)
1.36 + permitted_values = handler.get_permitted_values()
1.37 + periods = []
1.38 +
1.39 + # Do not attempt to redefine rule-based periods.
1.40 +
1.41 + last = None
1.42 +
1.43 + for period in handler.get_periods(handler.obj, explicit_only=True):
1.44 + duration = period.get_duration()
1.45 +
1.46 + # Try and schedule periods normally since some of them may be
1.47 + # compatible with the schedule.
1.48 +
1.49 + if permitted_values:
1.50 + period = period.get_corrected(permitted_values)
1.51 +
1.52 + scheduled = handler.can_schedule(freebusy, [period])
1.53 +
1.54 + if scheduled == "ACCEPTED":
1.55 + periods.append(period)
1.56 + last = period.get_end()
1.57 + continue
1.58 +
1.59 + # Get free periods from the time of each period.
1.60 +
1.61 + for found in periods_from(free, period):
1.62 +
1.63 + # Skip any periods before the last period.
1.64 +
1.65 + if last:
1.66 + if last > found.get_end():
1.67 + continue
1.68 +
1.69 + # Adjust the start of the free period to exclude the last period.
1.70 +
1.71 + found = found.make_corrected(max(found.get_start(), last), found.get_end())
1.72 +
1.73 + # Only test free periods long enough to hold the requested period.
1.74 +
1.75 + if found.get_duration() >= duration:
1.76 +
1.77 + # Obtain a possible period, starting at the found point and
1.78 + # with the requested duration. Then, correct the period if
1.79 + # necessary.
1.80 +
1.81 + start = to_timezone(found.get_start(), period.get_tzid())
1.82 + possible = period.make_corrected(start, start + period.get_duration())
1.83 + if permitted_values:
1.84 + possible = possible.get_corrected(permitted_values)
1.85 +
1.86 + # Only if the possible period is still within the free period
1.87 + # can it be used.
1.88 +
1.89 + if possible.within(found):
1.90 + periods.append(possible)
1.91 + break
1.92 +
1.93 + # Where no period can be found, decline the invitation.
1.94 +
1.95 + else:
1.96 + return "DECLINED"
1.97 +
1.98 + # Use the found period to set the start of the next window to search.
1.99 +
1.100 + last = periods[-1].get_end()
1.101 +
1.102 + # Replace the periods in the object.
1.103 +
1.104 + obj = handler.obj.copy()
1.105 + changed = handler.obj.set_periods(periods)
1.106 +
1.107 + # Check one last time, reverting the change if not scheduled.
1.108 +
1.109 + scheduled = schedule_in_freebusy(handler)
1.110 +
1.111 + if scheduled == "DECLINED":
1.112 + handler.set_object(obj)
1.113 +
1.114 + return scheduled == "ACCEPTED" and (changed and "COUNTER" or "ACCEPTED") or "DECLINED"
1.115 +
1.116 # Registry of scheduling functions.
1.117
1.118 scheduling_functions = {
1.119 "schedule_in_freebusy" : schedule_in_freebusy,
1.120 "schedule_corrected_in_freebusy" : schedule_corrected_in_freebusy,
1.121 + "schedule_next_available_in_freebusy" : schedule_next_available_in_freebusy,
1.122 }
1.123
1.124 # vim: tabstop=4 expandtab shiftwidth=4