001package org.cpsolver.exam.reports;
002
003import java.text.DecimalFormat;
004import java.util.List;
005
006import org.cpsolver.exam.model.Exam;
007import org.cpsolver.exam.model.ExamModel;
008import org.cpsolver.exam.model.ExamPlacement;
009import org.cpsolver.exam.model.ExamStudent;
010import org.cpsolver.ifs.assignment.Assignment;
011import org.cpsolver.ifs.util.CSVFile;
012import org.cpsolver.ifs.util.CSVFile.CSVField;
013
014
015/**
016 * Export student more than two exams a day conflicts between triplets of exams
017 * into a CSV file. <br>
018 * <br>
019 * Usage:
020 * <pre><code>
021 * &nbsp;&nbsp;&nbsp;&nbsp;new ExamStudentMoreTwoADay(model).report().save(file);
022 * </code></pre>
023 * <br>
024 * 
025 * @version ExamTT 1.3 (Examination Timetabling)<br>
026 *          Copyright (C) 2008 - 2014 Tomáš Müller<br>
027 *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
028 *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
029 * <br>
030 *          This library is free software; you can redistribute it and/or modify
031 *          it under the terms of the GNU Lesser General Public License as
032 *          published by the Free Software Foundation; either version 3 of the
033 *          License, or (at your option) any later version. <br>
034 * <br>
035 *          This library is distributed in the hope that it will be useful, but
036 *          WITHOUT ANY WARRANTY; without even the implied warranty of
037 *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
038 *          Lesser General Public License for more details. <br>
039 * <br>
040 *          You should have received a copy of the GNU Lesser General Public
041 *          License along with this library; if not see
042 *          <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
043 */
044public class ExamStudentMoreTwoADay {
045    private ExamModel iModel = null;
046
047    /**
048     * Constructor
049     * 
050     * @param model
051     *            examination timetabling model
052     */
053    public ExamStudentMoreTwoADay(ExamModel model) {
054        iModel = model;
055    }
056
057    /**
058     * generate report
059     * @param assignment current assignment
060     * @return resultant report
061     */
062    public CSVFile report(Assignment<Exam, ExamPlacement> assignment) {
063        CSVFile csv = new CSVFile();
064        csv.setHeader(new CSVField[] { new CSVField("Exam 1"), new CSVField("Enrl 1"), new CSVField("Period 1"),
065                new CSVField("Date 1"), new CSVField("Time 1"), new CSVField("Exam 2"), new CSVField("Enrl 2"),
066                new CSVField("Period 2"), new CSVField("Time 2"), new CSVField("Exam 3"), new CSVField("Enrl 3"),
067                new CSVField("Period 3"), new CSVField("Time 3"), new CSVField("More-2-Day"),
068                new CSVField("More-2-Day [%]") });
069        DecimalFormat df = new DecimalFormat("0.0");
070        for (Exam ex1 : iModel.variables()) {
071            ExamPlacement p1 = assignment.getValue(ex1);
072            if (p1 == null)
073                continue;
074            for (Exam ex2 : iModel.variables()) {
075                if (ex2.equals(ex1))
076                    continue;
077                ExamPlacement p2 = assignment.getValue(ex2);
078                if (p2 == null || p2.getPeriod().getDay() != p1.getPeriod().getDay()
079                        || p2.getPeriod().getIndex() < p1.getPeriod().getIndex())
080                    continue;
081                if (p1.getPeriod().equals(p2.getPeriod()) && ex1.getId() >= ex2.getId())
082                    continue;
083                List<ExamStudent> students = ex1.getJointEnrollments().get(ex2);
084                if (students == null || students.isEmpty())
085                    continue;
086                for (Exam ex3 : iModel.variables()) {
087                    if (ex3.equals(ex2) || ex3.equals(ex1))
088                        continue;
089                    ExamPlacement p3 = assignment.getValue(ex3);
090                    if (p3 == null || p3.getPeriod().getDay() != p2.getPeriod().getDay()
091                            || p3.getPeriod().getIndex() < p2.getPeriod().getIndex())
092                        continue;
093                    if (p1.getPeriod().equals(p3.getPeriod()) && ex1.getId() >= ex3.getId())
094                        continue;
095                    if (p2.getPeriod().equals(p3.getPeriod()) && ex2.getId() >= ex3.getId())
096                        continue;
097                    int m2d = 0;
098                    for (ExamStudent h : ex3.getStudents())
099                        if (students.contains(h))
100                            m2d++;
101                    if (m2d == 0)
102                        continue;
103                    csv.addLine(new CSVField[] {
104                            new CSVField(ex1.getName()),
105                            new CSVField(ex1.getStudents().size()),
106                            new CSVField(p1.getPeriod().getIndex() + 1),
107                            new CSVField(p1.getPeriod().getDayStr()),
108                            new CSVField(p1.getPeriod().getTimeStr()),
109                            new CSVField(ex2.getName()),
110                            new CSVField(ex2.getStudents().size()),
111                            new CSVField(p2.getPeriod().getIndex() + 1),
112                            new CSVField(p2.getPeriod().getTimeStr()),
113                            new CSVField(ex3.getName()),
114                            new CSVField(ex3.getStudents().size()),
115                            new CSVField(p3.getPeriod().getIndex() + 1),
116                            new CSVField(p3.getPeriod().getTimeStr()),
117                            new CSVField(m2d),
118                            new CSVField(df.format(100.0
119                                    * m2d
120                                    / Math.min(Math.min(ex1.getStudents().size(), ex2.getStudents().size()), ex3
121                                            .getStudents().size()))) });
122                }
123            }
124        }
125        return csv;
126    }
127}