001package org.cpsolver.exam.reports;
002
003import org.cpsolver.exam.criteria.InstructorBackToBackConflicts;
004import org.cpsolver.exam.criteria.InstructorDistanceBackToBackConflicts;
005import org.cpsolver.exam.model.Exam;
006import org.cpsolver.exam.model.ExamInstructor;
007import org.cpsolver.exam.model.ExamModel;
008import org.cpsolver.exam.model.ExamOwner;
009import org.cpsolver.exam.model.ExamPeriod;
010import org.cpsolver.exam.model.ExamPlacement;
011import org.cpsolver.exam.model.ExamRoomPlacement;
012import org.cpsolver.ifs.assignment.Assignment;
013import org.cpsolver.ifs.util.CSVFile;
014import org.cpsolver.ifs.util.CSVFile.CSVField;
015
016/**
017 * Export instructor direct, back-to-back, and more than two exams a day
018 * conflicts into a CSV file. <br>
019 * <br>
020 * Usage:
021 * <pre><code>
022 * &nbsp;&nbsp;&nbsp;&nbsp;new ExamInstructorConflicts(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 ExamInstructorConflicts {
046    private ExamModel iModel = null;
047
048    /**
049     * Constructor
050     * 
051     * @param model
052     *            examination timetabling model
053     */
054    public ExamInstructorConflicts(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("Instructor"), new CSVField("Type"),
066                new CSVField("Section/Course"), new CSVField("Period"), new CSVField("Day"), new CSVField("Time"),
067                new CSVField("Room"), new CSVField("Distance") });
068        boolean isDayBreakBackToBack = ((InstructorBackToBackConflicts)iModel.getCriterion(InstructorBackToBackConflicts.class)).isDayBreakBackToBack();
069        double backToBackDistance = ((InstructorDistanceBackToBackConflicts)iModel.getCriterion(InstructorDistanceBackToBackConflicts.class)).getBackToBackDistance();
070        for (ExamInstructor instructor : iModel.getInstructors()) {
071            for (ExamPeriod period : iModel.getPeriods()) {
072                int nrExams = instructor.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 : instructor.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 owner : exam.getOwners(instructor)) {
089                            if (sections.length() > 0) {
090                                sections += "\n";
091                                rooms += "\n";
092                                periods += "\n";
093                                periodDays += "\n";
094                                periodTimes += "\n";
095                            }
096                            sections += owner.getName();
097                            if (first)
098                                rooms += roomsThisExam;
099                            first = false;
100                        }
101                        if (exam.getOwners(instructor).isEmpty()) {
102                            sections += exam.getName();
103                            rooms += roomsThisExam;
104                        }
105                    }
106                    csv.addLine(new CSVField[] { new CSVField(instructor.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 && !instructor.getExams(assignment, period.next()).isEmpty()
112                            && (!isDayBreakBackToBack || period.next().getDay() == period.getDay())) {
113                        for (Exam ex1 : instructor.getExams(assignment, period)) {
114                            for (Exam ex2 : instructor.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 owner : ex1.getOwners(instructor)) {
129                                    if (sections.length() > 0) {
130                                        sections += "\n";
131                                        rooms += "\n";
132                                        periods += "\n";
133                                        periodDays += "\n";
134                                        periodTimes += "\n";
135                                    }
136                                    sections += owner.getName();
137                                    if (first)
138                                        rooms += roomsThisExam;
139                                    first = false;
140                                }
141                                if (ex1.getOwners(instructor).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 owner : ex2.getOwners(instructor)) {
154                                    sections += "\n";
155                                    rooms += "\n";
156                                    periods += "\n";
157                                    periodDays += "\n";
158                                    periodTimes += "\n";
159                                    sections += owner.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(instructor).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                                }
180                                String distStr = "";
181                                if (backToBackDistance >= 0) {
182                                    double dist = (assignment.getValue(ex1)).getDistanceInMeters(assignment.getValue(ex2));
183                                    if (dist > 0)
184                                        distStr = String.valueOf(dist);
185                                }
186                                csv.addLine(new CSVField[] { new CSVField(instructor.getName()),
187                                        new CSVField("back-to-back"), new CSVField(sections), new CSVField(periods),
188                                        new CSVField(periodDays), new CSVField(periodTimes), new CSVField(rooms),
189                                        new CSVField(distStr) });
190                            }
191                        }
192                    }
193                }
194                if (period.next() == null || period.next().getDay() != period.getDay()) {
195                    int nrExamsADay = instructor.getExamsADay(assignment, period.getDay()).size();
196                    if (nrExamsADay > 2) {
197                        String sections = "";
198                        String periods = "";
199                        String periodDays = "";
200                        String periodTimes = "";
201                        String rooms = "";
202                        for (Exam exam : instructor.getExamsADay(assignment, period.getDay())) {
203                            ExamPlacement placement = assignment.getValue(exam);
204                            String roomsThisExam = "";
205                            for (ExamRoomPlacement room : placement.getRoomPlacements()) {
206                                if (roomsThisExam.length() > 0)
207                                    roomsThisExam += ", ";
208                                roomsThisExam += room.getName();
209                            }
210                            boolean first = true;
211                            for (ExamOwner owner : exam.getOwners(instructor)) {
212                                if (sections.length() > 0) {
213                                    sections += "\n";
214                                    rooms += "\n";
215                                    periods += "\n";
216                                    periodDays += "\n";
217                                    periodTimes += "\n";
218                                }
219                                sections += owner.getName();
220                                if (first) {
221                                    periods += (placement.getPeriod().getIndex() + 1);
222                                    periodDays += placement.getPeriod().getDayStr();
223                                    periodTimes += placement.getPeriod().getTimeStr();
224                                    rooms += roomsThisExam;
225                                }
226                                first = false;
227                            }
228                            if (exam.getOwners(instructor).isEmpty()) {
229                                if (sections.length() > 0) {
230                                    sections += "\n";
231                                    rooms += "\n";
232                                    periods += "\n";
233                                    periodDays += "\n";
234                                    periodTimes += "\n";
235                                }
236                                sections += exam.getName();
237                                periods += (placement.getPeriod().getIndex() + 1);
238                                periodDays += placement.getPeriod().getDayStr();
239                                periodTimes += placement.getPeriod().getTimeStr();
240                                rooms += roomsThisExam;
241                            }
242                        }
243                        csv.addLine(new CSVField[] { new CSVField(instructor.getName()), new CSVField("more-2-day"),
244                                new CSVField(sections), new CSVField(periods), new CSVField(periodDays),
245                                new CSVField(periodTimes), new CSVField(rooms) });
246                    }
247                }
248            }
249        }
250        return csv;
251    }
252}