001package org.cpsolver.exam.reports;
002
003import org.cpsolver.exam.criteria.StudentBackToBackConflicts;
004import org.cpsolver.exam.criteria.StudentDistanceBackToBackConflicts;
005import org.cpsolver.exam.model.Exam;
006import org.cpsolver.exam.model.ExamModel;
007import org.cpsolver.exam.model.ExamOwner;
008import org.cpsolver.exam.model.ExamPeriod;
009import org.cpsolver.exam.model.ExamPlacement;
010import org.cpsolver.exam.model.ExamRoomPlacement;
011import org.cpsolver.exam.model.ExamStudent;
012import org.cpsolver.ifs.assignment.Assignment;
013import org.cpsolver.ifs.util.CSVFile;
014import org.cpsolver.ifs.util.CSVFile.CSVField;
015
016/**
017 * Export student direct, back-to-back, and more than two exams a day conflicts
018 * into a CSV file. <br>
019 * <br>
020 * Usage:
021 * <pre><code>
022 * &nbsp;&nbsp;&nbsp;&nbsp;new ExamStudentConflicts(model).report().save(file);
023 * </code></pre>
024 * <br>
025 * 
026 * @version ExamTT 1.3 (Examination Timetabling)<br>
027 *          Copyright (C) 2008 - 2014 Tomáš Müller<br>
028 *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
029 *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
030 * <br>
031 *          This library is free software; you can redistribute it and/or modify
032 *          it under the terms of the GNU Lesser General Public License as
033 *          published by the Free Software Foundation; either version 3 of the
034 *          License, or (at your option) any later version. <br>
035 * <br>
036 *          This library is distributed in the hope that it will be useful, but
037 *          WITHOUT ANY WARRANTY; without even the implied warranty of
038 *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
039 *          Lesser General Public License for more details. <br>
040 * <br>
041 *          You should have received a copy of the GNU Lesser General Public
042 *          License along with this library; if not see
043 *          <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
044 */
045public class ExamStudentConflicts {
046    private ExamModel iModel = null;
047
048    /**
049     * Constructor
050     * 
051     * @param model
052     *            examination timetabling model
053     */
054    public ExamStudentConflicts(ExamModel model) {
055        iModel = model;
056    }
057
058    /**
059     * generate report
060     * @param assignment current assignment
061     * @return resultant report
062     */
063    public CSVFile report(Assignment<Exam, ExamPlacement> assignment) {
064        CSVFile csv = new CSVFile();
065        csv.setHeader(new CSVField[] { new CSVField("Student"), new CSVField("Type"), new CSVField("Section/Course"),
066                new CSVField("Period"), new CSVField("Day"), new CSVField("Time"), new CSVField("Room"),
067                new CSVField("Distance") });
068        boolean isDayBreakBackToBack = ((StudentBackToBackConflicts)iModel.getCriterion(StudentBackToBackConflicts.class)).isDayBreakBackToBack();
069        double backToBackDistance = ((StudentDistanceBackToBackConflicts)iModel.getCriterion(StudentDistanceBackToBackConflicts.class)).getBackToBackDistance();
070        for (ExamStudent student : iModel.getStudents()) {
071            for (ExamPeriod period : iModel.getPeriods()) {
072                int nrExams = student.getExams(assignment, period).size();
073                if (nrExams > 1) {
074                    String sections = "";
075                    String rooms = "";
076                    String periods = String.valueOf(period.getIndex() + 1);
077                    String periodDays = period.getDayStr();
078                    String periodTimes = period.getTimeStr();
079                    for (Exam exam : student.getExams(assignment, period)) {
080                        ExamPlacement placement = assignment.getValue(exam);
081                        String roomsThisExam = "";
082                        for (ExamRoomPlacement room : placement.getRoomPlacements()) {
083                            if (roomsThisExam.length() > 0)
084                                roomsThisExam += ", ";
085                            roomsThisExam += room.getName();
086                        }
087                        boolean first = true;
088                        for (ExamOwner cs : exam.getOwners(student)) {
089                            if (sections.length() > 0) {
090                                sections += "\n";
091                                rooms += "\n";
092                                periods += "\n";
093                                periodDays += "\n";
094                                periodTimes += "\n";
095                            }
096                            sections += cs.getName();
097                            if (first)
098                                rooms += roomsThisExam;
099                            first = false;
100                        }
101                        if (exam.getOwners(student).isEmpty()) {
102                            sections += exam.getName();
103                            rooms += roomsThisExam;
104                        }
105                    }
106                    csv.addLine(new CSVField[] { new CSVField(student.getName()), new CSVField("direct"),
107                            new CSVField(sections), new CSVField(periods), new CSVField(periodDays),
108                            new CSVField(periodTimes), new CSVField(rooms) });
109                }
110                if (nrExams > 0) {
111                    if (period.next() != null && !student.getExams(assignment, period.next()).isEmpty()
112                            && (!isDayBreakBackToBack || period.next().getDay() == period.getDay())) {
113                        for (Exam ex1 : student.getExams(assignment, period)) {
114                            for (Exam ex2 : student.getExams(assignment, period.next())) {
115                                ExamPlacement placement = assignment.getValue(ex1);
116                                String sections = "";
117                                String rooms = "";
118                                String roomsThisExam = "";
119                                String periods = String.valueOf(period.getIndex() + 1);
120                                String periodDays = period.getDayStr();
121                                String periodTimes = period.getTimeStr();
122                                for (ExamRoomPlacement room : placement.getRoomPlacements()) {
123                                    if (roomsThisExam.length() > 0)
124                                        roomsThisExam += ", ";
125                                    roomsThisExam += room.getName();
126                                }
127                                boolean first = true;
128                                for (ExamOwner cs : ex1.getOwners(student)) {
129                                    if (sections.length() > 0) {
130                                        sections += "\n";
131                                        rooms += "\n";
132                                        periods += "\n";
133                                        periodDays += "\n";
134                                        periodTimes += "\n";
135                                    }
136                                    sections += cs.getName();
137                                    if (first)
138                                        rooms += roomsThisExam;
139                                    first = false;
140                                }
141                                if (ex1.getOwners(student).isEmpty()) {
142                                    sections += ex1.getName();
143                                    rooms += roomsThisExam;
144                                }
145                                placement = assignment.getValue(ex2);
146                                roomsThisExam = "";
147                                for (ExamRoomPlacement room : placement.getRoomPlacements()) {
148                                    if (roomsThisExam.length() > 0)
149                                        roomsThisExam += ", ";
150                                    roomsThisExam += room.getName();
151                                }
152                                first = true;
153                                for (ExamOwner cs : ex2.getOwners(student)) {
154                                    sections += "\n";
155                                    rooms += "\n";
156                                    periods += "\n";
157                                    periodDays += "\n";
158                                    periodTimes += "\n";
159                                    sections += cs.getName();
160                                    if (first) {
161                                        rooms += roomsThisExam;
162                                        periods += String.valueOf(period.next().getIndex() + 1);
163                                        periodDays += period.next().getDayStr();
164                                        periodTimes += period.next().getTimeStr();
165                                    }
166                                    first = false;
167                                }
168                                if (ex2.getOwners(student).isEmpty()) {
169                                    sections += "\n";
170                                    rooms += "\n";
171                                    periods += "\n";
172                                    periodDays += "\n";
173                                    periodTimes += "\n";
174                                    sections += ex2.getName();
175                                    rooms += roomsThisExam;
176                                    periods += String.valueOf(period.next().getIndex() + 1);
177                                    periodDays += period.next().getDayStr();
178                                    periodTimes += period.next().getTimeStr();
179                                    rooms += roomsThisExam;
180                                }
181                                String distStr = "";
182                                if (backToBackDistance >= 0) {
183                                    double dist = (assignment.getValue(ex1)).getDistanceInMeters(assignment.getValue(ex2));
184                                    if (dist > 0)
185                                        distStr = String.valueOf(dist);
186                                }
187                                csv.addLine(new CSVField[] { new CSVField(student.getName()),
188                                        new CSVField("back-to-back"), new CSVField(sections), new CSVField(periods),
189                                        new CSVField(periodDays), new CSVField(periodTimes), new CSVField(rooms),
190                                        new CSVField(distStr) });
191                            }
192                        }
193                    }
194                }
195                if (period.next() == null || period.next().getDay() != period.getDay()) {
196                    int nrExamsADay = student.getExamsADay(assignment, period.getDay()).size();
197                    if (nrExamsADay > 2) {
198                        String sections = "";
199                        String periods = "";
200                        String periodDays = "";
201                        String periodTimes = "";
202                        String rooms = "";
203                        for (Exam exam : student.getExamsADay(assignment, period.getDay())) {
204                            ExamPlacement placement = assignment.getValue(exam);
205                            String roomsThisExam = "";
206                            for (ExamRoomPlacement room : placement.getRoomPlacements()) {
207                                if (roomsThisExam.length() > 0)
208                                    roomsThisExam += ", ";
209                                roomsThisExam += room.getName();
210                            }
211                            boolean first = true;
212                            for (ExamOwner cs : exam.getOwners(student)) {
213                                if (sections.length() > 0) {
214                                    sections += "\n";
215                                    rooms += "\n";
216                                    periods += "\n";
217                                    periodDays += "\n";
218                                    periodTimes += "\n";
219                                }
220                                sections += cs.getName();
221                                if (first) {
222                                    periods += (placement.getPeriod().getIndex() + 1);
223                                    periodDays += placement.getPeriod().getDayStr();
224                                    periodTimes += placement.getPeriod().getTimeStr();
225                                    rooms += roomsThisExam;
226                                }
227                                first = false;
228                            }
229                            if (exam.getOwners(student).isEmpty()) {
230                                if (sections.length() > 0) {
231                                    sections += "\n";
232                                    rooms += "\n";
233                                    periods += "\n";
234                                    periodDays += "\n";
235                                    periodTimes += "\n";
236                                }
237                                sections += exam.getName();
238                                periods += (placement.getPeriod().getIndex() + 1);
239                                periodDays += placement.getPeriod().getDayStr();
240                                periodTimes += placement.getPeriod().getTimeStr();
241                                rooms += roomsThisExam;
242                            }
243                        }
244                        csv.addLine(new CSVField[] { new CSVField(student.getName()), new CSVField("more-2-day"),
245                                new CSVField(sections), new CSVField(periods), new CSVField(periodDays),
246                                new CSVField(periodTimes), new CSVField(rooms) });
247                    }
248                }
249            }
250        }
251        return csv;
252    }
253}