/**
* Copyright © 2002 Instituto Superior Técnico
*
* This file is part of FenixEdu Academic.
*
* FenixEdu Academic is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* FenixEdu Academic is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with FenixEdu Academic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.fenixedu.academic.ui.spring.controller.student;
import java.util.List;
import java.util.stream.Collectors;
import org.fenixedu.academic.domain.Attends;
import org.fenixedu.academic.domain.Grouping;
import org.fenixedu.academic.domain.Person;
import org.fenixedu.academic.domain.Shift;
import org.fenixedu.academic.domain.StudentGroup;
import org.fenixedu.academic.domain.exceptions.DomainException;
import org.fenixedu.academic.domain.student.Registration;
import org.fenixedu.academic.predicate.AccessControl;
import org.fenixedu.academic.util.EnrolmentGroupPolicyType;
import org.springframework.stereotype.Service;
import pt.ist.fenixframework.Atomic;
@Service
public class StudentGroupingService {
@Atomic
public void enroll(StudentGroup studentGroup, Person person) {
if (studentGroup == null) {
throw new DomainException("error.shift.noShift");
}
Grouping grouping = studentGroup.getGrouping();
if (!groupingIsOpenForEnrollment(grouping)) {
throw new DomainException("error.grouping.notOpenToEnrollment");
}
if (!personInGroupingAttends(grouping, person)) {
throw new DomainException("error.grouping.notEnroled");
}
if (grouping.getStudentGroupsSet().stream().anyMatch(sg -> personInStudentGroupAttends(sg, person))) {
throw new DomainException("error.studentGroup.alreadyEnroled");
}
if (grouping.getEnrolmentPolicy().equals(EnrolmentGroupPolicyType.ATOMIC) && grouping.getMinimumCapacity() != null
&& studentGroup.getAttendsSet().size() + 1 < grouping.getMinimumCapacity()) {
throw new DomainException("error.invalidNumberOfStudents");
}
if (grouping.getMaximumCapacity() != null && studentGroup.getAttendsSet().size() + 1 > grouping.getMaximumCapacity()) {
throw new DomainException("error.invalidNumberOfStudents");
}
studentGroup.addAttends(grouping.getAttendsSet().stream()
.filter(attends -> attends.getRegistration().getPerson() == person).findAny().get());
}
@Atomic
public void unenroll(StudentGroup studentGroup, Person person) {
Grouping grouping = studentGroup.getGrouping();
if (!groupingIsOpenForEnrollment(grouping)) {
throw new DomainException("error.grouping.notOpenToEnrollment");
}
if (!personInGroupingAttends(grouping, person) || !personInStudentGroupAttends(studentGroup, person)) {
throw new DomainException("error.studentGroup.notEnroled");
}
if (grouping.getMinimumCapacity() != null && studentGroup.getAttendsSet().size() - 1 < grouping.getMinimumCapacity()) {
throw new DomainException("error.invalidNumberOfStudents");
}
if (grouping.getMaximumCapacity() != null && studentGroup.getAttendsSet().size() - 1 > grouping.getMaximumCapacity()) {
throw new DomainException("error.invalidNumberOfStudents");
}
studentGroup.removeAttends(grouping.getAttendsSet().stream()
.filter(attends -> attends.getRegistration().getPerson() == person).findAny().get());
if (studentGroup.getAttendsSet().isEmpty()) {
studentGroup.delete();
}
}
@Atomic
public void createStudentGroup(Grouping grouping, Shift shift, List<Person> personList) {
if (!personList.contains(AccessControl.getPerson())) {
personList.add(AccessControl.getPerson());
}
List<Registration> registrationsList =
grouping.getAttendsSet().stream().map(Attends::getRegistration)
.filter(reg -> personList.contains(reg.getPerson())).collect(Collectors.toList());
if (!groupingIsOpenForEnrollment(grouping)) {
throw new DomainException("error.grouping.notOpenToEnrollment");
}
if (personList.stream().anyMatch(person -> !personInGroupingAttends(grouping, person))) {
throw new DomainException("error.studentGroup.notEnroled");
}
if (personList.stream().anyMatch(
person -> grouping.getStudentGroupsSet().stream().anyMatch(sg -> personInStudentGroupAttends(sg, person)))) {
throw new DomainException("error.studentGroup.alreadyEnrolled");
}
if (grouping.getShiftType() != null && !shift.getTypes().contains(grouping.getShiftType())) {
throw new DomainException("error.wrongShiftType");
}
if (shift != null && !grouping.getExecutionCourses().contains(shift.getExecutionCourse())) {
throw new DomainException("error.wrongShiftType");
}
if (grouping.getDifferentiatedCapacity()) {
if (shift != null && shift.getShiftGroupingProperties().getCapacity() != null
&& shift.getShiftGroupingProperties().getCapacity() < shift.getAssociatedStudentGroups(grouping).size() + 1) {
throw new DomainException("error.invalidNumberOfStudentGroups");
}
} else {
if (grouping.getGroupMaximumNumber() != null) {
if (shift != null && grouping.getGroupMaximumNumber() < shift.getAssociatedStudentGroups(grouping).size() + 1) {
throw new DomainException("error.invalidNumberOfStudentGroups");
}
if (shift == null && grouping.getGroupMaximumNumber() < grouping.getStudentGroupsSet().size() + 1) {
throw new DomainException("error.invalidNumberOfStudentGroups");
}
}
}
if (grouping.getEnrolmentPolicy().equals(EnrolmentGroupPolicyType.ATOMIC) && grouping.getMinimumCapacity() != null
&& personList.size() < grouping.getMinimumCapacity()) {
throw new DomainException("error.invalidNumberOfStudents");
}
if (grouping.getMaximumCapacity() != null && personList.size() > grouping.getMaximumCapacity()) {
throw new DomainException("error.invalidNumberOfStudents");
}
grouping.createStudentGroup(shift, grouping.findMaxGroupNumber() + 1, registrationsList);
}
@Atomic
public void changeShift(StudentGroup studentGroup, Shift shift) {
Grouping grouping = studentGroup.getGrouping();
if (!groupingIsOpenForEnrollment(grouping)) {
throw new DomainException("error.grouping.notOpenToEnrollment");
}
if (shift == null && grouping.getShiftType() != null || !shift.getTypes().contains(grouping.getShiftType())) {
throw new DomainException("error.wrongShiftType");
}
if (grouping.getDifferentiatedCapacity()) {
if (shift.getShiftGroupingProperties().getCapacity() < shift.getAssociatedStudentGroups(grouping).size() + 1) {
throw new DomainException("error.invalidNumberOfStudentGroups");
}
} else {
if (grouping.getGroupMaximumNumber() < shift.getAssociatedStudentGroups(grouping).size() + 1) {
throw new DomainException("error.invalidNumberOfStudentGroups");
}
}
studentGroup.setShift(shift);
}
public Boolean groupingIsOpenForEnrollment(Grouping grouping) {
return grouping.getEnrolmentBeginDayDateDateTime().isBeforeNow()
&& grouping.getEnrolmentEndDayDateDateTime().isAfterNow();
}
public Boolean personInStudentGroupAttends(StudentGroup studentGroup, Person person) {
return studentGroup.getAttendsSet().stream().map(Attends::getRegistration).map(Registration::getPerson)
.anyMatch(p -> p.equals(AccessControl.getPerson()));
}
public Boolean personInGroupingAttends(Grouping grouping, Person person) {
return grouping.getAttendsSet().stream()
.filter(attends -> grouping.getExecutionCourses().contains(attends.getExecutionCourse()))
.map(Attends::getRegistration).map(Registration::getPerson).anyMatch(p -> p.equals(AccessControl.getPerson()));
}
}