package net.sourceforge.fenixedu.domain.degreeStructure; import java.text.Collator; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.ListIterator; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import net.sourceforge.fenixedu.domain.CurricularCourse; import net.sourceforge.fenixedu.domain.Degree; import net.sourceforge.fenixedu.domain.DegreeCurricularPlan; import net.sourceforge.fenixedu.domain.EquivalencePlan; import net.sourceforge.fenixedu.domain.EquivalencePlanEntry; import net.sourceforge.fenixedu.domain.ExecutionDegree; import net.sourceforge.fenixedu.domain.ExecutionSemester; import net.sourceforge.fenixedu.domain.ExecutionYear; import net.sourceforge.fenixedu.domain.RootDomainObject; import net.sourceforge.fenixedu.domain.curricularRules.CreditsLimit; import net.sourceforge.fenixedu.domain.curricularRules.CurricularRule; import net.sourceforge.fenixedu.domain.curricularRules.CurricularRuleType; import net.sourceforge.fenixedu.domain.curricularRules.DegreeModulesSelectionLimit; import net.sourceforge.fenixedu.domain.curricularRules.Exclusiveness; import net.sourceforge.fenixedu.domain.curricularRules.ICurricularRule; import net.sourceforge.fenixedu.domain.degree.DegreeType; import net.sourceforge.fenixedu.domain.exceptions.DomainException; import pt.utl.ist.fenix.tools.util.i18n.Language; import pt.utl.ist.fenix.tools.util.i18n.MultiLanguageString; abstract public class DegreeModule extends DegreeModule_Base { static final public Comparator COMPARATOR_BY_NAME = new Comparator() { @Override public int compare(DegreeModule o1, DegreeModule o2) { final int c = Collator.getInstance().compare(o1.getName(), o2.getName()); return c == 0 ? COMPARATOR_BY_ID.compare(o1, o2) : c; } }; public static class ComparatorByMinEcts implements Comparator { private ExecutionSemester executionSemester; public ComparatorByMinEcts(final ExecutionSemester executionSemester) { this.executionSemester = executionSemester; } public int compare(DegreeModule leftDegreeModule, DegreeModule rightDegreeModule) { int comparationResult = leftDegreeModule.getMinEctsCredits(this.executionSemester).compareTo( rightDegreeModule.getMinEctsCredits(this.executionSemester)); return (comparationResult == 0) ? leftDegreeModule.getIdInternal().compareTo(rightDegreeModule.getIdInternal()) : comparationResult; } } public DegreeModule() { super(); setRootDomainObject(RootDomainObject.getInstance()); } /** * We need a method to return a full name of a course group - from it's * parent course group to the degree curricular plan's root course group. * * Given this is impossible, for there are many routes from the root course * group to one particular course group, we choose (for now...) to get one * possible full name, always visiting the first element of every list of * contexts on our way to the root course group. * * @return A string with one possible full name of this course group */ protected void getOneFullName(final StringBuilder result, final ExecutionSemester executionSemester) { final String selfName = getNameI18N(executionSemester).getContent(Language.getUserLanguage()); if (isRoot()) { result.append(selfName); } else { List parentContextsByExecutionPeriod = getParentContextsByExecutionPeriod(executionSemester); if (parentContextsByExecutionPeriod.isEmpty()) { // if not existing, just return all (as previous implementation // of method parentContextsByExecutionPeriod = getParentContexts(); } final CourseGroup parentCourseGroup = parentContextsByExecutionPeriod.get(0).getParentCourseGroup(); parentCourseGroup.getOneFullName(result, executionSemester); result.append(FULL_NAME_SEPARATOR); result.append(selfName); } } private static final String FULL_NAME_SEPARATOR = " > "; public String getOneFullName(final ExecutionSemester executionSemester) { final StringBuilder result = new StringBuilder(); getOneFullName(result, executionSemester); return result.toString(); } public String getOneFullName() { return getOneFullName(null); } public MultiLanguageString getNameI18N(final ExecutionSemester executionSemester) { final MultiLanguageString multiLanguageString = new MultiLanguageString(); String name = getName(executionSemester); if (name != null && name.length() > 0) { multiLanguageString.setContent(Language.pt, name); } String nameEn = getNameEn(executionSemester); if (nameEn != null && nameEn.length() > 0) { multiLanguageString.setContent(Language.en, nameEn); } return multiLanguageString; } public MultiLanguageString getNameI18N(final ExecutionYear executionYear) { return getNameI18N((executionYear == null) ? null : executionYear.getLastExecutionPeriod()); } public MultiLanguageString getNameI18N() { return getNameI18N((ExecutionSemester) null); } protected String getName(final ExecutionSemester executionSemester) { return getName(); } protected String getNameEn(final ExecutionSemester executionSemester) { return getNameEn(); } public void delete() { if (getCanBeDeleted()) { for (; !getParentContexts().isEmpty(); getParentContexts().get(0).delete()) ; for (; !getCurricularRules().isEmpty(); getCurricularRules().get(0).delete()) ; for (; !getParticipatingPrecedenceCurricularRules().isEmpty(); getParticipatingPrecedenceCurricularRules().get(0) .delete()) ; for (; !getParticipatingExclusivenessCurricularRules().isEmpty(); getParticipatingExclusivenessCurricularRules().get( 0).delete()) ; } else { throw new DomainException("courseGroup.notEmptyCurriculumModules"); } } protected Boolean getCanBeDeleted() { return !hasAnyCurriculumModules(); } public void deleteContext(Context context) { if (hasParentContexts(context)) { context.delete(); } if (!hasAnyParentContexts()) { delete(); } } public Set getAllParentCourseGroups() { Set result = new HashSet(); collectParentCourseGroups(result, this); return result; } private void collectParentCourseGroups(Set result, DegreeModule module) { for (Context parent : module.getParentContexts()) { if (!parent.getParentCourseGroup().isRoot()) { result.add(parent.getParentCourseGroup()); collectParentCourseGroups(result, parent.getParentCourseGroup()); } } } public List getParticipatingCurricularRules() { final List result = new ArrayList(); result.addAll(getParticipatingPrecedenceCurricularRules()); result.addAll(getParticipatingExclusivenessCurricularRules()); return result; } public List getCurricularRules(final ExecutionYear executionYear) { final List result = new ArrayList(); for (final CurricularRule curricularRule : this.getCurricularRules()) { if (isCurricularRuleValid(curricularRule, executionYear)) { result.add(curricularRule); } } return result; } public List getCurricularRules(final ExecutionSemester executionSemester) { final List result = new ArrayList(); for (final CurricularRule curricularRule : this.getCurricularRules()) { if (isCurricularRuleValid(curricularRule, executionSemester)) { result.add(curricularRule); } } return result; } public List getVisibleCurricularRules(final ExecutionYear executionYear) { final List result = new ArrayList(); for (final CurricularRule curricularRule : this.getCurricularRules()) { if (curricularRule.isVisible() && (executionYear == null || curricularRule.isValid(executionYear))) { result.add(curricularRule); } } return result; } public List getVisibleCurricularRules(final ExecutionSemester executionSemester) { final List result = new ArrayList(); for (final CurricularRule curricularRule : this.getCurricularRules()) { if (curricularRule.isVisible() && isCurricularRuleValid(curricularRule, executionSemester)) { result.add(curricularRule); } } return result; } public List getCurricularRules(final Context context, final ExecutionSemester executionSemester) { final List result = new ArrayList(); for (final CurricularRule curricularRule : getCurricularRules()) { if (isCurricularRuleValid(curricularRule, executionSemester) && curricularRule.appliesToContext(context)) { result.add(curricularRule); } } return result; } private boolean isCurricularRuleValid(final ICurricularRule curricularRule, final ExecutionSemester executionSemester) { return executionSemester == null || curricularRule.isValid(executionSemester); } private boolean isCurricularRuleValid(final ICurricularRule curricularRule, final ExecutionYear executionYear) { return executionYear == null || curricularRule.isValid(executionYear); } public List getParentContextsByExecutionYear(ExecutionYear executionYear) { final List result = new ArrayList(); for (final Context context : getParentContextsSet()) { if (executionYear == null || context.isValid(executionYear)) { result.add(context); } } return result; } public List getParentContextsByExecutionPeriod(final ExecutionSemester executionSemester) { final List result = new ArrayList(); for (final Context context : getParentContextsSet()) { if (executionSemester == null || context.isValid(executionSemester)) { result.add(context); } } return result; } public List getParentContextsBy(final ExecutionSemester executionSemester, final CourseGroup parentCourseGroup) { final List result = new ArrayList(); for (final Context context : getParentContextsSet()) { if (context.isValid(executionSemester) && context.getParentCourseGroup() == parentCourseGroup) { result.add(context); } } return result; } public boolean hasAnyParentContexts(final ExecutionSemester executionSemester) { for (final Context context : getParentContextsSet()) { if (executionSemester == null || context.isValid(executionSemester)) { return true; } } return false; } public boolean hasAnyOpenParentContexts(final ExecutionSemester executionSemester) { for (final Context context : getParentContextsSet()) { if (executionSemester == null || context.isOpen(executionSemester)) { return true; } } return false; } private Boolean bolonhaDegree = null; public boolean isBolonhaDegree() { if (bolonhaDegree == null) { bolonhaDegree = Boolean.valueOf(getParentDegreeCurricularPlan().isBolonhaDegree()); } return bolonhaDegree.booleanValue(); } public boolean isOptional() { return false; } public boolean isCycleCourseGroup() { return false; } public boolean isCurricularCourse() { return false; } public boolean isCourseGroup() { return false; } public Degree getDegree() { return getParentDegreeCurricularPlan().getDegree(); } public DegreeType getDegreeType() { return getDegree().getDegreeType(); } public boolean hasOnlyOneParentCourseGroup() { return hasOnlyOneParentCourseGroup(null); } public boolean hasOnlyOneParentCourseGroup(final ExecutionSemester executionSemester) { DegreeModule degreeModule = null; for (final Context context : getParentContextsByExecutionPeriod(executionSemester)) { if (degreeModule == null) { degreeModule = context.getParentCourseGroup(); } else if (degreeModule != context.getParentCourseGroup()) { return false; } } return true; } public List getCurricularRules(final CurricularRuleType ruleType, final ExecutionSemester executionSemester) { final List result = new ArrayList(); for (final ICurricularRule curricularRule : getCurricularRules()) { if (curricularRule.hasCurricularRuleType(ruleType) && isCurricularRuleValid(curricularRule, executionSemester)) { result.add(curricularRule); } } return result; } public boolean hasAnyCurricularRules(final CurricularRuleType ruleType, final ExecutionSemester executionSemester) { for (final ICurricularRule curricularRule : getCurricularRules()) { if (curricularRule.hasCurricularRuleType(ruleType) && isCurricularRuleValid(curricularRule, executionSemester)) { return true; } } return false; } public List getCurricularRules(final CurricularRuleType ruleType, final ExecutionYear executionYear) { final List result = new ArrayList(); for (final ICurricularRule curricularRule : getCurricularRules()) { if (curricularRule.hasCurricularRuleType(ruleType) && isCurricularRuleValid(curricularRule, executionYear)) { result.add(curricularRule); } } return result; } public List getCurricularRules(final CurricularRuleType ruleType, final CourseGroup parentCourseGroup, final ExecutionYear executionYear) { final List result = new ArrayList(); for (final ICurricularRule curricularRule : getCurricularRules()) { if (curricularRule.hasCurricularRuleType(ruleType) && isCurricularRuleValid(curricularRule, executionYear) && curricularRule.appliesToCourseGroup(parentCourseGroup)) { result.add(curricularRule); } } return result; } public List getCurricularRules(final CurricularRuleType ruleType, final CourseGroup parentCourseGroup, final ExecutionSemester executionSemester) { final List result = new ArrayList(); for (final ICurricularRule curricularRule : getCurricularRules()) { if (curricularRule.hasCurricularRuleType(ruleType) && isCurricularRuleValid(curricularRule, executionSemester) && curricularRule.appliesToCourseGroup(parentCourseGroup)) { result.add(curricularRule); } } return result; } public ICurricularRule getMostRecentActiveCurricularRule(final CurricularRuleType ruleType, final CourseGroup parentCourseGroup, final ExecutionYear executionYear) { final List curricularRules = new ArrayList(getCurricularRules(ruleType, parentCourseGroup, (ExecutionYear) null)); Collections.sort(curricularRules, ICurricularRule.COMPARATOR_BY_BEGIN); if (curricularRules.isEmpty()) { return null; } else if (executionYear == null) { final ListIterator iter = curricularRules.listIterator(curricularRules.size()); while (iter.hasPrevious()) { final ICurricularRule curricularRule = iter.previous(); if (curricularRule.isActive()) { return curricularRule; } } return null; } else { ICurricularRule result = null; for (final ICurricularRule curricularRule : curricularRules) { if (curricularRule.isValid(executionYear)) { if (result != null) { // TODO: remove this throw when curricular rule ensures // that it can be only one active for execution period // and replace by: return curricularRule throw new DomainException("error.degree.module.has.more.than.one.credits.limit.for.executionYear", getName()); } result = curricularRule; } } return result; } } public ICurricularRule getMostRecentActiveCurricularRule(final CurricularRuleType ruleType, final CourseGroup parentCourseGroup, final ExecutionSemester executionSemester) { final List curricularRules = new ArrayList(getCurricularRules(ruleType, parentCourseGroup, executionSemester)); if (curricularRules.isEmpty()) { return null; } ICurricularRule result = null; for (final ICurricularRule curricularRule : curricularRules) { if (curricularRule.isValid(executionSemester)) { if (result != null) { // TODO: remove this throw when curricular rule ensures // that it can be only one active for execution period // and replace by: return curricularRule throw new DomainException("error.degree.module.has.more.than.one.credits.limit.for.executionPeriod", getName()); } result = curricularRule; } } return result; } public Double getMaxEctsCredits() { return getMaxEctsCredits(ExecutionSemester.readActualExecutionSemester()); } public Double getMinEctsCredits() { return getMinEctsCredits(ExecutionSemester.readActualExecutionSemester()); } public boolean hasDegreeModule(final DegreeModule degreeModule) { return this.equals(degreeModule); } public ExecutionSemester getMinimumExecutionPeriod() { if (isRoot()) { return isBolonhaDegree() ? getBeginBolonhaExecutionPeriod() : getFirstExecutionPeriodOfFirstExecutionDegree(); } final SortedSet executionSemesters = new TreeSet(); for (final Context context : getParentContextsSet()) { executionSemesters.add(context.getBeginExecutionPeriod()); } return executionSemesters.first(); } public ExecutionSemester getBeginBolonhaExecutionPeriod() { return ExecutionSemester.readFirstBolonhaExecutionPeriod(); } private ExecutionSemester getFirstExecutionPeriodOfFirstExecutionDegree() { final ExecutionDegree executionDegree = getParentDegreeCurricularPlan().getFirstExecutionDegree(); return executionDegree != null ? executionDegree.getExecutionYear().getFirstExecutionPeriod() : getBeginBolonhaExecutionPeriod(); } public DegreeModulesSelectionLimit getDegreeModulesSelectionLimitRule(final ExecutionSemester executionSemester) { final List result = (List) getCurricularRules( CurricularRuleType.DEGREE_MODULES_SELECTION_LIMIT, executionSemester); return result.isEmpty() ? null : (DegreeModulesSelectionLimit) result.get(0); } public CreditsLimit getCreditsLimitRule(final ExecutionSemester executionSemester) { final List result = getCurricularRules(CurricularRuleType.CREDITS_LIMIT, executionSemester); return result.isEmpty() ? null : (CreditsLimit) result.get(0); } public List getExclusivenessRules(final ExecutionSemester executionSemester) { return (List) getCurricularRules(CurricularRuleType.EXCLUSIVENESS, executionSemester); } public Set getNewDegreeModuleEquivalencePlanEntries(final EquivalencePlan equivalencePlan) { final Set equivalencePlanEntries = new TreeSet( EquivalencePlanEntry.COMPARATOR); for (final EquivalencePlanEntry equivalencePlanEntry : getNewEquivalencePlanEntriesSet()) { if (equivalencePlanEntry.getEquivalencePlan() == equivalencePlan) { equivalencePlanEntries.add(equivalencePlanEntry); } } return equivalencePlanEntries; } public Collection getParentCycleCourseGroups() { Collection res = new HashSet(); for (CourseGroup courseGroup : getParentCourseGroups()) { res.addAll(courseGroup.getParentCycleCourseGroups()); } return res; } public Set getParentCourseGroups() { Set res = new HashSet(); for (Context context : getParentContextsSet()) { res.add(context.getParentCourseGroup()); } return res; } public boolean isDissertation() { return false; } abstract public DegreeCurricularPlan getParentDegreeCurricularPlan(); abstract public void print(StringBuilder stringBuffer, String tabs, Context previousContext); abstract public boolean isLeaf(); abstract public boolean isRoot(); abstract public Double getMaxEctsCredits(final ExecutionSemester executionSemester); abstract public Double getMinEctsCredits(final ExecutionSemester executionSemester); abstract public void getAllDegreeModules(final Collection degreeModules); abstract public Set getAllCurricularCourses(final ExecutionSemester executionSemester); abstract public Set getAllCurricularCourses(); abstract public void doForAllCurricularCourses(final CurricularCourseFunctor curricularCourseFunctor); }