(****
 *
 * Module File defines the objects and operations related to file processing
 * in the calendar system.
 *
 *)

module File;

from ScheduleDB import ScheduleDB;

  object UserWorkspace is
      components: uid:UserID and schedules:UserSchedule* and previous_state:PreviousState;
      description: (*
                   This is the user workspace that contains the UserSchedule which is the current schedule that the user is working on
                   This contains the information about what the file name is of the schedule that the user is working on
                   and the user that is working on the file.
      *);
   end;
  object PreviousState is
      components: ScheduleDB*;
      description: (*
			           This is used incase the admin does not want to save the changes that they have made to the database.
                    This way a admin can revert back to a certain state or point in which the schedule was generated
                    This is also helpful if the teacher creates a schedule and then doesn't like it.
      *);
  end;
  object UserSchedule is
      components:  file:UserScheduleFileName* and requires_saving:RequiresSaving and uid:UserID;
      description: (*
                     This contains the file that the  user is working on in the given workspace.
   						Given the user id also this tell who is working on the schedule.  If there are multiple admins
 							this could narrow down who is making the changes the schedule.
      *);
  end;

  object UserScheduleFileName is 
      components: name:FileName;
      description: (*
							This is the file name of schedule being accessed is the User workspace.
		*);
  end;

  object RequiresSaving is boolean
      description: (*
  						   This tell if the schedule has been modified so that if the user goes to close the schedule without
 							having saved yet, the program will prompt the user to save the schedule.  That way no changes are made
 							that get left out becuase the user left the program without saving.
		*);
  end;

  object UserID  is integer
		description: (*
						  This defines the UserID that is working on the schedules currently in the program.
		*);
  end;

  object FileSpace = File*
    description: (*
        A FileSpace is an abstract model of a file space in the operating
        environment in which the CalendarTool is run.  The FileSpace is simply
        a collection of zero or more Files, with no other properties modeled
        here.
     *);
  end;

  object File
    components: name:FileName and permissions:FilePermissions and
        file_type:FileType and size:FileSize and data:FileData;
    description: (*
        A File is an abstraction of a file stored in the file space.  It has a
        name, permissions, type, and data.  These are the components sufficient
        to specify the behavior of Schedule Tool file operations.
    *);
  end File;

  object FileName = string
    description: (*
        The name of a file.  The string representation here is an abstraction
        of file names used in specific operating environments.  Implementations
        may obey any syntactic or semantic constraints imposed by a particular
        environment.
    *);
  end;

  object FilePermissions = is_readable:IsReadable and is_writable:IsWritable
    description: (*
        FilePermissions indicate whether a file is readable and/or writable.
    *);
  end;

  object IsReadable = boolean
    description: (*
        Flag indicating whether a file is readable, which is required to be
        true by the FileOpen operation.
    *);
  end;

  object IsWritable = boolean
    description: (*
        Flag indicating whether a file is writable, which is required to be
        true by the FileSave operation.
    *);
  end;

  object FileType = schedule_type:ScheduleType 
    description: (*
        The type of file data is either CalendarType data (which we care
        about), SettingsType data (which we also care about), or any other
        type of data (which we don't care about).
    *);
  end FileType;

  object ScheduleType is boolean
		description: (*
							This tell if the program can open the type of file.   If the type of file is not a Schedule then the program
							will not be able to read the file correctly and display the correct information about the databases.
						   This way the program will not open xcel or word files and try to create a database off of bad information.
		*);
  end;

  object CalendarType
    description: (*
        File data typing tag indicating that a file contains calendar data
        created by the Calendar Tool.
    *);
  end CalendarType;

  object FileSize = integer
    description: (*
       The size in megabytes of a file.
    *);
  end FileSize;

  object FileData = UserSchedule
    description: (*
        The abstract representation of schedule-type FileData is a UserSchedule
        object.  Schedule Tool implementors may use any concrete file data
        representation that accurately holds all UserSchedule components.
    *);
  end FileData;



   obj Quarter is string
		description: (*
							This is sed to define in the name of the schedule what quarter the schedule is for.
		*);
   end;

   obj Year is integer
		description: (*
							This is used to define in the name of the schedule what year the schedule is for.
		*);
   end;
   obj Revision = integer;

  operation FileNewFromScratch  
    inputs: Quarter and Year and Revision and fs:FileSpace and fn:FileName and uws:UserWorkspace;
    outputs: uws':UserWorkspace;
    precondition: not ( exists (file in fs)
								(file.name = fn) );
    postcondition:
        (exists (uc:UserSchedule)
            (uc = uws'.schedules[1]) and
            (exists (file in fs)
                (file.name = fn) and
                (uc = file.data)
            ) and
            (uc.uid = uws.uid) and
            (not uc.requires_saving) and
            (#(uws'.schedules) = #(uws.schedules) +1) and
            (forall (i:integer | (i >= 2) and (i <= #(uws.schedules)))
                uws'.schedules[i+1] = uws.schedules[i+1]
            )
			);
    description: (*
                  * This takes in the name of what the new schedule is to be called and creates a schedule
                  * with temp databases layout allowing the user to add entries into the temp database.
    *);
  end FileNewFromScratch;

  operation FileOpen
    inputs: fs:FileSpace and fn:FileName and uws:UserWorkspace;
    outputs: uws':UserWorkspace;
    precondition: exists (file in fs)
            (file.name = fn) and
            file.permissions.is_readable and
            file.file_type.schedule_type;
    postcondition: 
        (*
         * The output workspace has a new schedule containing the file data of
         * the input file, and that schedule is current.  The user id of the
         * new schedule is that of the workspace, the options are the given
         * global options input, and the schedule does not require saving.  The
         * schedules in positions 1-last in the the input workspace are in
         * positions 2-last+1 in the output workspace.
         *)
        (exists (uc:UserSchedule)
            (uc = uws'.schedules[1]) and
            (exists (file in fs)
                (file.name = fn) and
                (uc = file.data)
            ) and
            (uc.uid = uws.uid) and
            (not uc.requires_saving) and
            (#(uws'.schedules) = #(uws.schedules) +1) and
            (forall (i:integer | (i >= 2) and (i <= #(uws.schedules)))
                uws'.schedules[i+1] = uws.schedules[i+1]
            )
        );
    description: (*File Open opens a file from disk and populates all windows with the correct data*);
  end FileOpen;

  operation FileClose
    inputs: fs:FileSpace, uws:UserWorkspace;
    outputs: uws':UserWorkspace;
    precondition:
         (*The schedule does not require saving.*)
    not (uws.schedules[1].requires_saving);
    postcondition: 
         (*
          * The current schedule is deleted from the workspace.  the remaining
          * schedules, if any, are shifted in position in the list one position
          * earlier.
          *)
          (not (uws.schedules[1] in uws'.schedules)) and
          (#(uws'.schedules) = #(uws.schedules) - 1) and
          (forall (i:integer | (i >= 1) and (i < #(uws.schedules)))
             uws'.schedules[i] = uws.schedules[i+1];
          );

    description: (*
	      Close the current schedule if it does not require saving
    *);
  end FileClose;

operation FileSave
    inputs: fs:FileSpace, uws:UserWorkspace;
    outputs: fs':FileSpace, uws':UserWorkspace;

    description: (*
        If the schedule in the given workspace requires saving, save it in the
        given file space.
    *);

    precondition:
        (*
         * The given workspace requires saving.  Also, there is a writable
         * file of the current workspace filename in the given FileSpace.  Note
         * that the only way the current file could be unwritable is through an
         * external change to the file space since the file was opened by the
         * Schedule Tool.  Note further that this precondition disallows the
         * case where the current schedule file has been externally deleted
         * since it was opened by the schedule tool.  That is, the file must
         * both exist and be writable at the time the save is attempted.
         *)
        (uws.schedules[1].requires_saving)
            and
        (exists (file in fs)
            (file.name = uws.schedules[1].file[1].name) and
            (file.permissions.is_writable));

    postcondition:
        (*
         * There is a schedule-type file in the resulting FileSpace containing
         * the current workspace schedule as its file data.  In the resulting
         * workspace, the requires saving indicator is false.
         *)
        (exists (file in fs')
            (file.name = uws'.schedules[1].file[1].name) and
            (file.data = uws'.schedules[1]) and
            (file.permissions.is_writable) and
            (file.file_type.schedule_type) and
            (not uws'.schedules[1].requires_saving)
        );
  end FileSave;

end File;