/**
* 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.domain.studentCurriculum;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.function.Predicate;
import java.util.stream.Stream;
import org.fenixedu.academic.domain.CurricularCourse;
import org.fenixedu.academic.domain.DegreeCurricularPlan;
import org.fenixedu.academic.domain.DomainObjectUtil;
import org.fenixedu.academic.domain.Enrolment;
import org.fenixedu.academic.domain.ExecutionSemester;
import org.fenixedu.academic.domain.ExecutionYear;
import org.fenixedu.academic.domain.Grade;
import org.fenixedu.academic.domain.Person;
import org.fenixedu.academic.domain.StudentCurricularPlan;
import org.fenixedu.academic.domain.curricularRules.CurricularRuleType;
import org.fenixedu.academic.domain.curricularRules.ICurricularRule;
import org.fenixedu.academic.domain.degreeStructure.DegreeModule;
import org.fenixedu.academic.domain.enrolment.IDegreeModuleToEvaluate;
import org.fenixedu.academic.domain.exceptions.DomainException;
import org.fenixedu.academic.domain.student.Registration;
import org.fenixedu.academic.domain.student.Student;
import org.fenixedu.academic.domain.student.curriculum.Curriculum;
import org.fenixedu.academic.util.Bundle;
import org.fenixedu.academic.util.MultiLanguageString;
import org.fenixedu.academic.util.predicates.ResultCollection;
import org.fenixedu.bennu.core.i18n.BundleUtil;
import org.joda.time.DateTime;
import org.joda.time.YearMonthDay;
abstract public class CurriculumModule extends CurriculumModule_Base {
static final public Comparator<CurriculumModule> COMPARATOR_BY_NAME_AND_ID = new Comparator<CurriculumModule>() {
@Override
public int compare(CurriculumModule o1, CurriculumModule o2) {
int result = o1.getName().compareTo(o2.getName());
return (result == 0) ? DomainObjectUtil.COMPARATOR_BY_ID.compare(o1, o2) : result;
}
};
static final public Comparator<CurriculumModule> COMPARATOR_BY_FULL_PATH_NAME_AND_ID = new Comparator<CurriculumModule>() {
@Override
public int compare(CurriculumModule o1, CurriculumModule o2) {
int result = o1.getFullPath().compareTo(o2.getFullPath());
return (result == 0) ? DomainObjectUtil.COMPARATOR_BY_ID.compare(o1, o2) : result;
}
};
static final public Comparator<CurriculumModule> COMPARATOR_BY_CREATION_DATE = new Comparator<CurriculumModule>() {
@Override
public int compare(CurriculumModule o1, CurriculumModule o2) {
return o1.getCreationDateDateTime().compareTo(o2.getCreationDateDateTime());
}
};
public CurriculumModule() {
super();
setCreationDateDateTime(new DateTime());
}
public void deleteRecursive() {
delete();
}
public void delete() {
DomainException.throwWhenDeleteBlocked(getDeletionBlockers());
setDegreeModule(null);
setCurriculumGroup(null);
super.deleteDomainObject();
}
public RootCurriculumGroup getRootCurriculumGroup() {
return getCurriculumGroup() != null ? getCurriculumGroup().getRootCurriculumGroup() : (RootCurriculumGroup) this;
}
public CycleCurriculumGroup getParentCycleCurriculumGroup() {
return getCurriculumGroup() != null ? getCurriculumGroup().getParentCycleCurriculumGroup() : null;
}
public boolean isCycleCurriculumGroup() {
return false;
}
public BranchCurriculumGroup getParentBranchCurriculumGroup() {
return getCurriculumGroup() != null ? getCurriculumGroup().getParentBranchCurriculumGroup() : null;
}
public boolean isBranchCurriculumGroup() {
return false;
}
public boolean isNoCourseGroupCurriculumGroup() {
return false;
}
public boolean isEnrolment() {
return false;
}
public boolean isDismissal() {
return false;
}
public boolean isCreditsDismissal() {
return false;
}
public boolean isCurriculumLine() {
return isLeaf();
}
abstract public boolean isLeaf();
abstract public boolean isRoot();
abstract public StringBuilder print(String tabs);
abstract public List<Enrolment> getEnrolments();
public abstract StudentCurricularPlan getStudentCurricularPlan();
final public boolean isBolonhaDegree() {
return getStudentCurricularPlan().isBolonhaDegree();
}
public DegreeCurricularPlan getDegreeCurricularPlanOfStudent() {
return getStudentCurricularPlan().getDegreeCurricularPlan();
}
public DegreeCurricularPlan getDegreeCurricularPlanOfDegreeModule() {
if (getDegreeModule() != null) {
return getDegreeModule().getParentDegreeCurricularPlan();
}
return null;
}
public MultiLanguageString getName() {
MultiLanguageString multiLanguageString = new MultiLanguageString();
if (this.getDegreeModule().getName() != null && this.getDegreeModule().getName().length() > 0) {
multiLanguageString = multiLanguageString.with(MultiLanguageString.pt, this.getDegreeModule().getName());
}
if (this.getDegreeModule().getNameEn() != null && this.getDegreeModule().getNameEn().length() > 0) {
multiLanguageString = multiLanguageString.with(MultiLanguageString.en, this.getDegreeModule().getNameEn());
}
return multiLanguageString;
}
public MultiLanguageString getPresentationName() {
return getName();
}
public boolean isApproved(final CurricularCourse curricularCourse) {
return isApproved(curricularCourse, null);
}
public boolean hasDegreeModule(final DegreeModule degreeModule) {
return this.getDegreeModule().equals(degreeModule);
}
public boolean hasCurriculumModule(final CurriculumModule curriculumModule) {
return this.equals(curriculumModule);
}
public boolean parentCurriculumGroupIsNoCourseGroupCurriculumGroup() {
return getCurriculumGroup() != null && getCurriculumGroup().isNoCourseGroupCurriculumGroup();
}
public boolean parentAllowAccumulatedEctsCredits() {
return !parentCurriculumGroupIsNoCourseGroupCurriculumGroup()
|| ((NoCourseGroupCurriculumGroup) getCurriculumGroup()).allowAccumulatedEctsCredits();
}
public Set<ICurricularRule> getCurricularRules(ExecutionSemester executionSemester) {
final Set<ICurricularRule> result =
getCurriculumGroup() != null ? getCurriculumGroup().getCurricularRules(executionSemester) : new HashSet<ICurricularRule>();
result.addAll(getDegreeModule().getCurricularRules(executionSemester));
return result;
}
public ICurricularRule getMostRecentActiveCurricularRule(final CurricularRuleType ruleType, final ExecutionYear executionYear) {
return getDegreeModule().getMostRecentActiveCurricularRule(ruleType, getCurriculumGroup().getDegreeModule(),
executionYear);
}
public ICurricularRule getMostRecentActiveCurricularRule(final CurricularRuleType ruleType,
final ExecutionSemester executionSemester) {
return getDegreeModule().getMostRecentActiveCurricularRule(ruleType, getCurriculumGroup().getDegreeModule(),
executionSemester);
}
public String getFullPath() {
if (isRoot()) {
return getName().getContent();
} else {
return getCurriculumGroup().getFullPath() + " > " + getName().getContent();
}
}
public boolean isFor(final DegreeCurricularPlan degreeCurricularPlan) {
return getDegreeModule().getParentDegreeCurricularPlan() == degreeCurricularPlan;
}
public boolean isFor(final Registration registration) {
return getRegistration() == registration;
}
final public Registration getRegistration() {
return getStudentCurricularPlan().getRegistration();
}
final public Student getStudent() {
return getRegistration().getStudent();
}
final public Person getPerson() {
return getStudent().getPerson();
}
public boolean isConcluded() {
return isConcluded(getApprovedCurriculumLinesLastExecutionYear()).value();
}
public ExecutionYear getApprovedCurriculumLinesLastExecutionYear() {
final SortedSet<ExecutionYear> executionYears = new TreeSet<ExecutionYear>(ExecutionYear.COMPARATOR_BY_YEAR);
for (final CurriculumLine curriculumLine : getApprovedCurriculumLines()) {
if (curriculumLine.hasExecutionPeriod()) {
executionYears.add(curriculumLine.getExecutionPeriod().getExecutionYear());
}
}
return executionYears.isEmpty() ? ExecutionYear.readCurrentExecutionYear() : executionYears.last();
}
final public Collection<CurriculumLine> getApprovedCurriculumLines() {
final Collection<CurriculumLine> result = new HashSet<CurriculumLine>();
addApprovedCurriculumLines(result);
return result;
}
final public CurriculumLine getLastApprovement() {
final SortedSet<CurriculumLine> curriculumLines =
new TreeSet<CurriculumLine>(CurriculumLine.COMPARATOR_BY_APPROVEMENT_DATE_AND_ID);
curriculumLines.addAll(getApprovedCurriculumLines());
if (curriculumLines.isEmpty()) {
throw new DomainException("error.curriculum.group.has.no.approved.curriculum.lines", getName().getContent());
}
return curriculumLines.last();
}
final public YearMonthDay getLastApprovementDate() {
return getLastApprovement().getApprovementDate();
}
final public ExecutionYear getLastApprovementExecutionYear() {
return getLastApprovement().getExecutionYear();
}
final protected boolean wasCreated(final DateTime when) {
return getCreationDateDateTime() == null || getCreationDateDateTime().isBefore(when);
}
final public Curriculum getCurriculum() {
return getCurriculum(new DateTime(), (ExecutionYear) null);
}
final public Curriculum getCurriculum(final DateTime when) {
return wasCreated(when) ? getCurriculum(when, (ExecutionYear) null) : Curriculum.createEmpty(this, (ExecutionYear) null);
}
final public Curriculum getCurriculum(final ExecutionYear executionYear) {
return getCurriculum(new DateTime(), executionYear);
}
public Grade calculateRawGrade() {
return getCurriculum().getRawGrade();
}
public Grade calculateFinalGrade() {
return getCurriculum().getFinalGrade();
}
public Double getCreditsConcluded() {
return getCreditsConcluded(getApprovedCurriculumLinesLastExecutionYear());
}
abstract public Double getEctsCredits();
abstract public Double getAprovedEctsCredits();
abstract public Double getEnroledEctsCredits(final ExecutionSemester executionSemester);
abstract public boolean isApproved(final CurricularCourse curricularCourse, final ExecutionSemester executionSemester);
abstract public boolean isEnroledInExecutionPeriod(final CurricularCourse curricularCourse,
final ExecutionSemester executionSemester);
abstract public boolean hasAnyEnrolments();
abstract public void addApprovedCurriculumLines(final Collection<CurriculumLine> result);
abstract public boolean hasAnyApprovedCurriculumLines();
abstract public boolean hasEnrolmentWithEnroledState(final CurricularCourse curricularCourse,
final ExecutionSemester executionSemester);
abstract public ExecutionYear getIEnrolmentsLastExecutionYear();
abstract public Enrolment findEnrolmentFor(final CurricularCourse curricularCourse, final ExecutionSemester executionSemester);
abstract public Set<IDegreeModuleToEvaluate> getDegreeModulesToEvaluate(final ExecutionSemester executionSemester);
abstract public Enrolment getApprovedEnrolment(final CurricularCourse curricularCourse);
abstract public CurriculumLine getApprovedCurriculumLine(final CurricularCourse curricularCourse);
abstract public Dismissal getDismissal(final CurricularCourse curricularCourse);
abstract public Collection<Enrolment> getSpecialSeasonEnrolments(ExecutionYear executionYear);
abstract public Collection<Enrolment> getSpecialSeasonEnrolments(ExecutionSemester executionSemester);
abstract public void collectDismissals(final List<Dismissal> result);
abstract public void getAllDegreeModules(Collection<DegreeModule> degreeModules);
abstract public Set<CurriculumLine> getAllCurriculumLines();
abstract public Stream<CurriculumLine> getCurriculumLineStream();
abstract public ConclusionValue isConcluded(ExecutionYear executionYear);
abstract public boolean hasConcluded(DegreeModule degreeModule, ExecutionYear executionYear);
public abstract YearMonthDay calculateConclusionDate();
abstract public Curriculum getCurriculum(final DateTime when, final ExecutionYear executionYear);
abstract public Double getCreditsConcluded(ExecutionYear executionYear);
abstract public boolean isPropaedeutic();
abstract public boolean hasEnrolment(ExecutionYear executionYear);
abstract public boolean hasEnrolment(ExecutionSemester executionSemester);
abstract public boolean isEnroledInSpecialSeason(final ExecutionSemester executionSemester);
abstract public boolean isEnroledInSpecialSeason(final ExecutionYear executionYear);
/**
* This enum represent possible conclusion values when checking registration
* processed - UNKNOWN: is used when some group doesn't have information to
* calculate it's value, for instance, doesn't have any curricular rules
*
*/
static public enum ConclusionValue {
CONCLUDED(true) {
@Override
public boolean isValid() {
return true;
}
},
NOT_CONCLUDED(false) {
@Override
public boolean isValid() {
return false;
}
},
UNKNOWN(false) {
@Override
public boolean isValid() {
return true;
}
};
private boolean value;
private ConclusionValue(final boolean value) {
this.value = value;
}
public boolean value() {
return this.value;
}
abstract public boolean isValid();
static public ConclusionValue create(final boolean value) {
return value ? CONCLUDED : NOT_CONCLUDED;
}
public String getLocalizedName() {
return BundleUtil.getString(Bundle.ENUMERATION, ConclusionValue.class.getSimpleName() + "." + name());
}
}
abstract public int getNumberOfAllApprovedEnrolments(final ExecutionSemester executionSemester);
abstract public void getCurriculumModules(final ResultCollection<CurriculumModule> collection);
public boolean hasAnyCurriculumModules(final Predicate<CurriculumModule> predicate) {
return predicate.test(this);
}
public boolean hasAnyCurriculumLines() {
return hasAnyCurriculumModules(new CurriculumModulePredicateByType(CurriculumLine.class));
}
abstract public Set<CurriculumGroup> getAllCurriculumGroups();
abstract public Set<CurriculumGroup> getAllCurriculumGroupsWithoutNoCourseGroupCurriculumGroups();
static public class CurriculumModulePredicateByType implements Predicate<CurriculumModule> {
private final Class<? extends CurriculumModule> clazz;
public CurriculumModulePredicateByType(final Class<? extends CurriculumModule> clazz) {
this.clazz = clazz;
}
@Override
public boolean test(final CurriculumModule curriculumModule) {
if (clazz.isAssignableFrom(curriculumModule.getClass())) {
return true;
}
return false;
}
}
static public class CurriculumModulePredicateByExecutionSemester implements Predicate<CurriculumModule> {
private final ExecutionSemester executionSemester;
public CurriculumModulePredicateByExecutionSemester(final ExecutionSemester executionSemester) {
this.executionSemester = executionSemester;
}
@Override
public boolean test(final CurriculumModule curriculumModule) {
if (curriculumModule.isCurriculumLine()) {
final CurriculumLine curriculumLine = (CurriculumLine) curriculumModule;
if (curriculumLine.getExecutionPeriod().equals(executionSemester)) {
return true;
}
}
return false;
}
}
static public class CurriculumModulePredicateByExecutionYear implements Predicate<CurriculumModule> {
private final ExecutionYear executionYear;
public CurriculumModulePredicateByExecutionYear(final ExecutionYear executionYear) {
this.executionYear = executionYear;
}
@Override
public boolean test(final CurriculumModule curriculumModule) {
if (curriculumModule.isCurriculumLine()) {
final CurriculumLine curriculumLine = (CurriculumLine) curriculumModule;
if (curriculumLine.getExecutionYear().equals(executionYear)) {
return true;
}
}
return false;
}
}
static public class CurriculumModulePredicateByApproval implements Predicate<CurriculumModule> {
@Override
public boolean test(final CurriculumModule curriculumModule) {
if (curriculumModule.isCurriculumLine()) {
final CurriculumLine curriculumLine = (CurriculumLine) curriculumModule;
if (curriculumLine.isApproved()) {
return true;
}
}
return false;
}
}
@Deprecated
public java.util.Date getCreationDate() {
org.joda.time.DateTime dt = getCreationDateDateTime();
return (dt == null) ? null : new java.util.Date(dt.getMillis());
}
@Deprecated
public void setCreationDate(java.util.Date date) {
if (date == null) {
setCreationDateDateTime(null);
} else {
setCreationDateDateTime(new org.joda.time.DateTime(date.getTime()));
}
}
}