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