package pt.utl.ist.scripts.runOnce.degreeStructure; import java.io.File; import java.io.PrintStream; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Set; import net.sourceforge.fenixedu.domain.CompetenceCourse; import net.sourceforge.fenixedu.domain.Degree; import net.sourceforge.fenixedu.domain.DegreeCurricularPlan; import net.sourceforge.fenixedu.domain.Enrolment; import net.sourceforge.fenixedu.domain.ExecutionYear; import net.sourceforge.fenixedu.domain.Person; import net.sourceforge.fenixedu.domain.StudentCurricularPlan; import net.sourceforge.fenixedu.domain.degreeStructure.BranchCourseGroup; import net.sourceforge.fenixedu.domain.degreeStructure.BranchType; import net.sourceforge.fenixedu.domain.degreeStructure.Context; import net.sourceforge.fenixedu.domain.degreeStructure.CourseGroup; import net.sourceforge.fenixedu.domain.student.Registration; import net.sourceforge.fenixedu.domain.student.registrationStates.RegistrationStateType; import net.sourceforge.fenixedu.domain.studentCurriculum.BranchCurriculumGroup; import net.sourceforge.fenixedu.domain.studentCurriculum.CurriculumGroup; import net.sourceforge.fenixedu.domain.studentCurriculum.CurriculumLine; import net.sourceforge.fenixedu.domain.studentCurriculum.CurriculumModule.ConclusionValue; import pt.utl.ist.scripts.commons.AtomicScript; public class UpdateStudentsCurriculumOfMEEC extends AtomicScript { private static class GroupCorrespondence implements Cloneable { public String oldCourseGroupName; public String newCourseGroupName; public List inBranches; public BranchCourseGroup branchCourseGroup; public CourseGroup oldCourseGroup; public CourseGroup newCourseGroup; private int count = 0; public GroupCorrespondence(String oldCourseGroupName, String newCourseGroupName, BranchType[] inBranches) { this.oldCourseGroupName = oldCourseGroupName; this.newCourseGroupName = newCourseGroupName; this.inBranches = Arrays.asList(inBranches); } public void attachCourseGroups(BranchCourseGroup branchCourseGroup) { count++; if (!inBranches.contains(branchCourseGroup.getBranchType())) { return; } this.branchCourseGroup = branchCourseGroup; CourseGroup oldCourseGroup = findCourseGroupFor(getExecutionYear20102011(), this.oldCourseGroupName); CourseGroup newCourseGroup = findCourseGroupFor(getExecutionYear20112012(), this.newCourseGroupName); if (oldCourseGroup == null || newCourseGroup == null) { throw new RuntimeException("Cannot find correspondence " + toString()); } this.oldCourseGroup = oldCourseGroup; this.newCourseGroup = newCourseGroup; } public Boolean isThisOldCourseGroup(CourseGroup courseGroup) { return this.oldCourseGroup == courseGroup; } private CourseGroup findCourseGroupFor(ExecutionYear executionYear, String courseGroupName) { return getChildCourseGroup(this.branchCourseGroup, courseGroupName, executionYear); } @Override public String toString() { return String.format("'%s' -> '%s' %s", this.oldCourseGroupName, this.newCourseGroupName, this.count); } public GroupCorrespondence cloneMe() { try { return (GroupCorrespondence) this.clone(); } catch (CloneNotSupportedException e) { throw new RuntimeException(e); } } }; private static final GroupCorrespondence[] CORRESPONDENCE_FOR_COMPUTADORES = { new GroupCorrespondence("Arquitectura de Computadores", "Arquitectura de Computadores", new BranchType[] { BranchType.MAJOR, BranchType.MINOR }), new GroupCorrespondence("Metodologia e Tecnologia da Programação", "Metodologia de Programação", new BranchType[] { BranchType.MAJOR, BranchType.MINOR }), new GroupCorrespondence("Sistemas de Informação", "Metodologia de Programação", new BranchType[] { BranchType.MAJOR, BranchType.MINOR }), new GroupCorrespondence("Redes de Comunicação e de Informação", "Arquitectura e Gestão de Redes de Computadores", new BranchType[] { BranchType.MAJOR, BranchType.MINOR }), new GroupCorrespondence("Redes e Sistemas de Telecomunicações", "Arquitectura e Gestão de Redes de Computadores", new BranchType[] { BranchType.MAJOR }), new GroupCorrespondence("Electrónica de Computadores", "Formação Complementar a Computadores", new BranchType[] { BranchType.MAJOR }), new GroupCorrespondence("Sinais e Sistemas", "Formação Complementar a Computadores", new BranchType[] { BranchType.MAJOR }) }; private static final GroupCorrespondence[] CORRESPONDENCE_FOR_ELECTRONICA = { new GroupCorrespondence("Arquitectura de Computadores & Metodologia e Tecnologia de Programação", "Sistemas Electrónicos de Computadores", new BranchType[] { BranchType.MAJOR }), new GroupCorrespondence("Dispositivos e Circuitos Electrónicos", "Electrónica e Sistemas Integrados", new BranchType[] { BranchType.MAJOR, BranchType.MINOR }), new GroupCorrespondence("Electrónica de Computadores", "Sistemas Electrónicos de Computadores", new BranchType[] { BranchType.MAJOR, BranchType.MINOR }), new GroupCorrespondence("Sistemas Electrónicos", "Electrónica e Sistemas Integrados", new BranchType[] { BranchType.MAJOR, BranchType.MINOR }), new GroupCorrespondence("Redes e Sistemas de Telecomunicações", "Formação Complementar a Electrónica", new BranchType[] { BranchType.MAJOR }) }; private static final GroupCorrespondence[] CORRESPONDENCE_FOR_ENERGIA = { new GroupCorrespondence("Electromagnetismo Aplicado e Conversão de Energia_1", "Electromagnetismo Aplicado e Conversão de Energia", new BranchType[] { BranchType.MAJOR, BranchType.MINOR }), new GroupCorrespondence("Electromagnetismo Aplicado e Conversão de Energia_2", "Electromagnetismo Aplicado e Conversão de Energia", new BranchType[] { BranchType.MAJOR, BranchType.MINOR }), new GroupCorrespondence("Electrónica de Energia", "Electrónica de Sistemas de Energia", new BranchType[] { BranchType.MAJOR, BranchType.MINOR }), new GroupCorrespondence("Redes e Sistemas de Energia", "Redes e Sistemas de Energia", new BranchType[] { BranchType.MAJOR, BranchType.MINOR }) }; private static final GroupCorrespondence[] CORRESPONDENCE_FOR_SISTEMA_DECISAO_CONTROLO = { new GroupCorrespondence("Arquitectura de Computadores", "Formação Complementar a Sistemas, Decisão e Controlo", new BranchType[] { BranchType.MAJOR }), new GroupCorrespondence("Dispositivos e Circuitos Electrónicos", "Formação Complementar a Sistemas, Decisão e Controlo", new BranchType[] { BranchType.MAJOR }), new GroupCorrespondence("Redes e Sistemas de Telecomunicações", "Formação Complementar a Sistemas, Decisão e Controlo", new BranchType[] { BranchType.MAJOR }), new GroupCorrespondence("Decisão e Controlo & Robótica", "Decisão e Controlo & Robótica", new BranchType[] { BranchType.MAJOR, BranchType.MINOR }), new GroupCorrespondence("Sinais e Sistemas", "Sistemas e Sinais", new BranchType[] { BranchType.MAJOR, BranchType.MINOR }) }; private static final GroupCorrespondence[] CORRESPONDENCE_FOR_TELECOMUNICACOES = { new GroupCorrespondence("Dispositivos e Circuitos Electrónicos", "Formação Complementar a Telecomunicações", new BranchType[] { BranchType.MAJOR }), new GroupCorrespondence("Electrónica de Computadores", "Formação Complementar a Telecomunicações", new BranchType[] { BranchType.MAJOR }), new GroupCorrespondence("Sistemas Electrónicos", "Formação Complementar a Telecomunicações", new BranchType[] { BranchType.MAJOR }), new GroupCorrespondence("Fundamentos das Comunicações", "Fundamentos das Comunicações", new BranchType[] { BranchType.MAJOR, BranchType.MINOR }), new GroupCorrespondence("Propagação e Radiação", "Propagação e Radiação", new BranchType[] { BranchType.MAJOR, BranchType.MINOR }), new GroupCorrespondence("Redes e Sistemas de Telecomunicações_1", "Redes e Sistemas de Telecomunicações", new BranchType[] { BranchType.MAJOR, BranchType.MINOR }), new GroupCorrespondence("Redes e Sistemas de Telecomunicações_2", "Redes e Sistemas de Telecomunicações", new BranchType[] { BranchType.MAJOR, BranchType.MINOR }) }; private static final HashMap> MAPS = new HashMap>(); private static final HashMap BRANCH_STRUCTURE = new HashMap(); static { BRANCH_STRUCTURE.put("Computadores", CORRESPONDENCE_FOR_COMPUTADORES); BRANCH_STRUCTURE.put("Electrónica", CORRESPONDENCE_FOR_ELECTRONICA); BRANCH_STRUCTURE.put("Energia", CORRESPONDENCE_FOR_ENERGIA); BRANCH_STRUCTURE.put("Sistemas, Decisão e Controlo", CORRESPONDENCE_FOR_SISTEMA_DECISAO_CONTROLO); BRANCH_STRUCTURE.put("Telecomunicações", CORRESPONDENCE_FOR_TELECOMUNICACOES); } public void fetchCourseGroupsAndBuildMap() { final String[] branchesHolders = { "Área de Especialização Principal", "Área de Especialização Secundária" }; DegreeCurricularPlan meec = getMEECDegreeCurricularPlan(); for (String branchHolderName : branchesHolders) { CourseGroup branchHolder = getChildCourseGroup(meec.getSecondCycleCourseGroup(), branchHolderName, getExecutionYear20112012()); for (String branchName : BRANCH_STRUCTURE.keySet()) { BranchCourseGroup branchCourseGroup = (BranchCourseGroup) getChildCourseGroup(branchHolder, branchName, getExecutionYear20112012()); MAPS.put(branchCourseGroup, new ArrayList()); for (GroupCorrespondence correspondence : BRANCH_STRUCTURE.get(branchName)) { GroupCorrespondence clone = correspondence.cloneMe(); clone.attachCourseGroups(branchCourseGroup); System.err.println(correspondence.toString()); MAPS.get(branchCourseGroup).add(clone); } } } } private DegreeCurricularPlan getMEECDegreeCurricularPlan() { return Degree.readBySigla("MEEC").getLastActiveDegreeCurricularPlan(); } private static List STUDENTS = Arrays.asList(new Integer[] { 55163, 55103 }); @Override protected void run() throws Exception { PrintStream stream = null; PrintStream defaultStream = System.out; try { stream = new PrintStream(new File(REPORT_DIR_PATH + "/meec.txt")); System.setOut(stream); fetchCourseGroupsAndBuildMap(); DegreeCurricularPlan meecDegreeCurricularPlan = Degree.readBySigla("MEEC").getLastActiveDegreeCurricularPlan(); int i = 0; for (StudentCurricularPlan studentCurricularPlan : meecDegreeCurricularPlan.getStudentCurricularPlans()) { if (!STUDENTS.contains(studentCurricularPlan.getRegistration().getNumber())) { continue; } // if (!isToModifySecondCycleCurriculumGroup(studentCurricularPlan)) { // continue; // } // infoEctsAndNumberOfCurriculumLinesForStudent(studentCurricularPlan); System.err.println("Student curricular plan [" + studentCurricularPlan.getRegistration().getNumber() + "] will be changed "); i++; try { BranchCurriculumGroup selectedMajorBranchCurriculumGroup = studentCurricularPlan.getSecondCycle().getMajorBranchCurriculumGroup(); BranchCurriculumGroup selectedMinorBranchCurriculumGroup = studentCurricularPlan.getSecondCycle().getMinorBranchCurriculumGroup(); if (selectedMajorBranchCurriculumGroup != null) { System.err.println("Change Major"); repositionCurriculumLines(selectedMajorBranchCurriculumGroup); } if (selectedMinorBranchCurriculumGroup != null) { System.err.println("Change Minor"); repositionCurriculumLines(selectedMinorBranchCurriculumGroup); } } catch (StudentException e) { System.out.println(String.format("Student %s : %s", studentCurricularPlan.getRegistration().getNumber(), e.getMessage())); } catch (Exception e) { System.out.println(String.format("Exception on student %s", studentCurricularPlan.getRegistration() .getNumber())); e.printStackTrace(System.err); } } System.out.println("Mess with " + i + " student curricular plans"); } finally { System.setOut(defaultStream); if (stream != null) { stream.close(); } } } private void repositionCurriculumLines(BranchCurriculumGroup branchCurriculumGroup) { Set allCurriculumLines = branchCurriculumGroup.getAllCurriculumLines(); for (CurriculumLine curriculumLine : allCurriculumLines) { BranchCourseGroup branchCourseGroup = branchCurriculumGroup.getDegreeModule(); CourseGroup parentCourseGroup = curriculumLine.getCurriculumGroup().getDegreeModule(); List groupCorrespondences = MAPS.get(branchCourseGroup); if (groupCorrespondences == null) { System.out.println(String.format("For student %s cannot find %s", branchCurriculumGroup.getStudent().getNumber(), branchCourseGroup.getName())); continue; } for (GroupCorrespondence correspondence : groupCorrespondences) { if (correspondence.isThisOldCourseGroup(parentCourseGroup)) { repositionLine(curriculumLine, correspondence.newCourseGroup); break; } } } cleanBranchCurriculumGroup(branchCurriculumGroup); } private void cleanBranchCurriculumGroup(BranchCurriculumGroup branchCurriculumGroup) { cleanCurriculumGroup(branchCurriculumGroup); } private void cleanCurriculumGroup(CurriculumGroup curriculumGroup) { for (CurriculumGroup childGroup : curriculumGroup.getChildCurriculumGroups()) { cleanCurriculumGroup(childGroup); } if (!curriculumGroup.hasAnyCurriculumModules()) { curriculumGroup.delete(); } } private void repositionLine(CurriculumLine curriculumLine, CourseGroup newCourseGroup) { BranchCurriculumGroup branchCurriculumGroup = curriculumLine.getParentBranchCurriculumGroup(); CurriculumGroup newCurriculumGroup = branchCurriculumGroup.findCurriculumGroupFor(newCourseGroup); if (newCurriculumGroup == null) { newCurriculumGroup = new CurriculumGroup(branchCurriculumGroup, newCourseGroup); } else if (newCurriculumGroup.getCurriculumGroup() != branchCurriculumGroup) { newCurriculumGroup.setCurriculumGroup(branchCurriculumGroup); } curriculumLine.setCurriculumGroup(newCurriculumGroup); } private void infoEctsAndNumberOfCurriculumLinesForStudent(StudentCurricularPlan studentCurricularPlan) { Registration registration = studentCurricularPlan.getRegistration(); System.out.println(String.format("%s\t%s\t%s\t%s", registration.getNumber(), registration.getPerson().getName(), studentCurricularPlan.getRoot().getAllCurriculumLines().size(), studentCurricularPlan.getRoot() .getAprovedEctsCredits())); } private boolean isToModifySecondCycleCurriculumGroup(StudentCurricularPlan studentCurricularPlan) { if (studentCurricularPlan.getSecondCycle() == null) { return false; } Registration registration = studentCurricularPlan.getRegistration(); if (registration.isCanceled()) { return false; } if (registration.isInternalAbandon()) { return false; } if (registration.isConcluded()) { return false; } if (registration.isSchoolPartConcluded()) { return false; } if (RegistrationStateType.STUDYPLANCONCLUDED.equals(registration.getActiveStateType())) { return false; } if (ConclusionValue.CONCLUDED.equals(studentCurricularPlan.getSecondCycle().isConcluded(getExecutionYear20112012()))) { return false; } if (hasEnrolmentsToConfirmAndToFinishCycle(studentCurricularPlan, getExecutionYear20102011())) { BigDecimal ectsSum = sumEctsEnrolledButNotEvaluated(studentCurricularPlan, getExecutionYear20102011()); BigDecimal aprovedEctsCredits = new BigDecimal(studentCurricularPlan.getSecondCycle().getAprovedEctsCredits()); Person person = registration.getPerson(); // System.out.println(String.format("%s\t%s\t%s\t%s", // registration.getNumber(), person.getName(), aprovedEctsCredits, // ectsSum)); return false; } return true; } private boolean hasEnrolmentsToConfirmAndToFinishCycle(StudentCurricularPlan studentCurricularPlan, ExecutionYear executionYear20102011) { BigDecimal ectsSum = sumEctsEnrolledButNotEvaluated(studentCurricularPlan, executionYear20102011); BigDecimal aprovedEctsCredits = new BigDecimal(studentCurricularPlan.getSecondCycle().getAprovedEctsCredits()); BigDecimal minEctsCredits = new BigDecimal(studentCurricularPlan.getSecondCycle().getCycleCourseGroup().getMinEctsCredits()); return ectsSum.add(aprovedEctsCredits).compareTo(minEctsCredits) >= 0; } private BigDecimal sumEctsEnrolledButNotEvaluated(StudentCurricularPlan studentCurricularPlan, ExecutionYear executionYear20102011) { Collection enrolments = studentCurricularPlan.getEnrolmentsByExecutionYear(executionYear20102011); Set annualEnrolments = new HashSet(); BigDecimal ectsSum = new BigDecimal(0); for (Enrolment enrolment : enrolments) { if (enrolment.isValid(executionYear20102011) && enrolment.isEnroled()) { if (annualEnrolments.contains(enrolment.getCurricularCourse().getCompetenceCourse())) { continue; } annualEnrolments.add(enrolment.getCurricularCourse().getCompetenceCourse()); ectsSum = ectsSum.add(new BigDecimal(enrolment.getEctsCredits())); } } return ectsSum; } private static ExecutionYear getExecutionYear20112012() { return ExecutionYear.readExecutionYearByName("2011/2012"); } private static ExecutionYear getExecutionYear20102011() { return ExecutionYear.readExecutionYearByName("2010/2011"); } static private CourseGroup getChildCourseGroup(CourseGroup courseGroup, String areaName, ExecutionYear executionYear) { if (areaName.equals(courseGroup.getName())) { return courseGroup; } for (Context context : courseGroup.getChildContexts()) { if (!context.getChildDegreeModule().isCourseGroup()) { continue; } if (!context.isValid(executionYear)) { continue; } CourseGroup result = getChildCourseGroup((CourseGroup) context.getChildDegreeModule(), areaName, executionYear); if (result != null) { return result; } } return null; } public static void main(String[] args) { processWriteTransaction(new UpdateStudentsCurriculumOfMEEC()); } private static class StudentException extends RuntimeException { private static final long serialVersionUID = 1L; public StudentException(String message) { super(message); } } }