/**
* 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.residence;
import java.io.ByteArrayOutputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;
import org.fenixedu.academic.domain.Enrolment;
import org.fenixedu.academic.domain.ExecutionSemester;
import org.fenixedu.academic.domain.GradeScale;
import org.fenixedu.academic.domain.IEnrolment;
import org.fenixedu.academic.domain.QueueJobResult;
import org.fenixedu.academic.domain.StudentCurricularPlan;
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.ICurriculumEntry;
import org.fenixedu.academic.domain.studentCurriculum.CurriculumLine;
import org.fenixedu.academic.domain.studentCurriculum.Dismissal;
import org.fenixedu.bennu.core.domain.Bennu;
import org.fenixedu.commons.spreadsheet.Spreadsheet;
import org.fenixedu.commons.spreadsheet.Spreadsheet.Row;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import pt.ist.fenixframework.Atomic;
public class StudentsPerformanceReport extends StudentsPerformanceReport_Base {
private static final Logger logger = LoggerFactory.getLogger(StudentsPerformanceReport.class);
private StudentsPerformanceReport() {
super();
setRootDomainObject(Bennu.getInstance());
setRootDomainObjectQueueUndone(Bennu.getInstance());
}
private StudentsPerformanceReport(final ExecutionSemester executionSemester, List<Student> studentList) {
this();
if (executionSemester == null) {
throw new DomainException("error.students.performance.report.execution.semester.is.null");
}
if (studentList == null || studentList.isEmpty()) {
throw new DomainException("error.students.performance.report.is.null.or.empty");
}
setExecutionSemester(executionSemester);
getStudentsSet().addAll(studentList);
}
@Override
public QueueJobResult execute() throws Exception {
ByteArrayOutputStream byteArrayOS = new ByteArrayOutputStream();
Spreadsheet spreadsheet = createSpreadsheet();
for (Student student : getStudentsSet()) {
addInformation(spreadsheet, student);
}
spreadsheet.exportToXLSSheet(byteArrayOS);
final QueueJobResult queueJobResult = new QueueJobResult();
queueJobResult.setContentType("application/txt");
queueJobResult.setContent(byteArrayOS.toByteArray());
logger.info("Job " + getFilename() + " completed");
return queueJobResult;
}
@Override
public String getFilename() {
return "Candidatos_Residencia_" + getExecutionSemester().getName() + new DateTime().toString("dd_MM_yyyy") + ".txt";
}
public static List<StudentsPerformanceReport> readGeneratedReports(final ExecutionSemester executionSemester) {
List<StudentsPerformanceReport> generatedReports = new ArrayList<StudentsPerformanceReport>();
CollectionUtils.select(executionSemester.getStudentsPerformanceReportsSet(), new Predicate() {
@Override
public boolean evaluate(Object arg0) {
return ((StudentsPerformanceReport) arg0).getDone();
}
}, generatedReports);
return generatedReports;
}
public static List<StudentsPerformanceReport> readNotGeneratedReports(final ExecutionSemester executionSemester) {
List<StudentsPerformanceReport> generatedReports = new ArrayList<StudentsPerformanceReport>();
CollectionUtils.select(executionSemester.getStudentsPerformanceReportsSet(), new Predicate() {
@Override
public boolean evaluate(Object arg0) {
return !((StudentsPerformanceReport) arg0).getDone();
}
}, generatedReports);
return generatedReports;
}
public static final Comparator<StudentsPerformanceReport> COMPARE_BY_REQUEST_DATE =
new Comparator<StudentsPerformanceReport>() {
@Override
public int compare(StudentsPerformanceReport o1, StudentsPerformanceReport o2) {
return o1.getRequestDate().compareTo(o2.getRequestDate());
}
};
public static StudentsPerformanceReport readPendingReport(final ExecutionSemester executionSemester) {
List<StudentsPerformanceReport> pendingReports = new ArrayList<StudentsPerformanceReport>();
CollectionUtils.select(executionSemester.getStudentsPerformanceReportsSet(), new Predicate() {
@Override
public boolean evaluate(Object arg0) {
return ((StudentsPerformanceReport) arg0).getIsNotDoneAndNotCancelled();
}
}, pendingReports);
if (pendingReports.isEmpty()) {
return null;
}
Collections.sort(pendingReports, Collections.reverseOrder(COMPARE_BY_REQUEST_DATE));
return pendingReports.iterator().next();
}
public static boolean hasPendingReports(final ExecutionSemester executionSemester) {
return readPendingReport(executionSemester) != null;
}
@Atomic
public static StudentsPerformanceReport launchJob(final ExecutionSemester executionSemester, List<Student> students) {
return new StudentsPerformanceReport(executionSemester, students);
}
/* STUDY */
private BigDecimal getApprovedECTS(final Student student) {
return student
.getLastActiveRegistration()
.getCurriculum(getExecutionSemester().getEndDateYearMonthDay().toDateTimeAtCurrentTime(),
getExecutionSemester().getExecutionYear(), null).getSumEctsCredits();
}
private BigDecimal getEnrolledECTS(final Student student) {
StudentCurricularPlan scp = getStudentCurricularPlan(student, getExecutionSemester());
BigDecimal totalECTS = new BigDecimal(0d);
for (final CurriculumLine curriculumLine : scp.getAllCurriculumLines()) {
if (curriculumLine.isExtraCurricular()) {
continue;
}
// until given ExecutionSemester
if (curriculumLine.getExecutionPeriod().isAfter(getExecutionSemester())) {
continue;
}
if (curriculumLine.isEnrolment()) {
final Enrolment enrolment = (Enrolment) curriculumLine;
totalECTS = totalECTS.add(enrolment.getEctsCreditsForCurriculum());
} else if (curriculumLine.isDismissal()) {
final Dismissal dismissal = (Dismissal) curriculumLine;
if (dismissal.getCredits().isSubstitution()) {
for (final IEnrolment enrolment : dismissal.getSourceIEnrolments()) {
totalECTS = totalECTS.add(enrolment.getEctsCreditsForCurriculum());
}
} else if (dismissal.getCredits().isEquivalence()) {
totalECTS = totalECTS.add(dismissal.getEctsCreditsForCurriculum());
}
} else {
throw new RuntimeException("error.unknown.curriculumLine");
}
}
return totalECTS;
}
private int getApprovedGradeValuesSum(final Student student) {
Collection<ICurriculumEntry> entries =
student.getLastActiveRegistration()
.getCurriculum(getExecutionSemester().getEndDateYearMonthDay().toDateTimeAtCurrentTime(),
getExecutionSemester().getExecutionYear(), null).getCurriculumEntries();
BigDecimal sum = new BigDecimal(0d);
for (final ICurriculumEntry entry : entries) {
if (entry.getGrade().isNumeric()) {
final BigDecimal weigth = entry.getWeigthForCurriculum();
if (GradeScale.TYPE20.equals(entry.getGrade().getGradeScale())) {
sum = sum.add(entry.getGrade().getNumericValue());
}
}
}
return sum.intValue();
}
private int getNumberOfApprovedCourses(final Student student) {
Collection<ICurriculumEntry> entries =
student.getLastActiveRegistration()
.getCurriculum(getExecutionSemester().getEndDateYearMonthDay().toDateTimeAtCurrentTime(),
getExecutionSemester().getExecutionYear(), null).getCurriculumEntries();
return entries.size() * 20;
}
private BigDecimal getA(final Student student) {
return BigDecimal.ZERO.equals(getEnrolledECTS(student)) ? BigDecimal.ZERO : getApprovedECTS(student).divide(
getEnrolledECTS(student), 2, RoundingMode.HALF_EVEN);
}
private BigDecimal getB(final Student student) {
return getNumberOfApprovedCourses(student) == 0 ? BigDecimal.ZERO : new BigDecimal(getApprovedGradeValuesSum(student))
.divide(new BigDecimal(getNumberOfApprovedCourses(student)), 2, RoundingMode.HALF_EVEN);
}
private static StudentCurricularPlan getStudentCurricularPlan(final Student student, final ExecutionSemester semester) {
List<Registration> registrations = student.getActiveRegistrationsIn(semester);
if (registrations.size() != 1) {
throw new DomainException("student.has.more.than.one.active.registration");
}
Registration registration = registrations.iterator().next();
final StudentCurricularPlan studentCurricularPlan = registration.getLastStudentCurricularPlan();
if (!studentCurricularPlan.isBolonhaDegree()) {
throw new DomainException("student.curricular.plan.is.not.bolonha");
}
return studentCurricularPlan;
}
private Spreadsheet createSpreadsheet() {
final Spreadsheet spreadsheet = new Spreadsheet("students");
spreadsheet.setHeaders(new String[] { "Num Aluno", "Nome", "Tipo Curso", "Curso", "Ciclo", "Ects Aprovados",
"Ects Total", "Soma classificacoes", "Num Aprovadas * 20", "A", "B", "100 * (A + B)" });
return spreadsheet;
}
private void addInformation(final Spreadsheet spreadsheet, final Student student) {
StudentCurricularPlan studentCurricularPlan = getStudentCurricularPlan(student, getExecutionSemester());
final Row row = spreadsheet.addRow();
row.setCell(student.getNumber());
row.setCell(student.getPerson().getName());
row.setCell(studentCurricularPlan.getDegreeType().getName().getContent());
row.setCell(studentCurricularPlan.getName());
row.setCell(studentCurricularPlan.getRegistration().getCycleType(getExecutionSemester().getExecutionYear())
.getDescription());
row.setCell(getApprovedECTS(student).toPlainString());
row.setCell(getEnrolledECTS(student).toPlainString());
row.setCell(getApprovedGradeValuesSum(student));
row.setCell(getNumberOfApprovedCourses(student));
row.setCell(getA(student).toPlainString());
row.setCell(getB(student).toPlainString());
row.setCell(getA(student).add(getB(student)).multiply(BigDecimal.valueOf(100)).intValue());
}
}