001 package net.sf.cpsolver.exam.reports; 002 003 import net.sf.cpsolver.exam.model.Exam; 004 import net.sf.cpsolver.exam.model.ExamModel; 005 import net.sf.cpsolver.exam.model.ExamOwner; 006 import net.sf.cpsolver.exam.model.ExamPeriod; 007 import net.sf.cpsolver.exam.model.ExamPlacement; 008 import net.sf.cpsolver.exam.model.ExamRoomPlacement; 009 import net.sf.cpsolver.exam.model.ExamStudent; 010 import net.sf.cpsolver.ifs.util.CSVFile; 011 import net.sf.cpsolver.ifs.util.CSVFile.CSVField; 012 013 /** 014 * Export student direct, back-to-back, and more than two exams a day conflicts 015 * into a CSV file. <br> 016 * <br> 017 * Usage:<br> 018 * <code> 019 * new ExamStudentConflicts(model).report().save(file); 020 * </code> <br> 021 * <br> 022 * 023 * @version ExamTT 1.2 (Examination Timetabling)<br> 024 * Copyright (C) 2008 - 2010 Tomas Muller<br> 025 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 026 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 027 * <br> 028 * This library is free software; you can redistribute it and/or modify 029 * it under the terms of the GNU Lesser General Public License as 030 * published by the Free Software Foundation; either version 3 of the 031 * License, or (at your option) any later version. <br> 032 * <br> 033 * This library is distributed in the hope that it will be useful, but 034 * WITHOUT ANY WARRANTY; without even the implied warranty of 035 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 036 * Lesser General Public License for more details. <br> 037 * <br> 038 * You should have received a copy of the GNU Lesser General Public 039 * License along with this library; if not see 040 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 041 */ 042 public class ExamStudentConflicts { 043 private ExamModel iModel = null; 044 045 /** 046 * Constructor 047 * 048 * @param model 049 * examination timetabling model 050 */ 051 public ExamStudentConflicts(ExamModel model) { 052 iModel = model; 053 } 054 055 /** 056 * generate report 057 */ 058 public CSVFile report() { 059 CSVFile csv = new CSVFile(); 060 csv.setHeader(new CSVField[] { new CSVField("Student"), new CSVField("Type"), new CSVField("Section/Course"), 061 new CSVField("Period"), new CSVField("Day"), new CSVField("Time"), new CSVField("Room"), 062 new CSVField("Distance") }); 063 for (ExamStudent student : iModel.getStudents()) { 064 for (ExamPeriod period : iModel.getPeriods()) { 065 int nrExams = student.getExams(period).size(); 066 if (nrExams > 1) { 067 String sections = ""; 068 String rooms = ""; 069 String periods = String.valueOf(period.getIndex() + 1); 070 String periodDays = period.getDayStr(); 071 String periodTimes = period.getTimeStr(); 072 for (Exam exam : student.getExams(period)) { 073 ExamPlacement placement = exam.getAssignment(); 074 String roomsThisExam = ""; 075 for (ExamRoomPlacement room : placement.getRoomPlacements()) { 076 if (roomsThisExam.length() > 0) 077 roomsThisExam += ", "; 078 roomsThisExam += room.getName(); 079 } 080 boolean first = true; 081 for (ExamOwner cs : exam.getOwners(student)) { 082 if (sections.length() > 0) { 083 sections += "\n"; 084 rooms += "\n"; 085 periods += "\n"; 086 periodDays += "\n"; 087 periodTimes += "\n"; 088 } 089 sections += cs.getName(); 090 if (first) 091 rooms += roomsThisExam; 092 first = false; 093 } 094 if (exam.getOwners(student).isEmpty()) { 095 sections += exam.getName(); 096 rooms += roomsThisExam; 097 } 098 } 099 csv.addLine(new CSVField[] { new CSVField(student.getName()), new CSVField("direct"), 100 new CSVField(sections), new CSVField(periods), new CSVField(periodDays), 101 new CSVField(periodTimes), new CSVField(rooms) }); 102 } 103 if (nrExams > 0) { 104 if (period.next() != null && !student.getExams(period.next()).isEmpty() 105 && (!iModel.isDayBreakBackToBack() || period.next().getDay() == period.getDay())) { 106 for (Exam ex1 : student.getExams(period)) { 107 for (Exam ex2 : student.getExams(period.next())) { 108 ExamPlacement placement = ex1.getAssignment(); 109 String sections = ""; 110 String rooms = ""; 111 String roomsThisExam = ""; 112 String periods = String.valueOf(period.getIndex() + 1); 113 String periodDays = period.getDayStr(); 114 String periodTimes = period.getTimeStr(); 115 for (ExamRoomPlacement room : placement.getRoomPlacements()) { 116 if (roomsThisExam.length() > 0) 117 roomsThisExam += ", "; 118 roomsThisExam += room.getName(); 119 } 120 boolean first = true; 121 for (ExamOwner cs : ex1.getOwners(student)) { 122 if (sections.length() > 0) { 123 sections += "\n"; 124 rooms += "\n"; 125 periods += "\n"; 126 periodDays += "\n"; 127 periodTimes += "\n"; 128 } 129 sections += cs.getName(); 130 if (first) 131 rooms += roomsThisExam; 132 first = false; 133 } 134 if (ex1.getOwners(student).isEmpty()) { 135 sections += ex1.getName(); 136 rooms += roomsThisExam; 137 } 138 placement = ex2.getAssignment(); 139 roomsThisExam = ""; 140 for (ExamRoomPlacement room : placement.getRoomPlacements()) { 141 if (roomsThisExam.length() > 0) 142 roomsThisExam += ", "; 143 roomsThisExam += room.getName(); 144 } 145 first = true; 146 for (ExamOwner cs : ex2.getOwners(student)) { 147 sections += "\n"; 148 rooms += "\n"; 149 periods += "\n"; 150 periodDays += "\n"; 151 periodTimes += "\n"; 152 sections += cs.getName(); 153 if (first) { 154 rooms += roomsThisExam; 155 periods += String.valueOf(period.next().getIndex() + 1); 156 periodDays += period.next().getDayStr(); 157 periodTimes += period.next().getTimeStr(); 158 } 159 first = false; 160 } 161 if (ex2.getOwners(student).isEmpty()) { 162 sections += "\n"; 163 rooms += "\n"; 164 periods += "\n"; 165 periodDays += "\n"; 166 periodTimes += "\n"; 167 sections += ex2.getName(); 168 rooms += roomsThisExam; 169 periods += String.valueOf(period.next().getIndex() + 1); 170 periodDays += period.next().getDayStr(); 171 periodTimes += period.next().getTimeStr(); 172 rooms += roomsThisExam; 173 } 174 String distStr = ""; 175 if (iModel.getBackToBackDistance() >= 0) { 176 double dist = (ex1.getAssignment()).getDistanceInMeters(ex2.getAssignment()); 177 if (dist > 0) 178 distStr = String.valueOf(dist); 179 } 180 csv.addLine(new CSVField[] { new CSVField(student.getName()), 181 new CSVField("back-to-back"), new CSVField(sections), new CSVField(periods), 182 new CSVField(periodDays), new CSVField(periodTimes), new CSVField(rooms), 183 new CSVField(distStr) }); 184 } 185 } 186 } 187 } 188 if (period.next() == null || period.next().getDay() != period.getDay()) { 189 int nrExamsADay = student.getExamsADay(period.getDay()).size(); 190 if (nrExamsADay > 2) { 191 String sections = ""; 192 String periods = ""; 193 String periodDays = ""; 194 String periodTimes = ""; 195 String rooms = ""; 196 for (Exam exam : student.getExamsADay(period.getDay())) { 197 ExamPlacement placement = exam.getAssignment(); 198 String roomsThisExam = ""; 199 for (ExamRoomPlacement room : placement.getRoomPlacements()) { 200 if (roomsThisExam.length() > 0) 201 roomsThisExam += ", "; 202 roomsThisExam += room.getName(); 203 } 204 boolean first = true; 205 for (ExamOwner cs : exam.getOwners(student)) { 206 if (sections.length() > 0) { 207 sections += "\n"; 208 rooms += "\n"; 209 periods += "\n"; 210 periodDays += "\n"; 211 periodTimes += "\n"; 212 } 213 sections += cs.getName(); 214 if (first) { 215 periods += (placement.getPeriod().getIndex() + 1); 216 periodDays += placement.getPeriod().getDayStr(); 217 periodTimes += placement.getPeriod().getTimeStr(); 218 rooms += roomsThisExam; 219 } 220 first = false; 221 } 222 if (exam.getOwners(student).isEmpty()) { 223 if (sections.length() > 0) { 224 sections += "\n"; 225 rooms += "\n"; 226 periods += "\n"; 227 periodDays += "\n"; 228 periodTimes += "\n"; 229 } 230 sections += exam.getName(); 231 periods += (placement.getPeriod().getIndex() + 1); 232 periodDays += placement.getPeriod().getDayStr(); 233 periodTimes += placement.getPeriod().getTimeStr(); 234 rooms += roomsThisExam; 235 } 236 } 237 csv.addLine(new CSVField[] { new CSVField(student.getName()), new CSVField("more-2-day"), 238 new CSVField(sections), new CSVField(periods), new CSVField(periodDays), 239 new CSVField(periodTimes), new CSVField(rooms) }); 240 } 241 } 242 } 243 } 244 return csv; 245 } 246 }