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