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 * new ExamInstructorConflicts(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 ExamInstructorConflicts { 047 private ExamModel iModel = null; 048 049 /** 050 * Constructor 051 * 052 * @param model 053 * examination timetabling model 054 */ 055 public ExamInstructorConflicts(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("Instructor"), new CSVField("Type"), 067 new CSVField("Section/Course"), new CSVField("Period"), new CSVField("Day"), new CSVField("Time"), 068 new CSVField("Room"), new CSVField("Distance") }); 069 boolean isDayBreakBackToBack = ((InstructorBackToBackConflicts)iModel.getCriterion(InstructorBackToBackConflicts.class)).isDayBreakBackToBack(); 070 double backToBackDistance = ((InstructorDistanceBackToBackConflicts)iModel.getCriterion(InstructorDistanceBackToBackConflicts.class)).getBackToBackDistance(); 071 for (ExamInstructor instructor : iModel.getInstructors()) { 072 for (ExamPeriod period : iModel.getPeriods()) { 073 int nrExams = instructor.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 : instructor.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 owner : exam.getOwners(instructor)) { 090 if (sections.length() > 0) { 091 sections += "\n"; 092 rooms += "\n"; 093 periods += "\n"; 094 periodDays += "\n"; 095 periodTimes += "\n"; 096 } 097 sections += owner.getName(); 098 if (first) 099 rooms += roomsThisExam; 100 first = false; 101 } 102 if (exam.getOwners(instructor).isEmpty()) { 103 sections += exam.getName(); 104 rooms += roomsThisExam; 105 } 106 } 107 csv.addLine(new CSVField[] { new CSVField(instructor.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 && !instructor.getExams(assignment, period.next()).isEmpty() 113 && (!isDayBreakBackToBack || period.next().getDay() == period.getDay())) { 114 for (Exam ex1 : instructor.getExams(assignment, period)) { 115 for (Exam ex2 : instructor.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 owner : ex1.getOwners(instructor)) { 130 if (sections.length() > 0) { 131 sections += "\n"; 132 rooms += "\n"; 133 periods += "\n"; 134 periodDays += "\n"; 135 periodTimes += "\n"; 136 } 137 sections += owner.getName(); 138 if (first) 139 rooms += roomsThisExam; 140 first = false; 141 } 142 if (ex1.getOwners(instructor).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 owner : ex2.getOwners(instructor)) { 155 sections += "\n"; 156 rooms += "\n"; 157 periods += "\n"; 158 periodDays += "\n"; 159 periodTimes += "\n"; 160 sections += owner.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(instructor).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 } 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(instructor.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 = instructor.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 : instructor.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 owner : exam.getOwners(instructor)) { 213 if (sections.length() > 0) { 214 sections += "\n"; 215 rooms += "\n"; 216 periods += "\n"; 217 periodDays += "\n"; 218 periodTimes += "\n"; 219 } 220 sections += owner.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(instructor).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(instructor.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}