operation addItem
    inputs: gb:Gradebook, i:Item;
    outputs: gb':Gradebook;
    precondition: not (i in gb.items);
    postcondition: forall (i':Item) (i' in gb'.items) iff ((i' in gb.items) or (i' = i));
    description: (* adds an item to the gradebook's hierarchy of items *);
end addItem;

operation editItem
    inputs: gb:Gradebook, old:Item, new:Item;
    outputs: gb':Gradebook;
    precondition: old in gb.items;
    postcondition: forall (i':Item) (i' in gb'.items) iff (((i' in gb.items) and (i' != old)) or (i' = new));
    description: (* replaces an old version of an item in the gradebook's hierarchy of items with a new version of that item *);
end editItem;

operation deleteItem
    inputs: gb:Gradebook, i:Item;
    outputs: gb':Gradebook;
    precondition: i in gb.items;
    postcondition: forall (i':Item) (i' in gb'.items) iff ((i' in gb.items) and (i' != i));
    description: (* removes an item from the gradebook's hierarchy of items *);
end deleteItem;

operation groupItems
    inputs: gb:Gradebook, cat:Item, i:Item *;
    outputs: gb':Gradebook;
    precondition: (not (cat in gb.items)) and (not (cat in i)) and (forall (i' in i) (i' in gb.items));
    postcondition: (forall (i':Item) (i' in gb'.items) iff ( ((i' in gb.items) and not (i' in i)) or (i' = cat) ))
        and (forall (i':Item) (i' in cat.children) iff (i' in i));
    description: (* removes items from the gradebook's hierarchy of items,
        then makes them children of a new item which is then added to the gradebook *);
end groupItems;

operation ungroupItem
    inputs: gb:Gradebook, i:Item;
    outputs: gb':Gradebook;
    precondition: (i in gb.items) and (#i.children > 0);
    postcondition: (forall (i':Item) (i' in gb'.items) iff (((i' in gb.items) or (i' in i.children)) and (i' != i)));
    description: (* takes an item with children [a category] and moves the child items to that item's parent, then removes the item *);
end ungroupItem;

operation collapseItem
    inputs: gb:Gradebook, i:Item;
    outputs: gb':Gradebook;
    precondition: i in gb.items;
    postcondition: forall (i':Item) (i' in gb'.items) iff (((i' in gb.items) and (i' != i)) or (
    	i'.name = i.name and
    	i'.dueDate = i.dueDate and
    	i'.gracePeriod = i.gracePeriod and
    	i'.gracePeriodInherit = i.gracePeriodInherit and
    	i'.latePolicy = i.latePolicy and
    	i'.latePolicyValue = i.latePolicyValue and
    	i'.latePolicyInherit = i.latePolicyInherit and
    	i'.pointsPossible = i.pointsPossible and
    	i'.pointsPossibleInherit = i.pointsPossibleInherit and
    	i'.weight = i.weight and
    	i'.weightPercent = i.weightPercent and
    	i'.weightInherit = i.weightInherit and
    	i'.gradingScheme = i.gradingScheme and
    	i'.gradingSchemeInherit = i.gradingSchemeInherit and
    	i'.extraCredit = i.extraCredit and
    	i'.extraCreditFor = i.extraCreditFor and
    	i'.extraCreditInherit = i.extraCreditInherit and
    	i'.children = i.children and
    	i'.selected = i.selected and
    	i'.hidden = i.hidden and
    	i'.collapsed = true
    ));
    description: (* takes an item and collapses it *);
end collapseItem;

operation expandItem
    inputs: gb:Gradebook, i:Item;
    outputs: gb':Gradebook;
    precondition: i in gb.items;
    postcondition: forall (i':Item) (i' in gb'.items) iff (((i' in gb.items) and (i' != i)) or (
    	i'.name = i.name and
    	i'.dueDate = i.dueDate and
    	i'.gracePeriod = i.gracePeriod and
    	i'.gracePeriodInherit = i.gracePeriodInherit and
    	i'.latePolicy = i.latePolicy and
    	i'.latePolicyValue = i.latePolicyValue and
    	i'.latePolicyInherit = i.latePolicyInherit and
    	i'.pointsPossible = i.pointsPossible and
    	i'.pointsPossibleInherit = i.pointsPossibleInherit and
    	i'.weight = i.weight and
    	i'.weightPercent = i.weightPercent and
    	i'.weightInherit = i.weightInherit and
    	i'.gradingScheme = i.gradingScheme and
    	i'.gradingSchemeInherit = i.gradingSchemeInherit and
    	i'.extraCredit = i.extraCredit and
    	i'.extraCreditFor = i.extraCreditFor and
    	i'.extraCreditInherit = i.extraCreditInherit and
    	i'.children = i.children and
    	i'.selected = i.selected and
    	i'.hidden = i.hidden and
    	i'.collapsed = false
    ));
    description: (* takes an item and expands it *);
end expandItem;

operation hideItem
    inputs: gb:Gradebook, i:Item;
    outputs: gb':Gradebook;
    precondition: i in gb.items;
    postcondition: forall (i':Item) (i' in gb'.items) iff (((i' in gb.items) and (i' != i)) or (
    	i'.name = i.name and
    	i'.dueDate = i.dueDate and
    	i'.gracePeriod = i.gracePeriod and
    	i'.gracePeriodInherit = i.gracePeriodInherit and
    	i'.latePolicy = i.latePolicy and
    	i'.latePolicyValue = i.latePolicyValue and
    	i'.latePolicyInherit = i.latePolicyInherit and
    	i'.pointsPossible = i.pointsPossible and
    	i'.pointsPossibleInherit = i.pointsPossibleInherit and
    	i'.weight = i.weight and
    	i'.weightPercent = i.weightPercent and
    	i'.weightInherit = i.weightInherit and
    	i'.gradingScheme = i.gradingScheme and
    	i'.gradingSchemeInherit = i.gradingSchemeInherit and
    	i'.extraCredit = i.extraCredit and
    	i'.extraCreditFor = i.extraCreditFor and
    	i'.extraCreditInherit = i.extraCreditInherit and
    	i'.children = i.children and
    	i'.selected = i.selected and
    	i'.hidden = true and
    	i'.collapsed = i.collapsed
    ));
    description: (* takes an item and hides it *);
end hideItem;

operation showItem
    inputs: gb:Gradebook, i:Item;
    outputs: gb':Gradebook;
    precondition: i in gb.items;
    postcondition: forall (i':Item) (i' in gb'.items) iff (((i' in gb.items) and (i' != i)) or (
    	i'.name = i.name and
    	i'.dueDate = i.dueDate and
    	i'.gracePeriod = i.gracePeriod and
    	i'.gracePeriodInherit = i.gracePeriodInherit and
    	i'.latePolicy = i.latePolicy and
    	i'.latePolicyValue = i.latePolicyValue and
    	i'.latePolicyInherit = i.latePolicyInherit and
    	i'.pointsPossible = i.pointsPossible and
    	i'.pointsPossibleInherit = i.pointsPossibleInherit and
    	i'.weight = i.weight and
    	i'.weightPercent = i.weightPercent and
    	i'.weightInherit = i.weightInherit and
    	i'.gradingScheme = i.gradingScheme and
    	i'.gradingSchemeInherit = i.gradingSchemeInherit and
    	i'.extraCredit = i.extraCredit and
    	i'.extraCreditFor = i.extraCreditFor and
    	i'.extraCreditInherit = i.extraCreditInherit and
    	i'.children = i.children and
    	i'.selected = i.selected and
    	i'.hidden = false and
    	i'.collapsed = i.collapsed
    ));
    description: (* takes an item and shows it *);
end showItem;

operation changeTurnInDate
    inputs: s:Score, d:Date;
    outputs: s':Score;
    precondition:;
    postcondition: s'.turnInDate = d;
    description: (* takes a score and changes its turn-in date *);
end changeTurnInDate;



operation addStudent
    inputs: s:Section, st:Student;
    outputs: s':Section;
    precondition: not ((st in s.students) or (exists (g:Group) ((g in s.groups) and (st in g.students))));
    postcondition: forall (st':Student) (st' in s'.students) iff (((st' in s.students) or (exists (g:Group) ((g in s.groups) and (st' in g.students)))) or (st' = st));
    description: (* adds a student to a specified section of a class *);
end addStudent;

operation editStudent
    inputs: s:Section, old:Student, new:Student;
    outputs: s':Section;
    precondition: ((old in s.students) or (exists (g:Group) ((g in s.groups) and (old in g.students))));
    postcondition: (forall (st:Student) (st in s'.students) iff (((st in s.students) and (st != old)) or (st = new)))
       and (forall (g:Group | g in s'.groups) forall (st:Student) ((st in g.students) iff (((st in g.students) and (st != old)) or (st = new))));
    description: (* replaces an old version of a student in a section with a new version of that student *);
end editStudent;

operation deleteStudent
    inputs: s:Section, st:Student;
    outputs: s':Section;
    precondition: ((st in s.students) or (exists (g:Group) ((g in s.groups) and (st in g.students))));
    postcondition: (forall (st':Student) (st' in s'.students) iff ((st' in s.students) and (st' != st)))
       and (forall (g:Group | g in s'.groups) forall (st':Student) ((st' in g.students) iff ((st' in g.students) and (st' != st))));
    description: (* removes a student from a section *);
end deleteStudent;

operation groupStudents
    inputs: s:Section, g:Group, st:Student *;
    outputs: s':Section;
    precondition: (not (g in s.groups)) and (forall (st' in st) (st' in s.students));
    postcondition: (forall (st':Student) (st' in s'.students) iff ((st' in s.students) and not (st' in st)))
        and (forall (g':Group) (g' in s'.groups) iff ((g' in s.groups) or (g' = g)))
        and (forall (st':Student) (st' in g.students) iff (st' in st));
    description: (* creates a new group, and moves students out of the section into the group *);
end groupStudents;

operation ungroupStudents
    inputs: s:Section, g:Group;
    outputs: s':Section;
    precondition: (g in s.groups);
    postcondition: (forall (st:Student) (st in s'.students) iff ((st in s.students) or (st in g.students)))
       and (forall (g':Group) (g' in s'.groups) iff ((g' in s.groups) and (g' != g)));
    description: (* takes a group of students, moves the students out of the group into the section, and removes the group *);
end ungroupStudents;

operation collapseGroup
    inputs: s:Section, g:Group;
    outputs: s':Section;
    precondition: (g in s.groups);
    postcondition: forall (g':Group) (g' in s'.groups) iff (((g' in s.groups) and (g' != g)) or (
    	g'.name = g.name and g'.students = g.students and g'.selected = g.selected and g'.collapsed
    ));
    description: (* takes a group and collapses it *);
end collapseGroup;

operation expandGroup
    inputs: s:Section, g:Group;
    outputs: s':Section;
    precondition: (g in s.groups);
    postcondition: forall (g':Group) (g' in s'.groups) iff (((g' in s.groups) and (g' != g)) or (
    	g'.name = g.name and g'.students = g.students and g'.selected = g.selected and not g'.collapsed
    ));
    description: (* takes a group and expands it *);
end expandGroup;