function getStudents(g:Gradebook) -> s:Student* = 
    ((forall (sections in g.sections) 
    		forall (student in sections.students) student in s)
	    and
    (forall (sections in g.sections)
    	forall (groups in sections.groups)
    	 forall (student in groups.students) student in s));

    	 
operation sortByFirstName
   inputs: s:Student*;
   outputs: s':Student*;
   precondition:;
   postcondition: ( forall (i:integer | 1 <= i and i < (#s'-1) ) ( s'[i].firstName <= s'[i+1].firstName ) );
   description: (*Sort students by first name with the first name that comes first alphabetically at the top.*);
end SortByFirstName;

operation sortByLastName
   inputs: s:Student*;
   outputs: s':Student*;
   precondition:;
   postcondition: ( forall (i:integer | 1 <= i and i < (#s'-1) ) ( s'[i].lastName <= s'[i+1].lastName ) );
   description: (*Sort students by last name with the last name that comes first alphabetically at the top.*);
end SortByLastName;

operation sortByIdNumber
   inputs: s:Student*;
   outputs: s':Student*;
   precondition:;
   postcondition: ( forall (i:integer | 1 <= i and i < (#s'-1) ) ( s'[i].emplId <= s'[i+1].emplId ) );
   description: (*Sort students by IdNumber, with the lowest IdNumber at the top.*);
end SortByIdNumber;

operation sortByItem
   inputs: s:Student*, itm:Item;
   outputs: s':Student*;
   precondition:;
   postcondition: ( forall (i:integer | 1 <= i and i < (#s'-1)) 
                     (forall (scoreN in s'[i].scores)  
                        if(scoreN.associatedItem = itm) 
                        then (forall (scoreNp1 in s'[i+1].scores ) 
                                    if(scoreNp1.associatedItem = itm) 
                                    then (scoreN.pointsEarned >= scoreNp1.pointsEarned) 
                              )
                      )
                   );
   description: (*Sort students by the scores of the given item. The Highest score on top.*);
end SortByItem;
    	 
operation chooseSortOrder
   inputs: gb:Gradebook, i:Item, menuChoice:string;
   outputs: s': Student*;
   precondition:;
   postcondition: if (i = nil) 
                  then (
                           if(menuChoice = "Last Name")
                           then (s' = sortByLastName(getStudents(gb)))
                           else (
                                    if(menuChoice = "First Name")
                                    then (s' = sortByFirstName(getStudents(gb)))
                                    else (
                                             if(menuChoice = "ID Number")
                                             then(s' = sortByIdNumber(getStudents(gb)))
                                         )
                                )
                       )
                  else (s' = sortByItem(getStudents(gb),i));
   description:(* This is called when the user wants to change the sorting order. It returns the students in the order they'll
   be displayed in. *);
end chooseSortOrder;
    	 
operation editScore
   inputs: s:Score, predictionMode:boolean, newScore:integer;
   outputs: s':Score;
   precondition:;
   postcondition: if (predictionMode)
                  then (s'.pointsEarnedPredicted = newScore)
                  else (s'.pointsEarned = newScore);
   description: (* Ths operation is called whenever a student's score is changed. *);
end editScore;