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