(**** * * This file defines the objs and ops related to the roster. * *) object Roster is components: groups:UserGroup* and cat:SortCat and isVisible:boolean; end; object UserGroup is components: users:User* and sortby:SortBy*; end; object User is components: utype:UserType and uname:UserName and pubdrawp:PublicDrawingPerm and showpubp:ShowPublicDrawingsPerm and pubnavp:PublicNavigationPerm and chatp:ChatPerm and hques:HasQuestion and online:Online; end; object Ascending is boolean; object SortCat is (unamecat:UserNameCat or utypecat:UserTypeCat or onlinecat:OnlineCat or pubdrawcat:PublicDrawingPermCat or showpubdrawcat:ShowPublicDrawingsPermCat or pubnavcat:PublicNavigationPermCat or chatcat:ChatPermCat or questioncat:HasQuestionCat); object SortBy is components: cat:SortCat and asc:Ascending; end; object UserNameCat; object UserTypeCat; object OnlineCat; object PublicDrawingPermCat; object ShowPublicDrawingsPermCat; object PublicNavigationPermCat; object ChatPermCat; object HasQuestionCat; object UserType is components: instructor:Instructor or student:Student or guest:Guest; end; object Instructor; object Student; object Guest; object UserName is string; object Online is boolean; object PublicDrawingPerm is boolean; object ShowPublicDrawingsPerm is boolean; object PublicNavigationPerm is boolean; object ChatPerm is boolean; object HasQuestion is boolean; operation setCategory inputs: r:Roster, c:SortCat; outputs: r':Roster; postcondition: (r'.cat = c); end; operation addSortBy inputs: r:Roster, g:UserGroup, s:SortBy; outputs: r':Roster; precondition: exists(group in r.groups) (g = group); postcondition: (* all groups are the same except the one we're changing *) forall(gs in (r.groups-g) ) ( exists(g' in r'.groups) (g' = gs) ) and #(r.groups) = #(r'.groups) and exists(g' in r'.groups) ( (g'.sortby[1] = s) and if(exists(sortby in g.sortby) (s.cat = sortby.cat)) then if( g.sortby[1].cat = s.cat ) then (g'.sortby[1].asc = not g.sortby[1].asc) else (g'.sortby = s + (g.sortby-s)) else (g'.sortby = s + g.sortby) and (g'.users = g.users) ); description: (* Takes the group that the sortby is being added to, the new sortby to be added and the roster. If the sortby that is being added is already the first sortby, then toggle the ascending flag. If the sortby that is being added exists elsewhere in the sortby list then move it to the first element and leave the rest. If the new sortby isn't in the sortby list then make it the first and shift the others sortbys over. *); end; operation Sort inputs: r:Roster; outputs: r':Roster; postcondition: (* Roster is grouped by cat and groups are sorted by sortby *) (* all the users in r must be in r' and none added *) forall( g in r.groups ) ( forall( u in g.users ) ( exists ( g' in r'.groups ) ( exists (u' in g'.users) (u' = u) ) ) ) and #(AllUsers(r.groups)) = #(AllUsers(r'.groups)) and if(r.cat?.unamecat) then ( (* all the users are in one group and sorted by name *) (#(r'.groups) = 1) and forall(u in AllUsers(r.groups)) ( exists(u' in r'.groups[1].users) (u' = u) ) and (#(AllUsers(r.groups)) = #(r'.groups[1].users)) and GroupSorted(r'.groups[1]) ) else if(r.cat?.utypecat) then ( (#(r'.groups) = 3) and forall(u in r'.groups[1].users) ( u.utype?.instructor ) and forall(u in r'.groups[2].users) ( u.utype?.student ) and forall(u in r'.groups[1].users) ( u.utype?.guest ) and GroupSorted(r'.groups[1]) and GroupSorted(r'.groups[2]) and GroupSorted(r'.groups[3]) ) else ( (#(r'.groups) = 2) and if(r.cat?.onlinecat) then ( forall(u in r'.groups[1].users) ( u.online ) and forall(u in r'.groups[2].users) ( not u.online ) ) else if(r.cat?.pubdrawcat) then ( forall(u in r'.groups[1].users) ( u.pubdrawp ) and forall(u in r'.groups[2].users) ( not u.pubdrawp ) ) else if(r.cat?.showpubdrawcat) then ( forall(u in r'.groups[1].users) ( u.showpubp ) and forall(u in r'.groups[2].users) ( not u.showpubp ) ) else if(r.cat?.pubnavcat) then ( forall(u in r'.groups[1].users) ( u.pubnavp ) and forall(u in r'.groups[2].users) ( not u.pubnavp ) ) else if(r.cat?.chatcat) then ( forall(u in r'.groups[1].users) ( u.chatp ) and forall(u in r'.groups[2].users) ( not u.chatp ) ) else if(r.cat?.questioncat) then ( forall(u in r'.groups[1].users) ( u.hques ) and forall(u in r'.groups[2].users) ( not u.hques ) ) else (false) and GroupSorted(r'.groups[1]) and GroupSorted(r'.groups[2]) ) ; description: (* Takes the cat in r and sortbys in r's UserGroups to sort the roster accordingly. *); end; function GroupSorted(g:UserGroup) = forall(i:integer | (i >= 1) and (i < #(g.users))) ( UserCompare(g.users[i], g.users[i+1], g.sortby); ); function UserCompare(u1:User, u2:User, s:SortBy*) = if(#s = 0) then ( true ) else if(s[1].cat?.unamecat) then ( if(s[1].asc) then ( if(u1.uname > u2.uname) then ( true ) else if(u1.uname < u2.uname) then ( false ) else ( UserCompare(u1, u2, s[2:#s]) ) ) else ( if(u1.uname > u2.uname) then ( false ) else if(u1.uname < u2.uname) then ( true ) else ( UserCompare(u1, u2, s[2:#s]) ) ) ) else if(s[1].cat?.utypecat) then ( if(s[1].asc) then ( if(u1.utype > u2.utype) then ( true ) else if(u1.utype < u2.utype) then ( false ) else ( UserCompare(u1, u2, s[2:#s]) ) ) else ( if(u1.utype > u2.utype) then ( false ) else if(u1.utype < u2.utype) then ( true ) else ( UserCompare(u1, u2, s[2:#s]) ) ) ) else if(s[1].cat?.onlinecat) then ( if(s[1].asc) then ( if(u1.online > u2.online) then ( true ) else if(u1.online < u2.online) then ( false ) else ( UserCompare(u1, u2, s[2:#s]) ) ) else ( if(u1.online > u2.online) then ( false ) else if(u1.online < u2.online) then ( true ) else ( UserCompare(u1, u2, s[2:#s]) ) ) ) else if(s[1].cat?.pubdrawcat) then ( if(s[1].asc) then ( if(u1.pubdrawp > u2.pubdrawp) then ( true ) else if(u1.pubdrawp < u2.pubdrawp) then ( false ) else ( UserCompare(u1, u2, s[2:#s]) ) ) else ( if(u1.pubdrawp > u2.pubdrawp) then ( false ) else if(u1.pubdrawp < u2.pubdrawp) then ( true ) else ( UserCompare(u1, u2, s[2:#s]) ) ) ) else if(s[1].cat?.showpubdrawcat) then ( if(s[1].asc) then ( if(u1.showpubp > u2.showpubp) then ( true ) else if(u1.showpubp < u2.showpubp) then ( false ) else ( UserCompare(u1, u2, s[2:#s]) ) ) else ( if(u1.showpubp > u2.showpubp) then ( false ) else if(u1.showpubp < u2.showpubp) then ( true ) else ( UserCompare(u1, u2, s[2:#s]) ) ) ) else if(s[1].cat?.pubnavcat) then ( if(s[1].asc) then ( if(u1.pubnavp > u2.pubnavp) then ( true ) else if(u1.pubnavp < u2.pubnavp) then ( false ) else ( UserCompare(u1, u2, s[2:#s]) ) ) else ( if(u1.pubnavp > u2.pubnavp) then ( false ) else if(u1.pubnavp < u2.pubnavp) then ( true ) else ( UserCompare(u1, u2, s[2:#s]) ) ) ) else if(s[1].cat?.chatcat) then ( if(s[1].asc) then ( if(u1.chatp > u2.chatp) then ( true ) else if(u1.chatp < u2.chatp) then ( false ) else ( UserCompare(u1, u2, s[2:#s]) ) ) else ( if(u1.chatp > u2.chatp) then ( false ) else if(u1.chatp < u2.chatp) then ( true ) else ( UserCompare(u1, u2, s[2:#s]) ) ) ) else if(s[1].cat?.questioncat) then ( if(s[1].asc) then ( if(u1.hques > u2.hques) then ( true ) else if(u1.hques < u2.hques) then ( false ) else ( UserCompare(u1, u2, s[2:#s]) ) ) else ( if(u1.hques > u2.hques) then ( false ) else if(u1.hques < u2.hques) then ( true ) else ( UserCompare(u1, u2, s[2:#s]) ) ) ) else (false); function AllUsers(g:UserGroup*) = if(#g = 0) then [] else g[1] + AllUsers(g[2:#g]); operation showPublicDrawings inputs: u:User, splp:ShowPublicDrawingsPerm; outputs: u':User; postcondition: u'.showpubp = splp; end; operation setPublicNavigation inputs: u:User, pubnavp:PublicNavigationPerm; outputs: u':User; postcondition: u'.pubnavp = pubnavp; end; operation setPublicDrawing inputs: u:User, pubdrawp:PublicDrawingPerm; outputs: u':User; postcondition: u'.pubdrawp = pubdrawp; end; operation setChatPerm inputs: u:User, chatp:ChatPerm; outputs: u':User; postcondition: u'.chatp = chatp; end; operation setHasQuestion inputs: u:User, hques:HasQuestion; outputs: u':User; postcondition: u'.hques = hques; end;