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