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