5.1. Scheduling (schedule.rsl)

(****
 *
 * Module Schedule defines the objects and operations related to scheduling
 * appointments, meetings, tasks, and events in the Calendar system.  It also
 * defines the objects and operations for defining calendar item categories.
 *
 *)

module Schedule;

  from CalendarDB import CalendarDB, UserWorkSpace, UserCalendar, UserOptions,
        RequiresSaving;
  from Admin import UserId;
  export ScheduledItem, Title, StartTime, Duration, Category, Location,
        Security, Priority, Date, Hours, Minutes, DateNumber, Time, Hour,
        Minute, AmOrPm, DayName, MonthName;

  object ScheduledItem is
    components: title:Title and start_or_due_date:StartOrDueDate and
        end_date:EndDate and category:Category and recurring_id:RecurringId;
    description: (*
        A ScheduledItem is the generic definition for the types of items stored
        in a calendar.  The Title component is a brief description of what the
        item is for.  The StartOrDueDate and EndDate components indicate when
        the item is scheduled.  The Category component is used to organize
        items into related color-coded categories.  RecurringId is used to
        identify the common instances of a recurring item.
                                                                            <p>
        There are four specializations of ScheduledItem.  They are Appointment,
        Meeting, Event, and Task, q.q.v.
    *);
  end ScheduledItem;

  object Appointment inherits from ScheduledItem
    components: start_time:StartTime and duration:Duration and
        recurring:RecurringInfo and location:Location and security:Security and
        priority:Priority and remind_info:RemindInfo and details:Details;
    description: (*
        An Appointment adds a number of components to a generic ScheduledItem.
        The StartTime and Duration indicate when the appointment starts and how
        long it lasts.  The RecurringInfo defines if and how an appointment
        recurs.  The Location is where it is held.  The Security indicates who
        can see that the appointment is scheduled.  Priority is how important
        the appointment is.  RemindInfo indicates if and how the user is
        reminded of the appointment.  Details are free form text describing any
        specific appointment details.
    *);
  end Appointment;

  object Meeting inherits from Appointment
    components: Attendees and MeetingMinutesLocation and ScheduledBy and
        ScheduledOn;
    description: (*
        A Meeting adds four components to an Appointment.  The Attendees
        component reflects the fact that a meeting is scheduled for more than
        one person, whereas an appointment is for a single user.  The
        MeetingMinutesLocation is URL for the minutes of a meeting, once it has
        been held.  The ScheduledBy component specifies which user scheduled
        the meeting.  ScheduledOn specifies the date and time on which it is
        scheduled.  Taken together, the ScheduledBy and ScheduledOn values
        provide a unique identification for a scheduled meeting, for use by the
        meeting change and delete operations, q.q.v.
    *);
  end Meeting;

  object Task inherits from ScheduledItem
    components: DueTime and RecurringInfo and SimpleSecurity and
        TaskPriority and RemindInfo and Details and CompletedFlag and
        CompletionDate;
    description: (*
        Like an Appointment, a Task adds a number of components to a generic
        ScheduledItem.  A task differs from an appointment as follows: (1)
        Appointments have Duration and Location, Tasks do not.  (2) For
        appointments, the priority is either 'Must' or 'Optional'; for tasks,
        priority is a positive integer indicating the relative priority of a
        task compared to other tasks.  (3) Tasks have a CompletedFlag and
        CompletionDate components; appointments do not.
    *);
  end Task;

  object Event inherits from ScheduledItem
    components: SimpleSecurity;
    description: (*
        An Event is the simplest type of ScheduledItem.  The only component it
        adds to a ScheduledItem is SimpleSecurity.
    *);
  end Event;

  object Title is string
    description: (*
        A Title is a free-form text string describing a scheduled item.
    *);
  end Title;

  object StartOrDueDate is Date
    description: (*
        StartOrDueDate is a multi-purpose component of ScheduledItem.  Its
        purpose depends on whether an item is a Task and whether it is recurs.
        For non-recurring appointments, meetings and events, StartOrDueDate is
        used as the single date on which the item is scheduled.  If the item is
        recurring or a multi-day event, StartOrDueDate is the first date on
        which it occurs.  For a non-recurring Task, StartOrDueDate is the
        single date the task is due.  If the task is recurring, StartOrDueDate
        is the first date it is due.
    *);
  end StartOrDueDate;

  object EndDate is Date
    description: (*
        In recurring appointments, meetings, and tasks, the end date defines
        the last date on which the item will recur.  In events, the end date
        defines the last date of a multi-day event.  When the value of end date
        is empty, the StartOrDueDate component is interpreted as the single
        date on which the item occurs.
    *);
  end EndDate;

  object Date is day:DayName and number:DateNumber and month:MonthName and
        year:Year
    description: (*
        A Date is the basic unit of calendar time keeping, consisting of a day
        of the week, numeric date, month, and year.
    *);
  end Date;

  object DayName is Sunday or Monday or Tuesday or Wednesday or Thursday or
        Friday or Saturday
    description: (*
        The seven standard names of the days of the week.
    *);
  end DayName;

  object Sunday
    description: (* One of the seven days of the week. *);
  end;

  object Monday
    description: (* One of the seven days of the week. *);
  end;

  object Tuesday
    description: (* One of the seven days of the week. *);
  end;

  object Wednesday
    description: (* One of the seven days of the week. *);
  end;

  object Thursday
    description: (* One of the seven days of the week. *);
  end;

  object Friday
    description: (* One of the seven days of the week. *);
  end;

  object Saturday
    description: (* One of the seven days of the week. *);
  end;

  object MonthName is jan:January or feb:February or mar:March or apr:April or
        may:May or jun:June or jul:July or aug:August or sep:September or
        oct:October or nov:November or dec:December
    description: (*
        One of the twelve months of the year.
    *);
  end MonthName;

  object January
    description: (* One of the twelve months of the year. *);
  end;

  object February
    description: (* One of the twelve months of the year. *);
  end;

  object March
    description: (* One of the twelve months of the year. *);
  end;

  object April
    description: (* One of the twelve months of the year. *);
  end;

  object May
    description: (* One of the twelve months of the year. *);
  end;

  object June
    description: (* One of the twelve months of the year. *);
  end;

  object July
    description: (* One of the twelve months of the year. *);
  end;

  object August
    description: (* One of the twelve months of the year. *);
  end;

  object September
    description: (* One of the twelve months of the year. *);
  end;

  object October
    description: (* One of the twelve months of the year. *);
  end;

  object November
    description: (* One of the twelve months of the year. *);
  end;

  object December
    description: (* One of the twelve months of the year. *);
  end;

  object Year is integer
    description: (*
        The four-digit year number.  (Yes, this Calendar Tool has a Y10K
        problem.)
    *);
  end Year;

  object StartTime is Time
    description: (*
        StartTime is the starting time of a scheduled appointment or meeting.
    *);
  end StartTime;

  object DueTime is Time
    description: (*
        DueTime is the time a task is due.
    *);
  end StartTime;

  object Duration is
    components: hours:Hours and minutes:Minutes;
    description: (*
        Duration is the time length of a scheduled item, in hours and minutes.
        The minimum duration value is 1 minute.  The maximum is 999 hours.
    *);
  end Duration;

  object Hours is integer
    description: (*
        Hours component of a scheduled item duration, between 0 and 999.
    *);
  end;

  object Minutes is integer
    description: (*
        Minutes component of a scheduled item duration, between 0 and 60*999.
    *);
  end;

  object Time is hour:Hour and minute:Minute and am_or_pm:AmOrPm
    description: (*
        A Time consists of an hour, minute, and AM or PM indicator.  A time
        value is expressed using a 12-hour or 24-hour clock style.  The clock
        style is set as an option by the user.  If the clock style is 24-hour,
        the AmOrPm indicator is nil.
    *);
  end Time;

  object Hour is integer
    description: (*
        The hour component of a time value, between 1 and 12 or 0 and 24 based
        on the clock style in use.
    *);
  end Hour;

  object Minute is integer
    description: (*
        The minute component of a time value, between 0 and 59.
    *);
  end Minute;

  object AmOrPm is AM or PM
    description: (*
        Standard suffix used in 12-hour time value.
    *);
  end AmOrPm;

  object AM
    description: (* The 12-hour time suffix indicating a morning time. *);
  end;

  object PM
    description: (* The 12-hour time suffix indicating an afternoon time. *);
  end;

  (**
   * Something's gotta get fixed in this vicinity given that recurring
   * information is different for Meetings versus MeetingRequests.
   *)
  object RecurringInfo is
    components: IsRecurring and Interval and IntervalDetails;
    description: (*
        RecurringInfo has components to specify the nature of a recurring item.
        IsRecurring is an on/off flag that indicates whether an item recurs.
        Interval is one of Weekly, Biweekly, Monthly, or Yearly.  The
        IntervalDetails component defines the precise means to define
        recurrence for the different interval levels.
    *);
  end RecurringInfo;

  object IsRecurring is boolean;

  obj Interval is
    components: Weekly or Biweekly or Monthly or Yearly;
    description: (*
        Interval specifies the granularity at which recurring items are
        defined.  The Weekly and Biweekly settings allow the user to specify
        recurrence on one or more days of the week.  The Monthly setting allows
        the user to specify recurrence on one or more days in one or more weeks
        of each month.  The Yearly setting allows the user to specify
        recurrence on one or more specific dates in the year.
    *);
  end Interval;

  object Weekly
    description: (* Indicates a scheduled item recurs weekly. *);
  end;

  object Biweekly
    description: (* Indicates a scheduled item recurs bi-weekly. *);
  end;

  object Monthly
    description: (* Indicates a scheduled item recurs monthly. *);
  end;

  object Yearly
    description: (* Indicates a scheduled item recurs yearly. *);
  end;

  object IntervalDetails is
    components: WeeklyDetails or MonthlyDetails;
    description: (*
        IntervalDetails are either weekly or monthly.
    *);
  end IntervalDetails;

  object WeeklyDetails is
    components: OnSun and OnMon and OnTue and OnWed and OnThu and OnFri and
        OnSat;
    description: (*
        WeeklyDetails has an on/off setting for each day of the week on which
        an item recurs.  These details are also used for the BiWeekly setting
        of the recurrence interval.
    *);
  end WeeklyDetails;

  object MonthlyDetails is
    components: MonthlyDayDetails or MonthlyDateDetails;
    description: (*
        MonthlyDetails can be specified on a day-of-the-week basis or on
        specific date(s) basis.  The two components contain the specific
        details for these two types of settings.
    *);
  end MonthlyDetails;

  object MonthlyDayDetails is
    components: FirstWeekDetails and SecondWeekDetails and ThirdWeekDetails and
        FourthWeekDetails and FifthWeekDetails and LastWeekDetails;
    description: (*
        MonthlyDayDetails contains a weekly details component for each possible
        week of a month.  The First- through ThirdWeekDetails are distinct for
        all possible months.  Depending on the configuration of a particular
        month in a particular year, there is potential conflict in specifying
        recurrence in the fourth, fifth, or last weeks.  The conflicts are
        resolved as follows:
                                                                            <p>
        For months with 4 weeks only, the settings in FifthWeekDetails do not
        apply, and the settings in LastWeekDetails, if present, override any
        settings in FourthWeekDetails.  For months with 5 weeks only, the
        settings in LastWeekDetails, if present, override any settings in
        FifthWeekDetails.  (For months with 6 weeks, the LastWeekDetails
        component applies to the 6th week, and there are no conflicts.)
    *);
  end MonthlyDayDetails;

  object MonthlyDateDetails is
    components: DateNumber*;
    description: (*
        MonthlyDateDetails is a list of zero or more specific dates in a month
        on which an item recurs.
    *);
  end MonthlyDateDetails;

  object DateNumber is integer
    description: (*
        The numeric value of the date in a month, between 1 and 31.
    *);
  end DateNumber;

  object OnSun is boolean
    description: (* Indicates that an item recurs on Sunday. *);
  end;

  object OnMon is boolean
    description: (* Indicates that an item recurs on Monday. *);
  end;

  object OnTue is boolean
    description: (* Indicates that an item recurs on Tuesday. *);
  end;

  object OnWed is boolean
    description: (* Indicates that an item recurs on Wednesday. *);
  end;

  object OnThu is boolean
    description: (* Indicates that an item recurs on Thursday. *);
  end;

  object OnFri is boolean
    description: (* Indicates that an item recurs on Friday. *);
  end;

  object OnSat is boolean
    description: (* Indicates that an item recurs on Saturday. *);
  end;


  object FirstWeekDetails is WeeklyDetails
    description: (*
        Scheduling details for the first week of a month.
    *);
  end;

  object SecondWeekDetails is WeeklyDetails
    description: (*
        Scheduling details for the second week of a month.
    *);
  end;

  object ThirdWeekDetails is WeeklyDetails
    description: (*
        Scheduling details for the third week of a month.
    *);
  end;

  object FourthWeekDetails is WeeklyDetails
    description: (*
        Scheduling details for the fourth week of a month.
    *);
  end;

  object FifthWeekDetails is WeeklyDetails
    description: (*
        Scheduling details for the fifth week of a month.
    *);
  end;

  object LastWeekDetails is WeeklyDetails
    description: (*
        Scheduling details for the last week of a month.
    *);
  end;

  object RecurringId is integer
    description: (*
        RecurringId is the unique identifier shared by all instances of a
        recurring item or multi-day event.  When a recurring item is scheduled,
        a collection of separate instances is created for each recurrence.
        When an instance is subsequently changed, the system may need to access
        all other instances in the collection.  The RecurringId is used for
        this purpose.  Viz., all instances in the same recurring collection
        have the same value for RecurringId.  Recurring Id is used in the same
        way for the multiple days of a multi-day event.
                                                                            <p>
        Using an integer representation for RecurringId is reasonable, since
        the exact representation is not directly visible to the user.  From the
        user's perspective, the requirements say that "the system keeps of
        instance collections as a whole, for the purposes of change and
        delete."  In this sense, a simple integer tag is a perfectly fine
        representation.
    *);
  end RecurringId;

  object Category is
    components: Name and StandardColor;
    description: (*
        A Category has a Name and StandardColor, which serve to distinguish it
        from other categories.  Colored-coded categories serve as visual cues
        to the user when viewing lists of scheduled items in some form.
        Categories can also be used in filtered viewing.
    *);
  end Category;

  object StandardColor is
    components: Black or Brown or Red or Orange or Yellow or Green or Blue or
        Purple;
    description: (*
        A StandardColor is one of a fixed set of possibilities.
    *);
  end StandardColor;

  object Black
    description: (* One of the built-in category colors. *);
  end;

  object Brown
    description: (* One of the built-in category colors. *);
  end;

  object Red
    description: (* One of the built-in category colors. *);
  end;

  object Orange
    description: (* One of the built-in category colors. *);
  end;

  object Yellow
    description: (* One of the built-in category colors. *);
  end;

  object Green
    description: (* One of the built-in category colors. *);
  end;

  object Blue
    description: (* One of the built-in category colors. *);
  end;

  object Purple
    description: (* One of the built-in category colors. *);
  end;

  object Location is string
    description: (*
        Location is a free-form string indicating in what physical location an
        item is scheduled.
    *);
  end Location;

  object Security is
    components: Public or TitleOnly or Confidential or Private;
    description: (*
        Security is one of four possible levels, from Public to Private.  The
        levels specify the degree of visibility an appointment or meeting has
        to other users.
    *);
  end Security;

  object Public
    description: (*
        Public security means other users can see the scheduled item and all of
        its component information.
    *);
  end Public;

  object TitleOnly
    description: (*
        TitleOnly security means other users can see title, time, and date
        components only.  TitleOnly security applies only to appointments and
        meetings.
    *);
  end Public;

  object Confidential
    description: (*
        Confidential security means other users can only see that a user is
        unavailable for the time period of a scheduled item; no other
        information about the scheduled item is visible.  Confidential security
        applies only to appointments and meetings.
    *);
  end;

  object Private
    description: (*
        Private security means other users see no information at all about a
        scheduled item, not even that the item is scheduled.  Note that private
        security hides a scheduled item from the ScheduleMeeting operation,
        q.v., so that a meeting may be scheduled at the same time as a private
        appointment.  It is up to the user to handle this situation by
        accepting or refusing the scheduled meeting.
    *);
  end;

  object SimpleSecurity is
    components: Public or Private;
    description: (*
        Simple security has only two levels -- public or private.  It applies
        to tasks and events.
    *);
  end SimpleSecurity;

  object Priority is
    components: Must or Optional;
    description: (*
        Priority indicates whether an appointment is a must or if it is
        optional.  This information is used to indicate the general importance
        of an appointment to the user.  The operational use of Priority is in
        the ScheduleMeeting operation, where the meeting scheduler can elect to
        consider optional appointments as allowable times for a meeting.
    *);
  end Priority;

  object Must
    description: (*
        Indicates a scheduled item is 'Must' priority.
    *);
  end;

  object Optional
    description: (*
        Indicates a scheduled item is 'Optional' priority.
    *);
  end;

  object TaskPriority is integer
    description: (*
        A TaskPriority is a positive integer that defines the priority of one
        task relative to others.  The priority value range is 0 to 10, with a
        higher value indicating a higher priority.
    *);
  end TaskPriority;

  axiom forall (tp: TaskPriority) tp >= 0;

  object RemindInfo is
    components: RemindWhen and RemindWhere;
    description: (*
        RemindInfo defines if, when, and where a scheduled item reminder is
        sent to the user.
    *);
  end RemindInfo;

  object RemindWhen is
    components: integer and ReminderTimeUnits;
    description: (*
        RemindWhen defines how soon before a scheduled item the reminder is to
        be sent.  The time units are minutes, hours, or days.
    *);
  end RemindInfo;

  object ReminderTimeUnits is
    components: MinutesBefore or HoursBefore or DaysBefore;
    description: (*
        Reminders can come minutes, hours, or days before the start time of a
        scheduled item.  Each of these units can be fractional, for maximum
        flexibility.
    *);
  end AppointmentReminderUnits;

  object MinutesBefore is real
    description: (*
        Number of minutes before a scheduled item to issue the reminder.
    *);
  end MinutesBefore;

  object HoursBefore is real
    description: (*
        Number of hours before a scheduled item to issue the reminder.
    *);
  end HoursBefore;

  object DaysBefore is real
    description: (*
        Number of days before a scheduled item to issue the reminder.
    *);
  end DaysBefore;

  object RemindWhere is OnScreen or BeepOnly or Email
    description: (*
        RemindInfo defines one of three ways that the user is alerted when a
        scheduled event is to occur.  OnScreen means the user is reminded with
        a pop-up alert on her computer screen.  BeepOnly means the user is
        reminded with a simple audible tone on the computer.  Email means the
        user is sent an electronic mail message reminder.
    *);
  end RemindInfo;

  object OnScreen
    description: (*
        Indicates that reminders are displayed in an on-screen pop-up window.
    *);
  end OnScreen;

  object BeepOnly
    description: (*
        Indicates that reminders are signaled with an audible beep only, with
        no pop-up window.
    *);
  end BeepOnly;

  object Email
    description: (*
        Indicates that reminders are send as email messages.
    *);
  end Email;

  object Details is string
    description: (*
        Details is a plain text string describing any details about a scheduled
        item the user may care to add.
    *);
  end Details;

  object Attendees
    components: Name*;
    description: (*
        Attendees is a list of names of those who attend a meeting.
    *);
  end Attendees;

  object Name is string
    description: (*
        The name of a category or a meeting attendee.
    *);
  end;

  object ScheduledBy is UserId
    description: (*
       ScheduledBy is the id of user who scheduled the meeting, i.e., the user
       who executed the ScheduleMeeting operation that led to the meeting being
       scheduled.
    *);
  end ScheduledBy;

  object ScheduledOn
    components: Date and Time;
    description: (*
       ScheduledOn is the date and time on which a meeting is scheduled.
    *);
  end ScheduledOn;



  object MeetingMinutesLocation is string
    description: (*
        MeetingMinutes is a plain text string that records the file or URL
        location of the minutes taken for a meeting.  The syntax of the
        location string is presumed to be compatible with the program that is
        used to view meeting minutes, as specified in the system options.  This
        syntax has no specific meaning to the Calendar Tool.
    *);
  end MeetingMinutes;

  object CompletedFlag is boolean
    description: (*
        CompletedFlag is true if a Task has been completed, false if not.  The
        system does not enforce any specific constraints on the setting of a
        task's CompletedFlag.  That is, the user may set or clear it at will.
        Hence the meaning of the CompletedFlag is subject to user
        interpretation, particularly for recurring tasks.
    *);
  end CompletionDate;

  object CompletionDate is
    components: Date;
    description: (*
        CompletionDate is date on which as task is completed.  The system does
        not enforce any specific constraints on the setting of a task's
        CompletionDate (other than it being a legal Date value).  The meaning
        of the CompletionDate value is up to user interpretation, particularly
        for recurring tasks.
    *);
  end CompletionDate;

  operation ScheduleAppointment is
    inputs: cdb:CalendarDB, appt:Appointment;
    outputs: cdb':CalendarDB;
    description: (*
        ScheduleAppointment adds the given Appointment to the current Calendar
        in the UserWorkSpace of the given CalendarDB.  The addition is made if
        an appointment of the same time, duration, and title is not already
        scheduled.  The RequiresSaving flag of the calendar is set to true.
    *);
    precondition:
        (*
         * The StartOrDueDate field is not empty and a valid date value.
         *)
        (appt.start_or_due_date != nil) and DateIsValid(appt.start_or_due_date)

            and

        (*
         * If non-empty, the EndDate field is a valid date value.
         *)
        (appt.end_date != nil) or DateIsValid(appt.end_date)

            and

        (*
         * The duration is between 1 minute and 999 hours, inclusive.
         *)
        DurationInRange(appt.duration)

            and

        (*
         * No appointment or meeting instance of the same StartTime, Duration,
         * and Title is in the current workspace calendar of the given
         * CalendarDB.  The current calendar is
         *
         *     cdb.workspace.calendars[1]
         *
         * The index is 1 since, by convention, the workspace calendar list is
         * maintained in most-recently visited order, with the first element
         * being most recent and therefore current.
         *)
        not (exists (item in cdb.workspace.calendars[1].items)
            (item.start_or_due_date = appt.start_or_due_date) and
            (item.<Appointment.duration = appt.duration) and
            (item.title = appt.title))
        ;
    postcondition:
        (*
         * A scheduled item is in the output calendar if and only if it is the
         * new appointment to be added or it is in the input calendar.  As
         * noted in the precond, the current calendar is
         *
         *     DB.workspace.calendars[1]
         *
         * where here in the postcond, DB is either cdb or cdb'.
         *)
        (forall (item:ScheduledItem)
            (item in cdb'.workspace.calendars[1].items) iff
                ((item.<Appointment = appt) or
                 (item in cdb'.workspace.calendars[1].items)))

            and

        (cdb'.workspace.calendars[1].requires_saving = true);

  end ScheduleAppointment;

  operation ScheduleMeeting is
    inputs: CalendarDB, MeetingRequest;
    outputs: PossibleMeetingTimes;
    description: (*
        ScheduleMeeting uses the given MeetingRequest to determine possible
        times that the requested meeting might be held, within the existing set
        of scheduled items in the CalendarDB.  The PossibleMeetingTimes output
        is a list of zero or more possible times and dates that the meeting can
        be held.
    *);
    precondition: (* User must be group leader *);
    postcondition: ;
  end ScheduleMeeting;

  (**
   * Something's gotta get fixed in this vicinity given that recurring
   * information is different for Meetings versus MeettingRequests.  In order
   * for a where clause sub of RecurringInfo to work, we gotta do some work to
   * distinguish recurring info for meetings versus meeting requests.
   *)
  object MeetingRequest inherits from Meeting
    where: StartDate = EarliestStartDate, EndDate=LatestEndDate,
        StartTime=EarliestStartTime;
    components: LatestStartDate and LatestEndDate and LatestStartTime;
    description: (*
        A meeting request has all the components of a meeting plus three
        additional components to specify the latest dates and time at which the
        meeting can be scheduled.  A meeting request is used to specify a range
        of possible meeting times, to allow scheduling alternatives to be
        considered.  The description of the ScheduleMeeting operation has
        further details on how meeting requests are handled.
    *);
  end MeetingRequest;

  object EarliestStartDate is Date
    description: (*
        In a meeting request, the earliest possible start date for the meeting
        to be scheduled.
    *);
  end;

  object LatestStartDate is Date
    description: (*
        In a meeting request, the latest possible start date for the meeting to
        be scheduled.
    *);
  end;

  object EarliestEndDate is Date
    description: (*
        In a meeting request, the earliest possible end date for a recurring
        meeting to be scheduled.
    *);
  end;

  object LatestEndDate is Date
    description: (*
        In a meeting request, the latest possible end date for a recurring
        meeting to be scheduled.
    *);
  end;

  object EarliestStartTime is Time
    description: (*
        In a meeting request, the earliest possible start time for the meeting
        to be scheduled.
    *);
  end;

  object LatestStartTime is Time
    description: (*
        In a meeting request, the latest possible start time for the meeting to
        be scheduled.
    *);
  end;

  object PossibleMeetingTimes is (StartTime and Date)*;

  operation ConfirmMeeting is
    inputs: CalendarDB, MeetingRequest, PossibleMeetingTimes, SelectedTime;
    outputs: CalendarDB;
    description: (*
        ConfirmMeeting takes a CalendarDB, MeetingRequest, list of
        PossibleMeetingTimes, and a Selected time from the list.  It outputs a
        new CalendarDB with the given request scheduled at the selected time.
        Further details of output constraints are forthcoming.
    *);
    precondition: ;
    postcondition: ;
  end ConfirmMeeting;

  object SelectedTime is integer;

  operation ScheduleTask is
    inputs: CalendarDB, Task;
    outputs: ;
    description: (*
        ScheduleTask adds the given Task to the given CalendarDB, if a task of
        the same time, duration, and title is not already scheduled.
    *);
    precondition: ;
    postcondition: ;
  end ScheduleTask;

  operation ScheduleEvent is
    inputs: cdb:CalendarDB, e:Event;
    outputs: cdb':CalendarDB;
    description: (*
        ScheduleEvent adds the given Event to the given CalendarDB, if an event
        of the same start date and title is not already scheduled.
    *);
    precondition:
        (*
         * The Title field is at least one character long.
         *)
        (#(e.title) >= 1)

            and

        (*
         * The StartOrDueDate field is not empty and a valid date value.
         *)
        (e.start_or_due_date != nil) and DateIsValid(e.start_or_due_date)

            and

        (*
         * If non-empty, the EndDate field is a valid date value.
         *)
        (e.end_date != nil) or DateIsValid(e.end_date)

            and

        (*
         * The current workspace is not nil.
         *)
        (cdb.workspace.calendars != nil)

            and

        (*
         * No event of same StartDate and Title is in the current workspace
         * calendar of the given CalendarDB.  The current calendar is
         *
         *     cdb.workspace.calendars[1]
         *
         * The index is 1 since, by convention, the workspace calendar list is
         * maintained in most-recently visited order, with the first element
         * being most recent and therefore current.
         *)
        not (exists (item in cdb.workspace.calendars[1].items)
            (item.start_or_due_date = e.start_or_due_date) and
            (item.title = e.title))
        ;
    postcondition:
        (*
         * A scheduled item is in the output calendar if and only if it is the
         * new event to be added or it is in the input calendar.  As noted in
         * the precond, the current calendar is
         *
         *     DB.workspace.calendars[1]
         *
         * where here in the postcond, DB is either cdb or cdb'.
         *)
        (forall (item:ScheduledItem)
            (item in cdb'.workspace.calendars[1].items) iff
                ((item.<Event = e) or
                 (item in cdb'.workspace.calendars[1].items)))

            and

        (cdb'.workspace.calendars[1].requires_saving = true);
  end ScheduleEvent;


  operation ChangeItem is
    inputs: cdb:CalendarDB, si_old:ScheduledItem, si_new:ScheduledItem;
    outputs:  cdb':CalendarDB;
    description: (*
        ChangeItem changes the given old item to the given new item in the
        given CalendarDB.
    *);
    precondition: ;
    postcondition: ;
  end ChangeItem;

  operation DeleteItem is
    inputs: cdb:CalendarDB, si:ScheduledItem;
    outputs: cdb':CalendarDB;
    description: (*
        DeleteItem deletes the given item from the given CalendarDB.
    *);
    precondition: ;
    postcondition: ;
  end DeleteItem;


  (**
   * Auxiliary functions.
   *)
  function DateIsValid(date:Date)->boolean = (

    (*
     * The date number is between one and the proper month-specific upper
     * bound.
     *)
    (date.number >= 1) and DateNumUpperBoundIsValid(
        date.number, date.month, date.year)

        and

    (*
     * The year is between 1 and 9999.
     *)
    (date.year >= 1) and (date.year <= 9999);

    )
    description: (*
        Auxiliary function that specifies date validity.
    *);
  end;

  function DateNumUpperBoundIsValid(num:DateNumber, month:MonthName,
        year:Year)->boolean = (

    (*
     * 30 days has September, and all that ... .
     *)

    (*
     * Upper bound for jan, mar, may, jul,aug, oct, and dec is 31 days.
     *)
    if (month?jan or month?mar or month?may or month?jul or month?aug or
        month?oct or month?dec)
    then num <= 31
    else

        (*
         * Upper bound for apr, jun, sep, and nov is 30 days.
         *)
        if (month?apr or month?jun or month?sep or month?nov)
        then num <= 30
        else (* Month is feb *)

            (*
             * Upper bound for feb is 29 if leap year, 28 if not.
             *)
            if IsLeapYear(year)
            then num <= 29
            else num <= 28;
    )
    description: (*
        Auxiliary function that specifies valid upper bound for day number
        component of a date.
    *);
  end;

  function IsLeapYear(year:Year)->boolean = (

    (*
     * The year is divisible by 4 but not by 400.
     *)
    (year mod 4 = 0) and (year mod 400 != 0);

    )
    description: (*
        Auxiliary function that specifies leap year definition.
    *);
  end;

  function DurationInRange(duration:Duration)->boolean = (

    (*
     * Both the hours and minutes fields must be non-negative.
     *)
    (duration.hours > 0) and (duration.minutes > 0)

        and

    (*
     * The maximum duration is 999 hours.
     *)
    (duration.hours + duration.minutes/60 <= 999);

    (*
     * Note that there is no specific upper bound on the minutes field.
     *)

    )
    description: (*
        Auxiliary function that specifies range criteria for the duration of a
        scheduled item.
    *);
  end;

end Schedule;





Prev: [none] | Next: caldb.rsl | Up: spec | Top: index