/**
* 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/>.
*/
/*
* Created on 08/Mar/2005
*
*/
package org.fenixedu.academic.domain;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import org.fenixedu.academic.domain.exceptions.DomainException;
import org.fenixedu.academic.domain.student.Registration;
import org.fenixedu.academic.util.Bundle;
import org.fenixedu.academic.util.EnrolmentGroupPolicyType;
import org.fenixedu.academic.util.ProposalState;
import org.fenixedu.bennu.core.domain.Bennu;
import pt.ist.fenixframework.FenixFramework;
/**
* @author joaosa & rmalo
*
*/
public class Grouping extends Grouping_Base {
public static Comparator<Grouping> COMPARATOR_BY_ENROLMENT_BEGIN_DATE = new Comparator<Grouping>() {
@Override
public int compare(Grouping g1, Grouping g2) {
return g1.getEnrolmentBeginDayDateDateTime().compareTo(g2.getEnrolmentBeginDayDateDateTime());
}
};
public Grouping() {
super();
setRootDomainObject(Bennu.getInstance());
}
public Calendar getEnrolmentBeginDay() {
if (this.getEnrolmentBeginDayDate() != null) {
Calendar result = Calendar.getInstance();
result.setTime(this.getEnrolmentBeginDayDate());
return result;
}
return null;
}
public void setEnrolmentBeginDay(Calendar enrolmentBeginDay) {
if (enrolmentBeginDay != null) {
this.setEnrolmentBeginDayDate(enrolmentBeginDay.getTime());
} else {
this.setEnrolmentBeginDayDate(null);
}
}
public Calendar getEnrolmentEndDay() {
if (this.getEnrolmentEndDayDate() != null) {
Calendar result = Calendar.getInstance();
result.setTime(this.getEnrolmentEndDayDate());
return result;
}
return null;
}
public void setEnrolmentEndDay(Calendar enrolmentEndDay) {
if (enrolmentEndDay != null) {
this.setEnrolmentEndDayDate(enrolmentEndDay.getTime());
} else {
this.setEnrolmentEndDayDate(null);
}
}
public List<ExecutionCourse> getExecutionCourses() {
final List<ExecutionCourse> result = new ArrayList<ExecutionCourse>();
for (final ExportGrouping exportGrouping : this.getExportGroupingsSet()) {
if (exportGrouping.getProposalState().getState() == ProposalState.ACEITE
|| exportGrouping.getProposalState().getState() == ProposalState.CRIADOR) {
result.add(exportGrouping.getExecutionCourse());
}
}
return result;
}
public List<StudentGroup> getStudentGroupsWithoutShift() {
final List<StudentGroup> result = new ArrayList<StudentGroup>();
for (final StudentGroup studentGroup : this.getStudentGroupsSet()) {
if (studentGroup.getShift() == null) {
result.add(studentGroup);
}
}
return result;
}
public List<StudentGroup> getStudentGroupsWithShift() {
final List<StudentGroup> result = new ArrayList<StudentGroup>();
for (final StudentGroup studentGroup : this.getStudentGroupsSet()) {
if (studentGroup.getShift() != null) {
result.add(studentGroup);
}
}
return result;
}
public Integer getNumberOfStudentsNotInGrouping() {
int numberOfStudents = 0;
for (final ExportGrouping exportGrouping : this.getExportGroupingsSet()) {
if (exportGrouping.getProposalState().getState() == ProposalState.ACEITE
|| exportGrouping.getProposalState().getState() == ProposalState.CRIADOR) {
for (final Attends attend : exportGrouping.getExecutionCourse().getAttendsSet()) {
if (!this.getAttendsSet().contains(attend)) {
numberOfStudents++;
}
}
}
}
return Integer.valueOf(numberOfStudents);
}
public void checkShiftCapacity(Shift shift) {
List shiftStudentGroups = this.readAllStudentGroupsBy(shift);
Integer groupMaximumNumber;
if (this.getDifferentiatedCapacity()) {
groupMaximumNumber = shift.getShiftGroupingProperties().getCapacity();
} else {
groupMaximumNumber = this.getGroupMaximumNumber();
}
if (shiftStudentGroups != null && groupMaximumNumber != null && shiftStudentGroups.size() == groupMaximumNumber) {
throw new DomainException(this.getClass().getName(), "error.shift.with.max.number.of.studentGroups");
}
}
public Integer getNumberOfStudentsInGrouping() {
return this.getAttendsSet().size();
}
public Attends getStudentAttend(final Registration registration) {
for (final Attends attend : this.getAttendsSet()) {
if (attend.getRegistration().getStudent() == registration.getStudent()) {
return attend;
}
}
return null;
}
public Attends getStudentAttend(String studentUsername) {
for (final Attends attend : this.getAttendsSet()) {
if (attend.getRegistration().getPerson().getUsername().equals(studentUsername)) {
return attend;
}
}
return null;
}
public StudentGroup readStudentGroupBy(Integer studentGroupNumber) {
for (final StudentGroup studentGroup : this.getStudentGroupsSet()) {
if (studentGroup.getGroupNumber().equals(studentGroupNumber)) {
return studentGroup;
}
}
return null;
}
public List<StudentGroup> readAllStudentGroupsBy(Shift shift) {
final List<StudentGroup> result = new ArrayList<StudentGroup>();
for (final StudentGroup studentGroup : this.getStudentGroupsSet()) {
if (studentGroup.getShift() == shift) {
result.add(studentGroup);
}
}
return result;
}
public static Grouping create(String goupingName, Date enrolmentBeginDay, Date enrolmentEndDay,
EnrolmentGroupPolicyType enrolmentGroupPolicyType, Integer groupMaximumNumber, Integer idealCapacity,
Integer maximumCapacity, Integer minimumCapacity, String projectDescription, ShiftType shiftType,
Boolean automaticEnrolment, Boolean differentiatedCapacity, ExecutionCourse executionCourse,
Map<String, Integer> shiftCapacityMap) {
if (goupingName == null || enrolmentBeginDay == null || enrolmentEndDay == null || enrolmentGroupPolicyType == null) {
throw new NullPointerException();
}
checkIfGroupingAlreadyExistInExecutionCourse(goupingName, executionCourse);
Grouping grouping = new Grouping();
grouping.setName(goupingName);
grouping.setEnrolmentBeginDayDate(enrolmentBeginDay);
grouping.setEnrolmentEndDayDate(enrolmentEndDay);
grouping.setEnrolmentPolicy(enrolmentGroupPolicyType);
grouping.setGroupMaximumNumber(groupMaximumNumber);
grouping.setIdealCapacity(idealCapacity);
grouping.setMaximumCapacity(maximumCapacity);
grouping.setMinimumCapacity(minimumCapacity);
grouping.setProjectDescription(projectDescription);
grouping.setShiftType(shiftType);
grouping.setAutomaticEnrolment(automaticEnrolment);
grouping.setDifferentiatedCapacity(differentiatedCapacity);
ExportGrouping exportGrouping = new ExportGrouping(grouping, executionCourse);
exportGrouping.setProposalState(new ProposalState(ProposalState.CRIADOR));
addGroupingToAttends(grouping, executionCourse.getAttendsSet());
GroupsAndShiftsManagementLog.createLog(executionCourse, Bundle.MESSAGING,
"log.executionCourse.groupAndShifts.grouping.added", grouping.getName(), executionCourse.getNome(),
executionCourse.getDegreePresentationString());
if (differentiatedCapacity) {
setDiferentiatedCapacityShiftsGroupingProperties(shiftType, shiftCapacityMap, grouping);
}
return grouping;
}
private static void addGroupingToAttends(final Grouping grouping, final Collection<Attends> attends) {
for (final Attends attend : attends) {
attend.addGroupings(grouping);
}
}
private static void checkIfGroupingAlreadyExistInExecutionCourse(final String goupingName,
final ExecutionCourse executionCourse) {
if (executionCourse.getGroupingByName(goupingName) != null) {
throw new DomainException("error.exception.existing.groupProperties");
}
}
public void edit(String goupingName, Date enrolmentBeginDay, Date enrolmentEndDay,
EnrolmentGroupPolicyType enrolmentGroupPolicyType, Integer groupMaximumNumber, Integer idealCapacity,
Integer maximumCapacity, Integer minimumCapacity, String projectDescription, ShiftType shiftType,
Boolean automaticEnrolment, Boolean differentiatedCapacity, Map<String, Integer> shiftCapacityMap) {
if (goupingName == null || enrolmentBeginDay == null || enrolmentEndDay == null || enrolmentGroupPolicyType == null) {
throw new NullPointerException();
}
checkIfGroupingAlreadyExists(goupingName);
if (getDifferentiatedCapacity() && !differentiatedCapacity) {
if (!super.getStudentGroupsSet().isEmpty()) {
throw new DomainException(this.getClass().getName(), "error.groupProperties.edit.attendsSet.withGroups");
}
Collection<ShiftGroupingProperties> shiftGroupingProperties = this.getShiftGroupingPropertiesSet();
for (ShiftGroupingProperties shiftGP : shiftGroupingProperties) {
shiftGP.delete();
}
} else if (getDifferentiatedCapacity() && differentiatedCapacity && isShiftTypeDifferent(shiftType)) {
if (!super.getStudentGroupsSet().isEmpty()) {
throw new DomainException(this.getClass().getName(), "error.groupProperties.edit.attendsSet.withGroups");
}
Collection<ShiftGroupingProperties> shiftGroupingProperties = this.getShiftGroupingPropertiesSet();
for (ShiftGroupingProperties shiftGP : shiftGroupingProperties) {
shiftGP.delete();
}
}
Integer groupMaximumNumberFix;
if (groupMaximumNumber == null) {
groupMaximumNumberFix = Integer.MAX_VALUE;
} else {
groupMaximumNumberFix = groupMaximumNumber;
}
if (!differentiatedCapacity && groupMaximumNumberFix < getMaxStudentGroupsCount()) {
throw new DomainException(this.getClass().getName(),
"error.groupProperties.edit.maxGroupCap.inferiorToExistingNumber");
}
setName(goupingName);
setEnrolmentBeginDayDate(enrolmentBeginDay);
setEnrolmentEndDayDate(enrolmentEndDay);
setEnrolmentPolicy(enrolmentGroupPolicyType);
setGroupMaximumNumber(groupMaximumNumber);
setIdealCapacity(idealCapacity);
setMaximumCapacity(maximumCapacity);
setMinimumCapacity(minimumCapacity);
setProjectDescription(projectDescription);
setShiftType(shiftType);
setAutomaticEnrolment(automaticEnrolment);
setDifferentiatedCapacity(differentiatedCapacity);
if (!differentiatedCapacity) {
Collection<ShiftGroupingProperties> shiftGroupingProperties = this.getShiftGroupingPropertiesSet();
for (ShiftGroupingProperties shiftGP : shiftGroupingProperties) {
shiftGP.delete();
}
} else {
setDiferentiatedCapacityShiftsGroupingProperties(shiftType, shiftCapacityMap, this);
}
if (shiftType == null) {
unEnrollStudentGroups(this.getStudentGroupsSet());
}
List<ExecutionCourse> ecs = getExecutionCourses();
for (ExecutionCourse ec : ecs) {
GroupsAndShiftsManagementLog.createLog(ec, Bundle.MESSAGING, "log.executionCourse.groupAndShifts.grouping.edited",
getName(), ec.getNome(), ec.getDegreePresentationString());
}
}
private static void setDiferentiatedCapacityShiftsGroupingProperties(ShiftType shiftType,
Map<String, Integer> shiftCapacityMap, Grouping grouping) {
shiftCapacityMap.forEach((shiftID, capacity) -> {
Shift shift = ((Shift) FenixFramework.getDomainObject(shiftID));
if (shift.getTypes().contains(shiftType)) {
if (capacity != null && grouping.getStudentGroupsIndexedByShift().get(shift) != null
&& capacity < grouping.getStudentGroupsIndexedByShift().get(shift).size()) {
throw new DomainException("error.groupProperties.edit.maxGroupCap.inferiorToExistingNumber");
}
if (shift.getShiftGroupingProperties() == null) {
shift.setShiftGroupingProperties(new ShiftGroupingProperties(shift, grouping, capacity));
} else {
shift.getShiftGroupingProperties().setCapacity(capacity);
}
}
});
}
private boolean isShiftTypeEqual(ShiftType shiftType) {
return ((shiftType != null && getShiftType() != null && getShiftType().compareTo(shiftType) == 0) || (shiftType == null && getShiftType() == null));
}
private boolean isShiftTypeDifferent(ShiftType shiftType) {
return (((shiftType == null && getShiftType() != null) || (shiftType != null && getShiftType() == null)) || getShiftType()
.compareTo(shiftType) != 0);
}
private Integer getMaxStudentGroupsCount() {
final Map<Object, Integer> shiftCountMap = new HashMap<Object, Integer>();
for (final StudentGroup studentGroup : super.getStudentGroupsSet()) {
if (!studentGroup.wasDeleted()) {
final Shift shift = studentGroup.getShift();
final int count = shiftCountMap.containsKey(shift) ? shiftCountMap.get(shift) + 1 : 1;
shiftCountMap.put(shift, Integer.valueOf(count));
}
}
int max = 0;
for (final Integer i : shiftCountMap.values()) {
if (i.intValue() > max) {
max = i.intValue();
}
}
return max;
}
private void checkIfGroupingAlreadyExists(String groupingName) {
if (!this.getName().equals(groupingName)) {
for (final ExecutionCourse executionCourse : this.getExecutionCourses()) {
if (executionCourse.getGroupingByName(groupingName) != null) {
throw new DomainException(this.getClass().getName(), "error.exception.existing.groupProperties");
}
}
}
}
private void unEnrollStudentGroups(Collection<StudentGroup> studentGroups) {
for (final StudentGroup studentGroup : studentGroups) {
studentGroup.setShift(null);
}
}
public void createStudentGroup(Shift shift, Integer groupNumber, List<Registration> students) {
if (groupNumber == null || students == null) {
throw new NullPointerException();
}
if (readStudentGroupBy(groupNumber) != null) {
throw new DomainException(this.getClass().getName(), "error.invalidGroupNumber");
}
checkForStudentsInStudentGroupsAndGrouping(students);
StudentGroup newStudentGroup = null;
if (shift != null) {
newStudentGroup = new StudentGroup(groupNumber, this, shift);
} else {
newStudentGroup = new StudentGroup(groupNumber, this);
}
StringBuilder sbStudentNumbers = new StringBuilder("");
sbStudentNumbers.setLength(0);
for (Registration registration : students) {
Attends attend = getStudentAttend(registration);
newStudentGroup.addAttends(attend);
if (sbStudentNumbers.length() != 0) {
sbStudentNumbers.append(", " + registration.getNumber().toString());
} else {
sbStudentNumbers.append(registration.getNumber().toString());
}
}
final String labelKey;
if (sbStudentNumbers.length() == 0) {
labelKey = "log.executionCourse.groupAndShifts.grouping.group.added.empty";
} else {
labelKey = "log.executionCourse.groupAndShifts.grouping.group.added";
}
List<ExecutionCourse> ecs = getExecutionCourses();
for (ExecutionCourse ec : ecs) {
GroupsAndShiftsManagementLog.createLog(ec, Bundle.MESSAGING, labelKey, groupNumber.toString(), getName(),
Integer.toString(students.size()), sbStudentNumbers.toString(), ec.getNome(),
ec.getDegreePresentationString());
}
}
private void checkForStudentsInStudentGroupsAndGrouping(List<Registration> students) {
for (Registration registration : students) {
Attends attend = getStudentAttend(registration);
for (final StudentGroup studentGroup : this.getStudentGroupsSet()) {
if (studentGroup.getAttendsSet().contains(attend)) {
throw new DomainException(this.getClass().getName(), "errors.existing.studentEnrolment");
} else if (!this.getAttendsSet().contains(attend)) {
throw new DomainException(this.getClass().getName(), "errors.notExisting.studentInGrouping");
}
}
}
}
public void delete() {
if (!super.getStudentGroupsSet().isEmpty()) {
throw new DomainException(this.getClass().getName(), "");
}
if (getGroupingGroup() != null) {
throw new DomainException("error.grouping.cannotDeleteGroupingUsedInAccessControl");
}
List<ExecutionCourse> ecs = getExecutionCourses();
for (ExecutionCourse ec : ecs) {
GroupsAndShiftsManagementLog.createLog(ec, Bundle.MESSAGING, "log.executionCourse.groupAndShifts.grouping.removed",
getName(), ec.getNome(), ec.getDegreePresentationString());
}
Collection<Attends> attends = this.getAttendsSet();
List<Attends> attendsAux = new ArrayList<Attends>();
attendsAux.addAll(attends);
for (Attends attend : attendsAux) {
attend.removeGroupings(this);
}
Collection<ExportGrouping> exportGroupings = this.getExportGroupingsSet();
List<ExportGrouping> exportGroupingsAux = new ArrayList<ExportGrouping>();
exportGroupingsAux.addAll(exportGroupings);
for (ExportGrouping exportGrouping : exportGroupingsAux) {
ExecutionCourse executionCourse = exportGrouping.getExecutionCourse();
executionCourse.removeExportGroupings(exportGrouping);
exportGrouping.delete();
}
for (ShiftGroupingProperties shiftGP : getShiftGroupingPropertiesSet()) {
shiftGP.delete();
}
for (Project project : getProjectsSet()) {
project.delete();
}
setRootDomainObject(null);
super.deleteDomainObject();
}
public int findMaxGroupNumber() {
int max = 0;
for (final StudentGroup studentGroup : super.getStudentGroupsSet()) {
max = Math.max(max, studentGroup.getGroupNumber().intValue());
}
return max;
}
public ExportGrouping getExportGrouping(final ExecutionCourse executionCourse) {
for (final ExportGrouping exportGrouping : this.getExportGroupingsSet()) {
if (exportGrouping.getExecutionCourse() == executionCourse) {
return exportGrouping;
}
}
return null;
}
public boolean hasExportGrouping(final ExecutionCourse executionCourse) {
return getExportGrouping(executionCourse) != null;
}
public StudentGroup getStudentGroupByAttends(Attends attends) {
for (StudentGroup studentGroup : getStudentGroupsSet()) {
if (studentGroup.getAttendsSet().contains(attends)) {
return studentGroup;
}
}
return null;
}
public Map<Shift, SortedSet<StudentGroup>> getStudentGroupsIndexedByShift() {
final Map<Shift, SortedSet<StudentGroup>> map =
new TreeMap<Shift, SortedSet<StudentGroup>>(Shift.SHIFT_COMPARATOR_BY_TYPE_AND_ORDERED_LESSONS);
for (final StudentGroup studentGroup : getStudentGroupsSet()) {
if (studentGroup.getShift() != null) {
final Shift shift = studentGroup.getShift();
final SortedSet<StudentGroup> studentGroups;
if (map.containsKey(shift)) {
studentGroups = map.get(shift);
} else {
studentGroups = new TreeSet<StudentGroup>(StudentGroup.COMPARATOR_BY_GROUP_NUMBER);
map.put(shift, studentGroups);
}
studentGroups.add(studentGroup);
}
}
return map;
}
public SortedSet<StudentGroup> getStudentGroupsOrderedByGroupNumber() {
final SortedSet<StudentGroup> studentGroups = new TreeSet<StudentGroup>(StudentGroup.COMPARATOR_BY_GROUP_NUMBER);
studentGroups.addAll(getStudentGroupsSet());
return studentGroups;
}
public boolean isPersonTeacher(Person person) {
for (ExecutionCourse ec : getExecutionCourses()) {
for (Professorship professorship : ec.getProfessorshipsSet()) {
if (professorship.getPerson() == person) {
return true;
}
}
}
return false;
}
@Override
public Set<StudentGroup> getStudentGroupsSet() {
Set<StudentGroup> result = new HashSet<StudentGroup>();
for (StudentGroup sg : super.getStudentGroupsSet()) {
if (!sg.wasDeleted()) {
result.add(sg);
}
}
return Collections.unmodifiableSet(result);
}
public List<StudentGroup> getDeletedStudentGroups() {
List<StudentGroup> result = new ArrayList<StudentGroup>();
for (StudentGroup sg : super.getStudentGroupsSet()) {
if (!sg.getValid()) {
result.add(sg);
}
}
return result;
}
@Deprecated
public java.util.Date getEnrolmentBeginDayDate() {
org.joda.time.DateTime dt = getEnrolmentBeginDayDateDateTime();
return (dt == null) ? null : new java.util.Date(dt.getMillis());
}
@Deprecated
public void setEnrolmentBeginDayDate(java.util.Date date) {
if (date == null) {
setEnrolmentBeginDayDateDateTime(null);
} else {
setEnrolmentBeginDayDateDateTime(new org.joda.time.DateTime(date.getTime()));
}
}
@Deprecated
public java.util.Date getEnrolmentEndDayDate() {
org.joda.time.DateTime dt = getEnrolmentEndDayDateDateTime();
return (dt == null) ? null : new java.util.Date(dt.getMillis());
}
@Deprecated
public void setEnrolmentEndDayDate(java.util.Date date) {
if (date == null) {
setEnrolmentEndDayDateDateTime(null);
} else {
setEnrolmentEndDayDateDateTime(new org.joda.time.DateTime(date.getTime()));
}
}
}