/*
 *
 * This file defines objects and operations related to calendar scheduling.
 * See Sections 2.2, 2.4, and 2.5 of the Milestone 6 requirements.
 *
 */

import java.util.Collection;

/**
 * The Calendar object is derived from an overall view of Sections 2.1 through
 * 2.5 of the requirements.  The functionality described in those sections
 * makes it clear that a Calendar is the primarily data object of the Calendar
 * Tool.
 *
 * The data component of a Calendar is a collection of scheduled items.  The
 * operations are those that schedule each of the four types of scheduled
 * item.  In the case of meetings, there are two operations involved -- one to
 * compute a list of possible times, and another to confirm a specific selected
 * meeting time.
 */
abstract class Calendar {

    Collection<ScheduledItem> items;

    /**
     * ScheduleAppointment adds the given Appointment to this.data, if an
     * appointment of the same time, duration, and title is not already
     * scheduled.
     */
    abstract void scheduleAppointment(Appointment appointment);

    /**
     * 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 this.data.  The PossibleMeetingTimes output is
     * a list of zero or more possible times and dates that the meeting can be
     * held.
     */
    abstract PossibleMeetingTimes scheduleMeeting(
        MeetingRequest meetingRequest);

    /**
     * ConfirmMeeting takes a MeetingRequest, list of PossibleMeetingTimes, and
     * a Selected time from the list.  It adds a meeting to this.data,
     * comprised of the given request, scheduled at the selected time.  Further
     * details of output constraints are forthcoming.
     */
    abstract void confirmMeeting(
        MeetingRequest request,
        PossibleMeetingTimes times,
        int selectedTime);

    /**
     * ScheduleTask adds the given Task to this.data, if a task of the same
     * time, duration, and title is not already scheduled.
     */
    abstract void scheduleTask(Task task);

    /**
     * ScheduleEvent adds the given Event to this.data, if an event of the same
     * time, duration, and title is not already scheduled.
     */
    /*@
      requires
        //
        // The Title field is not empty.
        //
        (event.title != null && event.title.length() >= 1)

            &&

        //
        // The startOrDueDate field is a valid date value.
        //
        (event.startOrDueDate != null) && event.startOrDueDate.isValid()

            &&

        //
        // If non-empty, the EndDate field is a valid date value.
        //
        (event.endDate != null) ==> event.endDate.isValid()

            &&

        //
        // The current workspace is not null.
        //
        (calDB.getCurrentCalendar() != null)

            &&

        //
        // No event of same startDate and title is in the current workspace
        // calendar.
        //
        ! (\exists ScheduledItem item ; 
            calDB.getCurrentCalendar().items.contains(item) ;
                (item.startOrDueDate.equals(event.startOrDueDate)) &&
                item.duration.equals(event.duration) &&
                (item.title.equals(event.title)));

      ensures
        //
        // If preconds met, a scheduled item is in the output calendar if
        // and only if it is the new appt to be added or it is in the 
        // input calendar.
        //
        (\forall ScheduledItem item;
            \old(calDB).getCurrentCalendar().items.contains(item) <==>
                (item == event ||
                 \old(calDB).getCurrentCalendar().items.contains(item)))

            &&

        //
        // Also, requiresSaving is true in the output calendar.
        //
        calDB.getCurrentCalendar().requiresSaving;
     @*/
    abstract void scheduleEvent(Event event);

    CalendarDB calDB;
    boolean requiresSaving;
}

/**
 * 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.
 *                                                                           <p>
 * There are four extensions of ScheduledItem.  They are Appointment, Meeting,
 * Task, and Event.  A ScheduledItem is derived from examining the common data
 * fields of these four types of item, and the requirements narrative that
 * describes these items.
 *                                                                           <p>
 * The startOrDueDate is a multi-purpose component of ScheduledItem.  Its
 * purpose depends on whether an item is a Task and whether it is recurring
 * (Events cannot recur).  For non-recurring appointments and meetings,
 * StartOrDueDate is used as the single date on which the item is scheduled.
 * If the item is recurring, 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.
 *                                                                           <p>
 * In recurring appointments, meetings, and tasks, the endDate 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.
 */
abstract class ScheduledItem {
    String title;
    Date startOrDueDate;
    Date endDate;
    Category category;
    Duration duration;
}

/**
 * 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 Location is where it is held.  The Security indicates who can
 * see that the appointment is scheduled.  AppointmentPriority 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.
 *                                                                           <p>
 * This object is derived from Section 2.2 of the Milestone 6 requirements, in
 * particular Figure 6.
 */
abstract class Appointment extends ScheduledItem {
    Time startTime;
    Duration duration;
    RecurringInfo recurringInfo;
    Location location;
    Security security;
    AppointmentPriority priority;
    RemindInfo remind;
    Text details;
}

/**
 * A Meeting adds two 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 MeetingMinutes component
 * is a URL for the minutes of a meeting, once it has been held.
 *                                                                           <p>
 * This object is derived from Section 2.4.1 of the Milestone 6 requirements, in
 * particular Figure 46.
 */
abstract class Meeting extends Appointment {
    Attendees attendees;
    MeetingMinutes minutes;
}

/**
 * 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.  In the meeting
 * request, the inherited fields for startDate, endDate, and time are used for
 * the earliest dates and time at which the meeting can be held, i.e., for the
 * beginning values of each range.  The description of the ScheduleMeeting
 * operation has further details on how meeting requests are handled.
 *                                                                           <p>
 * This object is derived from Section 2.4.1 of the Milestone 6 requirements,
 * in particular Figure 45.
 */
abstract class MeetingRequest extends Meeting {
    Date latestStartDate;
    Date latestEndDate;
    Time latestStartTime;
}

/**
 * The PossibleMeetingTimes object is a collection of (start time, start date)
 * pairs at which a meeting could be held.
 */
abstract class PossibleMeetingTimes {
    Collection<TimeAndDate> timesAndDates;
}

/**
 * A TimeAndDate object is an element of a possible meeting time list.
 */
class TimeAndDate {
    Time startTime;
    Date startDate;
}

/**
 * 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 StartTime, 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) For appointments, reminders can be set to
 * occur at hour or minute granularity; for tasks, the smallest granularity of
 * reminder is a day.  (4) Tasks have a completedFlag, and completionDate
 * components; appointments do not.
 *                                                                           <p>
 * The 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 up to user interpretation, particularly for
 * recurring tasks.
 *                                                                           <p>
 * The completionDate is the 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).  As with the
 * completedFlag, the meaning of the completionDate value is up to user
 * interpretation, particularly for recurring tasks.
 *                                                                           <p>
 * This object is derived from Section 2.4.2 of the Milestone 6 requirements,
 * in particular Figure 47.
 */
abstract class Task extends ScheduledItem {
    RecurringInfo recurringInfo;
    Security security;
    TaskPriority priority;
    TaskRemindInfo remind;
    Text details;
    boolean completedFlag;
    Date completionDate;
}

/**
 * An Event is the simplest type of ScheduledItem.  The only component it adds
 * to is Location.
 *                                                                           <p>
 * This object is derived from Section 2.4.3 of the Milestone 6 requirements,
 * in particular Figure 48.
 */
abstract class Event extends ScheduledItem {
    Location location;
    Duration duration;
}

/**
 * An AppointmentPriority 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 AppointmentPriority is
 * in the ScheduleMeeting operation, where the meeting scheduler can elect to
 * consider optional appointments as allowable times for a meeting.
 */
enum AppointmentPriority {
    Must,
    Optional
}

/**
 * A TaskPriority is a positive integer that defines the priority of one
 * task relative to others.  It's defined as a separate class in case we want
 * to enforce the value range restriction within the class constructor.
 */
abstract class TaskPriority {
    int value;
}

/**
 * For now, a Date is just as string.  This definition will expand soon.
 */
abstract class Date {
    String value;

    /**
     * Aux function used in scheduleEvent specs.
     */
    abstract boolean isValid();
}

/**
 * Duration is the time length of a scheduled item, in hours and minutes.
 */
abstract class Duration {
    int Hours;
    int Minutes;
}

/**
 * As with Date, Time is for now just as string.  This definition will expand
 * soon.
 */
abstract class Time {
    String value;
}

/**
 * RecurringInfo has components to specify the nature of a recurring item.  The
 * isRecurring component is an on/off flag that indicates whether an item
 * recurs.  The interval is one of Weekly, Biweekly, Monthly, or Yearly.  The
 * IntervalDetails component defines the precise means to define recurrence for
 * the different interval levels.
 */
abstract class RecurringInfo {
    boolean isRecurring;
    Interval interval;
    IntervalDetails details;
}

/**
 * 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.
 */
enum Interval {
    Weekly, Biweekly, Monthly, Yearly
}

/**
 * IntervalDetails are either weekly or monthly.  This parent class is used
 * generically for either kind of details.
 */
abstract class IntervalDetails {}

/**
 * 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.
 */
abstract class WeeklyDetails extends IntervalDetails {
    int onSun;
    int onMon;
    int onTue;
    int onWed;
    int onThu;
    int onFri;
    int onSat;
}

/**
 * MonthlyDetails can be specified on a day-of-the-week basis or on specific
 * date(s) basis.  The two extending classes have the specific details for these
 * two types of settings.  This parent class is used generically for either
 * kind of details.
 */
abstract class MonthlyDetails {}


/*
 * 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.)
 */
abstract class MonthlyDayDetails extends MonthlyDetails {
    WeeklyDetails firstWeekDetails;
    WeeklyDetails secondWeekDetails;
    WeeklyDetails thirdWeekDetails;
    WeeklyDetails fourthWeekDetails;
    WeeklyDetails fifthWeekDetails;
    WeeklyDetails lastWeekDetails;
}

/**
 * MonthlyDateDetails is a collection of zero or more specific dates in a month
 * on which an item recurs.
 */
abstract class MonthlyDateDetails extends MonthlyDetails {
    Collection<DateNumber> dates;
}

/**
 * A DateNumber is a positive integer between 1 and 31.  It's defined as a
 * separate class in case we want to enforce the value range restriction within
 * the class constructor.
 */
abstract class DateNumber {
    int value;
}

/**
 * A Category has a name and StandardColor, which serve distinguish it from
 * other categories.  Colored-coded categories serve visual cues to the user
 * when viewing lists of scheduled items in some form.  Categories can also be
 * used in filtered viewing.
 */
abstract class Category {
    String name;
    StandardColor color;
}

/**
 * A StandardColor is one of a fixed set of possibilities, per the requirements
 * scenarios.
 */
enum StandardColor {
   Black, Brown, Red, Orange, Yellow, Green, Blue, Purple
}

/**
 * For now a Location is a free-form string indicating in what physical
 * location an item is scheduled.  It may be refined to something like
 * (building,room) pair.
 */
abstract class Location {
    String value;
}

/**
 * Security is one of four possible levels, each of which is described
 * individually in the body of the enum.  The selected level specifies the
 * degree of visibility a scheduled item has to other users.  For an
 * appointment, task, or event, "other users" are defined as all users other
 * than the user on whose calendar the scheduled item appears.  For a meeting,
 * "other users" are defined as all users not on the Attendee list of the
 * meeting.
 */
enum Security {
   
    /**
     * Public security means other users can see the scheduled item and all the
     * information about the item.
     */
    Public,

    /*
     * PublicTitle security means other users can see the title of the
     * scheduled item but none of the other information about the item.
     */
    PublicTitle,

    /**
     * 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.  Since confidential
     * security applies to a specific time period, it is meaningful only for
     * appointments and meetings, not for tasks or events; tasks and events do
     * not have specific time components.
     */
    Confidential,
    
    /**
     * 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.  Given the nature of
     * private security, it does not apply to meetings.  I.e., only
     * appointments can have private security.
     */
    Private
}

/**
 * RemindInfo has a flag that indicates if a scheduled item will have a
 * reminder sent and 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.
 */
abstract class RemindInfo {
    boolean isReminded;
    HowReminded howReminded;
}

enum HowReminded {    
  OnScreen,
  BeepOnly,
  Email
}

/**
 * AppointmentRemindInfo extends RemindInfo by adding information for how
 * soon before a scheduled item the reminder is to be sent.  For appointments,
 * the time units are minutes, hours, or days (cf. TaskRemindInfo).
 */
abstract class AppointmentRemindInfo extends RemindInfo {
    double howSoonBefore;
    AppointmentReminderUnits units;
}

/**
 * TaskRemindInfo extends RemindInfo by adding information for how soon before
 * a task the reminder is to be sent.  For tasks, the time unit is days.  A
 * fractional day can be used for smaller granularity if desired.
 */
abstract class TaskRemindInfo extends RemindInfo {
    double howSoonBefore;
}

/**
 * Appointment reminders can come minutes, hours, or days before an
 * appointment.  The units for these can be fractional, for maximum
 * flexibility.
 */
enum AppointmentReminderUnits {
    MinutesBefore, HoursBefore, DaysBefore
}

/**
 * Attendees is a collection of names of those who attend a meeting.
 */
abstract class Attendees {
    Collection<String> names;
}

/**
 * MeetingMinutes is current defined as the URL for the location of the minutes
 * of a meeting.  This definition may be refined in upcoming versions of the
 * requirements.
 */
abstract class MeetingMinutes {
    String url;
}

/**
 * The details of the Text object are TBD.  It may just turn out to be a
 * plain string.  Or it may a limited form of HTML, so we can include linkable
 * URLs in it.
 */
abstract class Text {}