org.fenixedu.academic.domain.mobility.outbound.OutboundMobilityCandidacyContestGroup.java Source code

Java tutorial

Introduction

Here is the source code for org.fenixedu.academic.domain.mobility.outbound.OutboundMobilityCandidacyContestGroup.java

Source

/**
 * Copyright  2002 Instituto Superior Tcnico
 *
 * 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.mobility.outbound;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

import org.apache.commons.collections.CollectionUtils;
import org.fenixedu.academic.domain.Country;
import org.fenixedu.academic.domain.Degree;
import org.fenixedu.academic.domain.ExecutionDegree;
import org.fenixedu.academic.domain.Person;
import org.fenixedu.academic.domain.StudentCurricularPlan;
import org.fenixedu.academic.domain.candidacyProcess.mobility.MobilityAgreement;
import org.fenixedu.academic.domain.degreeStructure.CycleType;
import org.fenixedu.academic.domain.exceptions.DomainException;
import org.fenixedu.academic.domain.mobility.outbound.OutboundMobilityCandidacySubmission.Calculator;
import org.fenixedu.academic.domain.organizationalStructure.UniversityUnit;
import org.fenixedu.academic.domain.student.Registration;
import org.fenixedu.academic.domain.student.curriculum.ICurriculum;
import org.fenixedu.academic.util.Bundle;
import org.fenixedu.bennu.core.domain.Bennu;
import org.fenixedu.bennu.core.i18n.BundleUtil;
import org.fenixedu.commons.spreadsheet.Spreadsheet;
import org.fenixedu.commons.spreadsheet.Spreadsheet.Row;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import pt.ist.fenixframework.Atomic;

public class OutboundMobilityCandidacyContestGroup extends OutboundMobilityCandidacyContestGroup_Base
        implements Comparable<OutboundMobilityCandidacyContestGroup> {

    private static final Logger logger = LoggerFactory.getLogger(OutboundMobilityCandidacyContestGroup.class);

    public OutboundMobilityCandidacyContestGroup(final OutboundMobilityCandidacyContest contest,
            final Set<ExecutionDegree> executionDegrees) {
        if (contest == null) {
            throw new NullPointerException("error.OutboundMobilityCandidacyContestGroup.must.have.contest");
        }
        if (executionDegrees.isEmpty()) {
            throw new NullPointerException(
                    "error.OutboundMobilityCandidacyContestGroup.must.have.execution.degree");
        }
        setRootDomainObject(Bennu.getInstance());
        addOutboundMobilityCandidacyContest(contest);
        getExecutionDegreeSet().addAll(executionDegrees);

        // TODO : This is a hack due to a bug in the consistency predicate or fenix-framework code.
        //        When the relation is initialized but never traversed, the consistency predicate always
        //        fails. Forcing a traversal will resolve this issue. The bug has already been solved in
        //        the framework, but the framework has not yet been updated on this project.
        getOutboundMobilityCandidacyContestSet().size();
        getExecutionDegreeSet().size();
    }

    public OutboundMobilityCandidacyContestGroup(final Set<ExecutionDegree> executionDegrees) {
        if (executionDegrees.isEmpty()) {
            throw new NullPointerException(
                    "error.OutboundMobilityCandidacyContestGroup.must.have.execution.degree");
        }
        setRootDomainObject(Bennu.getInstance());
        getExecutionDegreeSet().addAll(executionDegrees);

        // TODO : This is a hack due to a bug in the consistency predicate or fenix-framework code.
        //        When the relation is initialized but never traversed, the consistency predicate always
        //        fails. Forcing a traversal will resolve this issue. The bug has already been solved in
        //        the framework, but the framework has not yet been updated on this project.
        getOutboundMobilityCandidacyContestSet().size();
        getExecutionDegreeSet().size();
    }

    @Override
    public int compareTo(final OutboundMobilityCandidacyContestGroup o) {
        final int dc = getDescription().compareTo(o.getDescription());
        return dc == 0 ? getExternalId().compareTo(o.getExternalId()) : dc;
    }

    public String getDescription() {
        final StringBuilder builder = new StringBuilder();
        for (final ExecutionDegree executionDegree : getSortedExecutionDegrees()) {
            if (builder.length() > 0) {
                builder.append(", ");
            }
            builder.append(executionDegree.getDegree().getSigla());
        }
        return builder.toString();
    }

    public SortedSet<ExecutionDegree> getSortedExecutionDegrees() {
        final SortedSet<ExecutionDegree> result = new TreeSet<ExecutionDegree>(
                ExecutionDegree.COMPARATOR_BY_DEGREE_CODE);
        result.addAll(getExecutionDegreeSet());
        return result;
    }

    @Atomic
    public void addExecutionDegreeService(final ExecutionDegree executionDegree) {
        addExecutionDegree(executionDegree);
    }

    @Atomic
    public void removeExecutionDegreeService(final ExecutionDegree executionDegree) {
        removeExecutionDegree(executionDegree);
    }

    @Atomic
    public void addMobilityCoordinatorService(final Person person) {
        addMobilityCoordinator(person);
    }

    @Atomic
    public void removeMobilityCoordinatorService(final Person person) {
        removeMobilityCoordinator(person);
    }

    public static OutboundMobilityCandidacyContestGroup findOrCreateGroup(final ExecutionDegree executionDegree) {
        for (final OutboundMobilityCandidacyContestGroup mobilityGroup : executionDegree
                .getOutboundMobilityCandidacyContestGroupSet()) {
            if (mobilityGroup.getExecutionDegreeSet().size() == 1) {
                return mobilityGroup;
            }
        }
        return new OutboundMobilityCandidacyContestGroup(Collections.singleton(executionDegree));
    }

    public void delete() {
        getExecutionDegreeSet().clear();
        getMobilityCoordinatorSet().clear();
        for (final OutboundMobilityCandidacyContest contest : getOutboundMobilityCandidacyContestSet()) {
            contest.delete();
        }
        setRootDomainObject(null);
        deleteDomainObject();

    }

    public boolean handles(final Degree degree) {
        for (final ExecutionDegree executionDegree : getExecutionDegreeSet()) {
            if (executionDegree.getDegree() == degree) {
                return true;
            }
        }
        return false;
    }

    public Spreadsheet getCandidatesInformationSpreadSheet(final OutboundMobilityCandidacyPeriod period) {
        final String filename = BundleUtil.getString(Bundle.ACADEMIC,
                "label.mobility.candidates.information.filename");

        final Spreadsheet spreadsheetCurricularInfo = new Spreadsheet(filename);
        final Spreadsheet spreadsheetOptions = spreadsheetCurricularInfo
                .addSpreadsheet(BundleUtil.getString(Bundle.ACADEMIC, "label.mobility.candidates.options"));
        final Spreadsheet spreadsheetContactInformation = spreadsheetOptions
                .addSpreadsheet(BundleUtil.getString(Bundle.ACADEMIC, "label.contact.information"));
        final Spreadsheet spreadsheetOtherCurricularInfo = spreadsheetOptions
                .addSpreadsheet(BundleUtil.getString(Bundle.ACADEMIC, "label.other.curricular.info"));

        final Set<Registration> processed = new HashSet<Registration>();
        for (final OutboundMobilityCandidacyContest contest : getOutboundMobilityCandidacyContestSet()) {
            for (final OutboundMobilityCandidacy candidacy : contest.getOutboundMobilityCandidacySet()) {
                final OutboundMobilityCandidacySubmission submission = candidacy
                        .getOutboundMobilityCandidacySubmission();
                final Registration registration = submission.getRegistration();
                final Calculator calculator = new Calculator(registration.getStudent());

                if (!processed.contains(registration)) {
                    final Person person = registration.getPerson();

                    final Row row = spreadsheetCurricularInfo.addRow();
                    final BigDecimal candidacyGrade = submission.getGrade(this);
                    //                    final ICurriculum curriculum = registration.getCurriculum();
                    row.setCell(getString("label.username"), person.getUsername());
                    row.setCell(getString("label.name"), person.getName());
                    row.setCell(getString("label.degree"), registration.getDegree().getSigla());
                    row.setCell(getString("label.candidate.classification"),
                            candidacyGrade == null ? "" : candidacyGrade.toString());

                    row.setCell(getString("label.ects.first.cycle"), calculator.completedECTSCycle1.toString());
                    row.setCell(getString("label.ects.average"), calculator.getEctsAverage().toString());
                    row.setCell(getString("label.ects.average.first.and.second.cycle"),
                            calculator.getEctsEverateFirstAndSecondCycle().toString());
                    row.setCell(getString("label.ects.completed"), calculator.completedECTS.toString());
                    //row.setCell(getString("label.ects.pending"), calculator.getPendingEcts().toString());
                    row.setCell(getString("label.ects.enrolled"), calculator.enrolledECTS.toString());

                    for (final Registration otherRegistration : registration.getStudent().getRegistrationsSet()) {
                        final Row rowOCI = spreadsheetOtherCurricularInfo.addRow();
                        final ICurriculum curriculumOther = otherRegistration.getCurriculum();
                        rowOCI.setCell(getString("label.username"), person.getUsername());
                        rowOCI.setCell(getString("label.name"), person.getName());
                        rowOCI.setCell(getString("label.degree"), otherRegistration.getDegree().getSigla());
                        rowOCI.setCell(getString("label.curricular.year"), curriculumOther.getCurricularYear());
                        rowOCI.setCell(getString("label.ects.completed.degree"),
                                curriculumOther.getSumEctsCredits().toString());
                        rowOCI.setCell(getString("label.average.degree"), curriculumOther.getRawGrade().getValue());
                        fillCycleDetails(rowOCI, CycleType.FIRST_CYCLE, otherRegistration,
                                getString("label.ects.completed.cycle.first"),
                                getString("label.average.cycle.first"));
                        fillCycleDetails(rowOCI, CycleType.SECOND_CYCLE, otherRegistration,
                                getString("label.ects.completed.cycle.second"),
                                getString("label.average.cycle.second"));
                    }

                    for (final OutboundMobilityCandidacy c : submission.getSortedOutboundMobilityCandidacySet()) {
                        final OutboundMobilityCandidacyContest contestFromCandidacy = c
                                .getOutboundMobilityCandidacyContest();
                        final MobilityAgreement mobilityAgreement = contestFromCandidacy.getMobilityAgreement();
                        final UniversityUnit unit = mobilityAgreement.getUniversityUnit();
                        final Country country = unit.getCountry();

                        final Row row2 = spreadsheetOptions.addRow();
                        row2.setCell(getString("label.username"), person.getUsername());
                        row2.setCell(getString("label.preference.order"), c.getPreferenceOrder());
                        row2.setCell(getString("label.degrees"),
                                contestFromCandidacy.getOutboundMobilityCandidacyContestGroup().getDescription());
                        row2.setCell(getString("label.mobility.program"), mobilityAgreement.getMobilityProgram()
                                .getRegistrationProtocol().getDescription().getContent());
                        row2.setCell(getString("label.country"), country == null ? "" : country.getName());
                        row2.setCell(getString("label.university"), unit.getPresentationName());
                    }

                    final Row contactRow = spreadsheetContactInformation.addRow();
                    contactRow.setCell(getString("label.username"), person.getUsername());
                    contactRow.setCell(getString("label.name"), person.getName());
                    contactRow.setCell(getString("label.email"), person.getEmailForSendingEmails());
                    contactRow.setCell(getString("label.phone"), person.getDefaultPhoneNumber());
                    contactRow.setCell(getString("label.mobile"), person.getDefaultMobilePhoneNumber());

                    processed.add(registration);
                }
            }
        }

        return spreadsheetCurricularInfo;
    }

    public void fillCandidateOptions(Spreadsheet spreadsheet, OutboundMobilityCandidacyPeriod period) {
    }

    void fillCycleDetails(final Row row, final CycleType cycleType, final Registration registration,
            final String header1, final String header2) {
        if (isForCycle(cycleType, registration)) {
            ICurriculum curriculum = registration.getCurriculum(cycleType);
            row.setCell(header1, curriculum.getSumEctsCredits().toString());
            row.setCell(header2, curriculum.getRawGrade().getValue());
        } else {
            row.setCell(header1, "");
            row.setCell(header2, "");
        }
    }

    private boolean isForCycle(final CycleType cycleType, final Registration registration) {
        for (final StudentCurricularPlan studentCurricularPlan : registration.getStudentCurricularPlansSet()) {
            if (studentCurricularPlan.getCycle(cycleType) != null) {
                return true;
            }
        }
        return false;
    }

    private String getString(final String key) {
        return BundleUtil.getString(Bundle.ACADEMIC, key);
    }

    @Atomic
    public void setGrades(final OutboundMobilityCandidacyPeriod candidacyPeriod, final String contents) {
        final StringBuilder problems = new StringBuilder();

        int l = 0;
        for (final String line : contents.split("\r?\n")) {
            l++;
            final String[] parts = line.split("\t");
            final Person person = Person.findByUsername(parts[0]);
            if (person == null) {
                // truncate to avoid long lines while printing code for username from an invalid file (xls)
                problems.append(getMessage("error.mobility.outbound.username.not.valid.on.line",
                        truncateDots(parts[0], 12), Integer.toString(l)));
                problems.append("; ");
                continue;
            }
            try {
                final BigDecimal grade = new BigDecimal(parts[1]);
                final OutboundMobilityCandidacySubmission submission = candidacyPeriod.findSubmissionFor(person);
                submission.setGrade(this, grade);
            } catch (final NumberFormatException ex) {
                // truncate to avoid long lines while printing code for grade from an invalid file (xls)
                problems.append(getMessage("error.mobility.outbound.invalid.grade.on.one",
                        truncateDots(parts[1], 4), Integer.toString(l)));
                problems.append("; ");
            } catch (final ArrayIndexOutOfBoundsException ex) {
                problems.append(getMessage("error.mobility.outbound.invalid.format.on.line", Integer.toString(l)));
                problems.append(".");
                break;
            }
        }

        if (problems.length() > 0) {
            throw new DomainException("error.mobility.outbound.unable.to.set.grades", problems.toString());
        }
    }

    private String getMessage(final String key, final String... args) {
        return BundleUtil.getString(Bundle.ACADEMIC, key, args);
    }

    // truncate string and add (...) if it is longer than length
    private String truncateDots(String stringToTruncate, int length) {
        return (stringToTruncate.length() > length) ? (stringToTruncate.substring(0, length) + "(...)")
                : stringToTruncate;
    }

    public boolean areAllStudentsGraded(final OutboundMobilityCandidacyPeriod period) {
        for (final OutboundMobilityCandidacyContest contest : getOutboundMobilityCandidacyContestSet()) {
            for (final OutboundMobilityCandidacy candidacy : contest.getOutboundMobilityCandidacySet()) {
                final OutboundMobilityCandidacySubmission submission = candidacy
                        .getOutboundMobilityCandidacySubmission();
                if (submission.getOutboundMobilityCandidacyPeriod() == period && !hasGrade(submission)) {
                    return false;
                }
            }
        }
        return true;
    }

    private boolean hasGrade(final OutboundMobilityCandidacySubmission submission) {
        for (final OutboundMobilityCandidacySubmissionGrade grade : submission
                .getOutboundMobilityCandidacySubmissionGradeSet()) {
            if (grade.getOutboundMobilityCandidacyContestGroup() == this) {
                return true;
            }
        }
        return false;
    }

    public boolean isCandidacySelectionConcluded(final OutboundMobilityCandidacyPeriod period) {
        return getConcludedCandidateSelectionForPeriodSet().contains(period);
    }

    public boolean isCandidateNotificationConcluded(final OutboundMobilityCandidacyPeriod period) {
        return getCandidatesNotifiedOfSelectionResultsForPeriodSet().contains(period);
    }

    public boolean areCandidatesNotofiedOfSelectionResults(final OutboundMobilityCandidacyPeriod period) {
        return getCandidatesNotifiedOfSelectionResultsForPeriodSet().contains(period);
    }

    public boolean haveAllCandidatesConfirmed(final OutboundMobilityCandidacyPeriod period) {
        for (final OutboundMobilityCandidacyContest contest : getOutboundMobilityCandidacyContestSet()) {
            for (final OutboundMobilityCandidacy candidacy : contest.getOutboundMobilityCandidacySet()) {
                final OutboundMobilityCandidacySubmission submission = candidacy
                        .getSubmissionFromSelectedCandidacy();
                if (submission != null) {
                    if (!submission.hasConfirmedPlacement()) {
                        return false;
                    }
                }
            }
        }
        return true;
    }

    @Atomic
    public void selectCandidates(final OutboundMobilityCandidacyPeriod period) {
        for (final OutboundMobilityCandidacyContest contest : getOutboundMobilityCandidacyContestSet()) {
            if (contest.getOutboundMobilityCandidacyPeriod() == period) {
                for (final OutboundMobilityCandidacy candidacy : contest.getOutboundMobilityCandidacySet()) {
                    final OutboundMobilityCandidacySubmission submission = candidacy
                            .getSubmissionFromSelectedCandidacy();
                    if (submission != null) {
                        candidacy.unselect();
                    }
                }
            }
        }

        final SortedSet<OutboundMobilityCandidacySubmissionGrade> grades = new TreeSet<OutboundMobilityCandidacySubmissionGrade>();
        collectGradesForGroup(grades, period);

        for (final OutboundMobilityCandidacyContestGroup otherGroup : getRootDomainObject()
                .getOutboundMobilityCandidacyContestGroupSet()) {
            if (otherGroup != this && intersect(otherGroup)) {
                otherGroup.collectGradesForGroup(grades, period);
            }
        }

        for (final OutboundMobilityCandidacySubmissionGrade submissionGrade : grades) {
            logger.info("Selecting for: " + submissionGrade.getOutboundMobilityCandidacySubmission()
                    .getRegistration().getPerson().getUsername());
            final BigDecimal grade = submissionGrade.getGrade();
            if (grade.signum() == 1) {
                submissionGrade.getOutboundMobilityCandidacySubmission().select();
            }
        }
    }

    private void unselectCandidates(final OutboundMobilityCandidacyPeriod period) {
        for (final OutboundMobilityCandidacyContest contest : getOutboundMobilityCandidacyContestSet()) {
            if (contest.getOutboundMobilityCandidacyPeriod() == period) {
                for (final OutboundMobilityCandidacy candidacy : contest.getOutboundMobilityCandidacySet()) {
                    final OutboundMobilityCandidacySubmission submission = candidacy
                            .getSubmissionFromSelectedCandidacy();
                    if (submission != null) {
                        candidacy.unselect();
                    }
                }
            }
        }
    }

    private boolean intersect(final OutboundMobilityCandidacyContestGroup otherGroup) {
        return CollectionUtils.containsAny(getExecutionDegreeSet(), otherGroup.getExecutionDegreeSet());
    }

    private void collectGradesForGroup(final SortedSet<OutboundMobilityCandidacySubmissionGrade> grades,
            final OutboundMobilityCandidacyPeriod period) {
        for (final OutboundMobilityCandidacySubmissionGrade submissionGrade : getOutboundMobilityCandidacySubmissionGradeSet()) {
            final OutboundMobilityCandidacySubmission submission = submissionGrade
                    .getOutboundMobilityCandidacySubmission();
            if (submission.getOutboundMobilityCandidacyPeriod() == period) {
                grades.add(submissionGrade);
            }
        }
    }

    @Atomic
    public void concludeCandidateSelection(final OutboundMobilityCandidacyPeriod period) {
        addConcludedCandidateSelectionForPeriod(period);
    }

    @Atomic
    public void revertConcludeCandidateSelection(final OutboundMobilityCandidacyPeriod period) {
        removeConcludedCandidateSelectionForPeriod(period);
    }

    @Atomic
    public void concludeCandidateNotification(final OutboundMobilityCandidacyPeriod period) {
        addCandidatesNotifiedOfSelectionResultsForPeriod(period);
    }

    @Atomic
    public void revertConcludeCandidateNotification(final OutboundMobilityCandidacyPeriod period) {
        removeCandidatesNotifiedOfSelectionResultsForPeriod(period);
    }

}