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 * @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}