(* Schedule Management *)

module ScheduleManagement;

	from ScheduleM import all;

	object Server is
	    components: sl: ScheduleList;
	    description: (* This represents the server which contains a list of schedules. *);
	end Server;

	object UserComputer is
	    components: sl: ScheduleList and ut: UserType and id: string;
	    description: (* This represents the list of schedules that is located on a user's computer.
	                    It includes the type of user whose computer it is and the
	                    user name of that user. *);
	end UserComputer;

	object UserType is
	    components: Admin or Instructor or Student;
	    description: (* The type of a user. *);
	end UserType;

	object Admin is
	    description: (* An emumeration of an Administrator user type. *);
	end Admin;

	object Instructor is
	    description: (* An emumeration of an Instructor user type. *);
	end Instructor;

	object Student is
	    description: (* An emumeration of an Administrator user type. *);
	end Student;



	operation Checkout is
	    inputs: ser: Server and uc: UserComputer and s: Schedule*;
	    outputs: ser': Server and uc': UserComputer;	    
	    precondition: ser != nil and  (* To check out a schedule, there must be at least one schedule on the server *)
	                  s != nil and  (* To check out a schedule, there must be at least one schedule that you've chosen to check out *)
	                  ( forall (st: Student) uc.ut != st) and  (* Students cannot check out schedules *)
	                  (
	                  if( exists (ins: Instructor) uc.ut = ins)  (* If the user is an instructor, then.... *)
	                  
	                  then (forall (sch: Schedule | sch.t != nil) not (sch in s))  (* there are no schedules for specific terms in
	                                                                                    the schedules selected to be checked out. They
	                                                                                    are all master schedules. *)
	                  ) and
	                  (
	                   forall (sch: Schedule | sch in s)  sch in ser.sl and  (* The schedules selected to be checked out are on the server and *)
	                                                      not (sch in uc.sl) and (* they are not on the user's computer and *)
	                                                      sch.l.b = false (* they are not locked. *)
	                  );               
	    postcondition: ( forall (sch: Schedule | sch in s)  sch in uc'.sl and (* The schedules selected are now on the user's computer and *)
	                                                       if (exists (adm: Admin) uc.ut = adm) (* if the user is an adminstrator, then.... *)
	                                                       then (sch.l.b = true and sch.l.id = uc.id)  (* the schedule is locked and his
	                                                                                                      user name is listed with the lock. *)
	                   ) and
	                   ( forall (sch: Schedule | sch in ser.sl)  sch in ser'.sl ) and (* All schedules that were in the inputed server's (ser)
	                                                                                  schedule list are in the outputed server's (ser') schedule
	                                                                                  list *)
	                   ( forall (sch: Schedule | not (sch in ser.sl))  not (sch in ser'.sl)) and (* No schedules that were not in the inputed server's
	                                                                                             (ser) schedule list are in the outputed
	                                                                                             server's (ser') schedule list. *)
	                   ( forall (sch: Schedule | sch in uc.sl and not (sch in s)) not (sch in uc'.sl)) (* No schedules that were not in the inputed
	                                                                                                      user computer's schedule list (uc.sl) or in the
	                                                                                                      inputed schedules (s) are in the outputed
	                                                                                                      user computer's schedule list (uc'.sl). *)
	                   ;	    
	    description: (* Takes the schedules that the user selects from the server, marks them as checked out on the server and
	                    copies them to the user's computer. If the user is an admin, the schedules that have been checked out
	                    are locked so that no one else can check them out. If they are an instructor, they can only check out
	                    master schedules and the schedules that they check out are not locked. *);
	end Checkout;


	operation Checkin is
	    inputs: ser: Server and uc: UserComputer and s: Schedule*;
	    outputs: ser': Server and uc': UserComputer;
	    precondition: uc != nil and (* To check in a schedule, there must be at least one schedule on the user's computer *)
	                  s != nil and (* To check in a schedule, there must be at least one schedule that you've chosen to check in *)
	                  ( forall (st: Student) uc.ut != st) and  (* Students cannot check in schedules *)
	                  (
			   if( exists (ins:Instructor) uc.ut = ins)  (* If the user is an instructor, then.... *)
			  	                  
			   then (forall (sch: Schedule | sch.t != nil) not (sch in s))  (* there are no schedules for specific terms in
			  	                                                              the schedules selected to be checked in. They
			  	                                                              are all master schedules. *)
			  ) and
			  (
			   forall (sch: Schedule | sch in s)  sch in ser.sl  (* The schedules selected to be checked in are on the user's computer *)
	                  );   
	    postcondition: ( forall (sch: Schedule | sch in s) sch in ser'.sl and  (* The schedules selected are now on the server and *)
	                                                       sch.l.b = false and sch.l.id = nil and  (* The schedules are no longer locked and *)
	                                                       not (sch in uc'.sl)  (* The selected schedules are no longer on the user's computer. *)
	                   ) and
	                   ( forall (sch: Schedule | sch in ser.sl)  sch in ser'.sl ) and (* All schedules that were in the inputed server's (ser)
			   	                                                          schedule list are in the outputed server's (ser') schedule
			   	                                                          list *)
			   ( forall (sch: Schedule | not (sch in ser.sl))  not (sch in ser'.sl)) and (* No schedules that were not in the inputed server's
			   	                                                                     (ser) schedule list are in the outputed
			   	                                                                     server's (ser') schedule list. *)
			   ( forall (sch: Schedule | sch in s) not (sch in uc'.sl)) (* No schedules that were in the inputed schedules (s) are
			                                                               in the outputed user computer's schedule list (uc'.sl). *)
	                   
	                    ;
	    description: (* Moves the schedules that the user selects from their computer onto the server where they replace
	                    the version that is on ther server. If the user is an admin, it replaces the entire schedule. If the 
	                    user is an instructor, then it replaces only their personal preferences. Also, if the user is an
	                    administrator, then the schedules that they are checking in are unlocked on the server so that
	                    they can be checked out again. If the user is an instructor, the schedules were never locked, so there
	                    is no need to unlock them. *);
	end Checkin;



	operation RemoveSchedule is
	    inputs: ser: Server and s: Schedule*;
	    outputs: ser': Server;
	    precondition: ser != nil and ser.sl != nil and  (* The server has at least one schedule. *)
	                  s != nil and  (* There is at least one schedule listed for deletion *)
	                  ( forall (sch: Schedule | sch in s) sch in ser.sl and sch.l.b = false) (* All selected schedules are on the server
	                                                                                            and are not locked. *)
	                  ;
	    postcondition: ( forall (sch: Schedule | sch in s) not (sch in ser'.sl) ) and  (* All selected schedules are no longer on the server. *)
	                   ( forall (sch: Schedule | sch in ser.sl  and  not (sch in s)) sch in ser'.sl) and (* All schedules that were not
	                                                                                                        selected are still on the server. *)
	                   ( forall (sch: Schedule | not (sch in ser.sl)) not (sch in ser'.sl) )  (* All schedules that weren't on the server still
	                                                                                             aren't on the server. *)
	                  ;
	    description: (* Permanently removes the selected schedules from the server. *);
	end RemoveSchedule;

end ScheduleManagement;