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 EasyGrader 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 FileSpace = File*
    description: (*
        A FileSpace is an abstract model of a file space in the operating
        environment in which the EasyGrader is run.  The FileSpace is simply
        a collection of zero or more Files, with no other properties modeled
        here.
    *);
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 = gradebook_type:GraderType or other_type:OtherType
    description: (*
        The type of file data is either GraderType data, TemplateType data
        , or any other type of data.
    *);
end FileType;

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

object OtherType
    description: (*
        File data typing tag indicating that a file contains data other than
        grader data created by the EasyGrader.
    *);
end OtherType;

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

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

operation new
    inputs: eg:EasyGrader;
    outputs: eg':EasyGrader;

    description: (*
        Add a new empty Gradebook to the EasyGrader.
    *);

    precondition: ;
    postcondition: 
        (exists (gb:Gradebook)
            (gb.sections = nil) and
            (gb = eg'.gradebooks[1]) and
            (gb.items = nil) and
            (gb.FinalGrade = nil) and
            (gb.name = nil) and
            (gb.sortedByItem = nil) and
            (gb.curve = nil) and
            (gb.userCredentials = nil));
end new;

operation open
    inputs: fs:FileSpace, fn:FileName, eg:EasyGrader;
    outputs: eg':EasyGrader;
    precondition:
        (*
         * file extension is correct
         * file is readable
         * file name is right
         *)
        (exists (file in fs)
            (file.name = fn) and
            file.permissions.is_readable and
            file.file_type?.gradebook_type
        );
    postcondition:
        (exists (gb:Gradebook)
            (gb = eg'.gradebooks[1]) and
            (exists (file in fs)
                (file.name = fn) and
                (gb = file.data)
            ) and
            (forall (i:integer | (i >= 2) and (i <= #(eg.gradebooks)))
                eg'.gradebooks[i+1] = eg.gradebooks[i+1]
            )
         );
    description: (*
       Reads from a .egb file and set it up as a gradebook
    *);
end open;

operation save
    inputs: fs:FileSpace, eg:EasyGrader;
    outputs: fs':FileSpace, eg':EasyGrader;
    precondition:
        (exists (file in fs)
            (file.name = eg.gradebooks[1].filename) and
            (file.data != eg.gradebooks[1]) and
            (file.permissions.is_writable));
    postcondition:
        (*
         * Current Gradebook is saved
         *)
        (exists (file in fs')
            (file.name = eg'.gradebooks[1].filename) and
            (file.data = eg'.gradebooks[1]) and
            (file.permissions.is_writable) and
            (file.file_type?.gradebook_type)
        );
    description:
    (*
     * Write the current gradebook into a file;
     * Replace the older file;
     *);
end save;

operation saveAs
    inputs: fs:FileSpace, eg:EasyGrader, filename:string;
    outputs: fs':FileSpace, eg':EasyGrader;
    precondition:
        (not exists (file in fs)
            (file.name = eg.gradebooks[1].filename) and
            (file.data != eg.gradebooks[1]) and
            (file.permissions.is_writable));
    postcondition:
        (*
         * Current Gradebook is saved
         *)
        (exists (file in fs')
            (filename = eg'.gradebooks[1].filename) and
            (file.data = eg'.gradebooks[1]) and
            (file.permissions.is_writable) and
            (file.file_type?.gradebook_type)
        );
    description:
        (*
         * Write the current gradebook into a file on the specified path;
         * Prompt to replace file if the file name exists;
         *);
end saveAs;

operation dlRoster
    inputs: c:Credentials;
    outputs: gb:Gradebook;
    precondition:       
        (*
	 * The Credentials are correct and no fields are left blank to first
	 * connect to SIS.
	 *)      
        (c.userName != nil)
             and
        (c.password != nil)
             and
        (c.server != nil);
    postcondition: ;
    description:
    	(*
	 * The instructor downloads the roster to create a Gradebook. 
         *);
end dlRoster;

operation syncRoster
    inputs: gb:Gradebook, c:Credentials;
    outputs: gb':Gradebook;
    precondition:
        (*
	 * The Credentials are correct and no fields are left blank to first connect to SIS.
         * Displays the current and updated roster.
         * For all students not on the updated roster, their names are in
         * red on the current roster. For all students not on the current
         * roster, their names are in red on the updated roster.
         *)      
        ((c.userName != nil) and (c.password != nil) and (c.server != nil));
    postcondition: (* The instructor has an updated roster *);
    description:
        (*
	 * The current roster and the updated roster from SIS are available for the instructor to compare.
         * This is used for the instructor to add new students from the updated roster, drop old students from the
         * old roster, or keep students the instructor personally added that the updated roster does not have.
         *);
end syncRoster;

operation merge
	inputs: fs:FileSpace, fn:FileName*, eg:EasyGrader;
	outputs: eg':EasyGrader;
	precondition: 
	    (*
	     * file extension is correct
	     * files are readable
	     * file names are right
	     *)
            (forall (i: integer | (i >= 1) and (i <= #fn))
	        (exists (file in fs)
	            (file.name = fn[i]) and
		    file.permissions.is_readable and
		    file.file_type?.gradebook_type
	        )
            );
	postcondition:
       	    (exists (gb:Gradebook)
	         (gb = eg'.gradebooks[1]) and
                 (forall (j:integer | (j >= 1) and (j <= #fn))
		    (exists (file in fs)
                        (file.name = fn[j])
		        (* file.data is element of gb*)
                    )
		 ) and
		 (forall (k:integer | (k >=2) and (k <= #(eg.gradebooks)))
		      eg'.gradebooks[k+1] = eg.gradebooks[k+1]
		 )
            );
	description: (*
	      Reads from multiple .egb files and set it up as one single gradebook
	*);
end merge;

operation submitGrades
    inputs: gb:Gradebook, c:Credentials;
    outputs: gb':Gradebook;
    precondition:
        (* The Credentials are correct and no fields are left blank *)      
        ((c.userName != nil) and
        (c.password != nil) and
        (c.server != nil));
    postcondition: ;
    description: (*
       Students' final grades are uploaded to the SIS server.
    *);
end submitGrades;


operation post_grades
    inputs: c:Credentials;
    outputs: gb':Gradebook;
    precondition:
        (* The Credentials are correct and no fields are left blank *)
        (c.userName != nil)
             and
        (c.password != nil)
             and
        (c.server != nil);
    postcondition: ;
    description:
	(*
	 * The current gradebook in focus in uploaded to department server. 
	 *);
end post_grades;

operation fetch
    inputs: c:Credentials;
    outputs: eg':EasyGrader;
    precondition:
        (* The Credentials are correct and no fields are left blank *)
        (c.userName != nil)
             and
        (c.password != nil)
             and
        (c.server != nil);
    postcondition: (* For each roster downloaded, a Gradebook is created *)
        (exists (gb:Gradebook)
            (gb = eg'.gradebooks[1]) and
            (forall (i:integer | (i >= 2) and (i <= #(eg.gradebooks)))
                eg'.gradebooks[i+1] = eg.gradebooks[i+1]
            )
         );
description:
	(*
	 * Creates a Gradebook for each roster that is downloaded.
	 *);
end fetch;

operation pageSetup
    inputs: ps:PageSetup;
    outputs: ps':PageSetup;
    precondition:
        (*
         * ps:PageSetup is the previous PageSetup being passed in.
         *);
    postcondition:
        (*
         * The user changes the old page setup and save it.
         *)
        (ps = ps');
    description: (*
        Sets up the printer settings
    *);
end pageSetup;

operation printPreview
    inputs: gb:Gradebook;
    outputs: gb':Gradebook;
    precondition: ;
    postcondition:
        (* Nothing is changed in preview *)
        (gb = gb');
    description:
	(*
	 * Preview for the printed format of the Gradebook
	 *);
end printPreview;

operation print
    inputs: gb:Gradebook;
    outputs: gb':Gradebook;
    precondition: ;
    postcondition: ;
    description:
	(*
	 * Prints the current Gradebook
	 *);
end print;