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