def set_grade(self, aid, sid, grd):
        '''
        Set a grade by Stud ID and Assginment ID
        :param aid: int
        :param sid: int
        :param grd: float
        :return:
        '''
        grade = self.__grade_repo.get(str(sid) + "::" + str(aid))

        if self.__assign_repo.get(aid) is None:
            raise RepositoryError("This assignment doesn't exist")

        if grade is None:
            undo = FunctionCall(self.set_grade, aid, sid, -1)
            redo = FunctionCall(self.set_grade, aid, sid, grd)

            op = Operation(undo, redo)

            self.__timeline.append(op)

            self.__grade_repo.append(self.create_grade(sid, aid, grd))
        else:
            undo = FunctionCall(self.set_grade, aid, sid, grade.getGrade)
            redo = FunctionCall(self.set_grade, aid, sid, grd)

            op = Operation(undo, redo)

            self.__timeline.append(op)

            grade.getGrade = grd
    def update_student_name(self, ID, name):
        '''
        Update a student's NAME by given ID
        :param ID: int ID of student
        :param name: string NAME
        :return: None
        :exception:
                - Repository: No records for given ID
        '''
        if self.__stud_repo.get(ID) is not None:
            undo = FunctionCall(self.update_student_name, ID,
                                self.__stud_repo.get(ID).getName())
            redo = FunctionCall(self.update_student_name, ID, name)

            op = Operation(undo, redo)

            self.__timeline.append(op)

            self.__stud_repo.get(ID).setName(name)

            try:
                self.__stud_repo.backup()
            except Exception as E:
                print(E)

        else:
            raise RepositoryError("No student for given ID, " + str(ID))
    def remove_student(self, ID):
        '''
        Remove a student from Repo by ID
        :param ID: int ID
        :return: True if succeded
        :exception:
                - Repository: No records for given ID
        '''
        if self.__stud_repo.get(ID) is None:
            raise RepositoryError("No student for given ID, " + str(ID))
        else:
            CSC = Cascade()

            undo = FunctionCall(self.add_student,
                                deepcopy(self.__stud_repo.get(ID)))
            redo = FunctionCall(self.remove_student, ID)

            self.__stud_repo.remove(ID)
            self.remove_grade_student(ID, CSC)  # REMOVE FROM GRADE
            op = Operation(undo, redo)

            CSC.append(op)

            self.__timeline.append(CSC)

            try:
                self.__stud_repo.backup()
            except:
                pass

            return True
    def add_student(self, student):
        '''
        Add a student to Students repo
        :param student: student object
        :return: True if succeded
        :exception:
                - Repository : ID not unique
        '''
        if self.__stud_repo.get(student.getID()) is None:
            self.__stud_repo.append(student)

            undo = FunctionCall(self.remove_student, student.getID())
            redo = FunctionCall(self.add_student, deepcopy(student))

            op = Operation(undo, redo)

            self.__timeline.append(op)

            try:
                self.__stud_repo.backup()
            except:
                pass

            return True
        else:
            raise RepositoryError("ID " + str(student.getID()) +
                                  " already in use!")
    def remove_grade_student(self, ID, CSC):
        '''
        Remove grades for given student ID
        :param ID: int ID of student
        :return: None
        '''

        TMP = self.__grade_repo.get_all()

        i = 0
        while i < len(TMP):
            if TMP[i].getStudent() == ID:
                redo = FunctionCall(self.remove_grade_obj, TMP[i].getID())
                undo = FunctionCall(self.insert_grade, deepcopy(TMP[i]))

                CSC.append(Operation(undo, redo))

                del TMP[i]

                # not needed anymore at this level
                #self.remove_grade_obj(TMP[i].getID())
            else:
                i += 1

        try:
            self.__grade_repo.backup()
        except:
            pass
    def allocate_assign_student(self, ID, target):
        '''
        Allocate an assignment for a student by ID
        :param ID: int ID of assignment
        :param target: int ID of student
        :return: None
        '''
        link = self.create_grade(target, ID)

        if self.__grade_repo.get(link.getID()) is None:
            self.__grade_repo.append(link)

            #print(link.getID())
            undo = FunctionCall(self.remove_grade_obj, link.getID())
            redo = FunctionCall(self.allocate_assign_student, ID, target)

            op = Operation(undo, redo)

            self.__timeline.append(op)

            try:
                self.__grade_repo.backup()
            except:
                pass

            return True
        else:
            raise RepositoryError("ID already in use!")
    def allocate_assign_group(self, ID, target):
        '''
        Allocate an assignment for an entire group by IDs (no conflicts)
        :param ID: int ID of assignment
        :param target: int ID of group
        :return: None
        '''
        TMP = self.__stud_repo.get_all()

        CSC = Cascade()

        undo = FunctionCall(self.remove_grade_assign, ID, CSC)
        redo = FunctionCall(self.allocate_assign_group, ID, target)

        op = Operation(undo, redo)

        CSC.append(op)

        self.__timeline.append(op)

        for each in TMP:
            if each.getGroup() == target:
                link = self.create_grade(each.getID(), ID)

                if self.__grade_repo.get(link.getID()) is None:
                    self.__grade_repo.append(link)

        try:
            self.__grade_repo.backup()
        except:
            pass
    def update_assignment_deadline(self, ID, date):
        '''
        Update assignment's deadline by ID
        :param ID: int ID of assignment
        :param date: date type Deadline
        :return: None
        :exception:
                - Repository: No records for given ID
        '''
        if self.__assign_repo.get(ID) is not None:
            undo = FunctionCall(self.update_assignment_deadline, ID,
                                self.__assign_repo.get(ID).getDeadline())
            redo = FunctionCall(self.update_assignment_deadline, ID, date)

            op = Operation(undo, redo)

            self.__timeline.append(op)

            self.__assign_repo.get(ID).setDeadline(date)

            try:
                self.__assign_repo.backup()
            except:
                pass

        else:
            raise RepositoryError("No assignment for given ID")
    def update_assignment_descr(self, ID, desc):
        '''
        Update assignment description by ID
        :param ID: int ID of assignment
        :param desc: new string Description
        :return: None
        :exception:
                - Repository: No records for given ID
        '''
        if self.__assign_repo.get(ID) is not None:
            undo = FunctionCall(self.update_assignment_descr, ID,
                                self.__assign_repo.get(ID).getDescription())
            redo = FunctionCall(self.update_assignment_descr, ID, desc)

            op = Operation(undo, redo)

            self.__timeline.append(op)

            self.__assign_repo.get(ID).setDescription(desc)

            try:
                self.__assign_repo.backup()
            except:
                pass

        else:
            raise RepositoryError("No assignment for given ID")
    def add_assignment(self, assign):
        '''
        Add an assignment to assignments repo
        :param assign: Assignment object
        :return: True if succeded
        :exception:
                - Repository: ID already in ussage
        '''
        if self.__assign_repo.get(assign.getID()) is None:
            self.__assign_repo.append(assign)

            undo = FunctionCall(self.remove_assignment, assign.getID())
            redo = FunctionCall(self.add_assignment, deepcopy(assign))

            op = Operation(undo, redo)

            self.__timeline.append(op)

            try:
                self.__assign_repo.backup()
            except:
                pass

            return True
        else:
            raise RepositoryError("ID already in use!")
    def update_student_group(self, ID, group):
        '''
        Update a student's GROUP id
        :param ID: int ID of student
        :param group: new GROUP ID
        :return: None
        :exception:
                - Repository: No records for given ID
        '''
        if self.__stud_repo.get(ID) is not None:
            undo = FunctionCall(self.update_student_group, ID,
                                self.__stud_repo.get(ID).getGroup())
            redo = FunctionCall(self.update_student_group, ID, group)

            op = Operation(undo, redo)

            self.__timeline.append(op)

            self.__stud_repo.get(ID).setGroup(group)

            try:
                self.__stud_repo.backup()
            except:
                pass

        else:
            raise RepositoryError("No student for given ID, " + str(ID))
    def remove_grade_assign(self, ID, CSC):
        '''
        Remove grades for given assignment ID
        :param ID: int ID of assignment
        :return: None
        '''
        TMP = self.__grade_repo.get_all()

        i = 0
        while i < len(TMP):
            if TMP[i].getAssignment() == ID:
                redo = FunctionCall(self.remove_grade_obj, TMP[i].getID())
                undo = FunctionCall(self.insert_grade, deepcopy(TMP[i]))

                CSC.append(Operation(undo, redo))

                del TMP[i]
            else:
                i += 1

        try:
            self.__grade_repo.backup()
        except:
            pass