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     * &nbsp;&nbsp;&nbsp;&nbsp;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    }