001    package net.sf.cpsolver.studentsct;
002    
003    import java.io.File;
004    import java.util.ArrayList;
005    import java.util.BitSet;
006    import java.util.HashSet;
007    import java.util.HashMap;
008    import java.util.Iterator;
009    import java.util.List;
010    import java.util.Map;
011    import java.util.Set;
012    
013    import net.sf.cpsolver.coursett.model.Placement;
014    import net.sf.cpsolver.coursett.model.RoomLocation;
015    import net.sf.cpsolver.coursett.model.TimeLocation;
016    import net.sf.cpsolver.ifs.model.Constraint;
017    import net.sf.cpsolver.ifs.util.Progress;
018    import net.sf.cpsolver.studentsct.filter.StudentFilter;
019    import net.sf.cpsolver.studentsct.model.AcademicAreaCode;
020    import net.sf.cpsolver.studentsct.model.Choice;
021    import net.sf.cpsolver.studentsct.model.Config;
022    import net.sf.cpsolver.studentsct.model.Course;
023    import net.sf.cpsolver.studentsct.model.CourseRequest;
024    import net.sf.cpsolver.studentsct.model.Enrollment;
025    import net.sf.cpsolver.studentsct.model.FreeTimeRequest;
026    import net.sf.cpsolver.studentsct.model.Offering;
027    import net.sf.cpsolver.studentsct.model.Request;
028    import net.sf.cpsolver.studentsct.model.Section;
029    import net.sf.cpsolver.studentsct.model.Student;
030    import net.sf.cpsolver.studentsct.model.Subpart;
031    import net.sf.cpsolver.studentsct.reservation.CourseReservation;
032    import net.sf.cpsolver.studentsct.reservation.CurriculumReservation;
033    import net.sf.cpsolver.studentsct.reservation.DummyReservation;
034    import net.sf.cpsolver.studentsct.reservation.GroupReservation;
035    import net.sf.cpsolver.studentsct.reservation.IndividualReservation;
036    import net.sf.cpsolver.studentsct.reservation.Reservation;
037    
038    import org.dom4j.Document;
039    import org.dom4j.Element;
040    import org.dom4j.io.SAXReader;
041    
042    /**
043     * Load student sectioning model from an XML file.
044     * 
045     * <br>
046     * <br>
047     * Parameters:
048     * <table border='1'>
049     * <tr>
050     * <th>Parameter</th>
051     * <th>Type</th>
052     * <th>Comment</th>
053     * </tr>
054     * <tr>
055     * <td>General.Input</td>
056     * <td>{@link String}</td>
057     * <td>Path of an XML file to be loaded</td>
058     * </tr>
059     * <tr>
060     * <td>Xml.LoadBest</td>
061     * <td>{@link Boolean}</td>
062     * <td>If true, load best assignments</td>
063     * </tr>
064     * <tr>
065     * <td>Xml.LoadInitial</td>
066     * <td>{@link Boolean}</td>
067     * <td>If false, load initial assignments</td>
068     * </tr>
069     * <tr>
070     * <td>Xml.LoadCurrent</td>
071     * <td>{@link Boolean}</td>
072     * <td>If true, load current assignments</td>
073     * </tr>
074     * <tr>
075     * <td>Xml.LoadOfferings</td>
076     * <td>{@link Boolean}</td>
077     * <td>If true, load offerings (and their stucture, i.e., courses,
078     * configurations, subparts and sections)</td>
079     * </tr>
080     * <tr>
081     * <td>Xml.LoadStudents</td>
082     * <td>{@link Boolean}</td>
083     * <td>If true, load students (and their requests)</td>
084     * </tr>
085     * <tr>
086     * <td>Xml.StudentFilter</td>
087     * <td>{@link StudentFilter}</td>
088     * <td>If provided, students are filtered by the given student filter</td>
089     * </tr>
090     * </table>
091     * 
092     * <br>
093     * <br>
094     * Usage:<br>
095     * <code>
096     * StudentSectioningModel model = new StudentSectioningModel(cfg);<br>
097     * new StudentSectioningXMLLoader(model).load();<br>
098     * </code>
099     * 
100     * @version StudentSct 1.2 (Student Sectioning)<br>
101     *          Copyright (C) 2007 - 2010 Tomas Muller<br>
102     *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
103     *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
104     * <br>
105     *          This library is free software; you can redistribute it and/or modify
106     *          it under the terms of the GNU Lesser General Public License as
107     *          published by the Free Software Foundation; either version 3 of the
108     *          License, or (at your option) any later version. <br>
109     * <br>
110     *          This library is distributed in the hope that it will be useful, but
111     *          WITHOUT ANY WARRANTY; without even the implied warranty of
112     *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
113     *          Lesser General Public License for more details. <br>
114     * <br>
115     *          You should have received a copy of the GNU Lesser General Public
116     *          License along with this library; if not see
117     *          <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
118     */
119    
120    public class StudentSectioningXMLLoader extends StudentSectioningLoader {
121        private static org.apache.log4j.Logger sLogger = org.apache.log4j.Logger
122                .getLogger(StudentSectioningXMLLoader.class);
123    
124        private File iInputFile;
125        private File iTimetableFile = null;
126        private boolean iLoadBest = false;
127        private boolean iLoadInitial = false;
128        private boolean iLoadCurrent = false;
129        private boolean iLoadOfferings = true;
130        private boolean iLoadStudents = true;
131        private StudentFilter iStudentFilter = null;
132    
133        /**
134         * Constructor
135         * 
136         * @param model
137         *            student sectioning model
138         */
139        public StudentSectioningXMLLoader(StudentSectioningModel model) {
140            super(model);
141            iInputFile = new File(getModel().getProperties().getProperty("General.Input",
142                    "." + File.separator + "solution.xml"));
143            if (getModel().getProperties().getProperty("General.InputTimetable") != null)
144                iTimetableFile = new File(getModel().getProperties().getProperty("General.InputTimetable"));
145            iLoadBest = getModel().getProperties().getPropertyBoolean("Xml.LoadBest", true);
146            iLoadInitial = getModel().getProperties().getPropertyBoolean("Xml.LoadInitial", true);
147            iLoadCurrent = getModel().getProperties().getPropertyBoolean("Xml.LoadCurrent", true);
148            iLoadOfferings = getModel().getProperties().getPropertyBoolean("Xml.LoadOfferings", true);
149            iLoadStudents = getModel().getProperties().getPropertyBoolean("Xml.LoadStudents", true);
150            if (getModel().getProperties().getProperty("Xml.StudentFilter") != null) {
151                try {
152                    iStudentFilter = (StudentFilter) Class.forName(
153                            getModel().getProperties().getProperty("Xml.StudentFilter")).getConstructor(new Class[] {})
154                            .newInstance(new Object[] {});
155                } catch (Exception e) {
156                    sLogger.error("Unable to create student filter, reason: " + e.getMessage(), e);
157                }
158            }
159        }
160    
161        /** Set input file (e.g., if it is not set by General.Input property) */
162        public void setInputFile(File inputFile) {
163            iInputFile = inputFile;
164        }
165    
166        /** Set student filter */
167        public void setStudentFilter(StudentFilter filter) {
168            iStudentFilter = filter;
169        }
170    
171        /** Set whether to load students */
172        public void setLoadStudents(boolean loadStudents) {
173            iLoadStudents = loadStudents;
174        }
175    
176        /** Set whether to load offerings */
177        public void setLoadOfferings(boolean loadOfferings) {
178            iLoadOfferings = loadOfferings;
179        }
180    
181        /** Create BitSet from a bit string */
182        private static BitSet createBitSet(String bitString) {
183            BitSet ret = new BitSet(bitString.length());
184            for (int i = 0; i < bitString.length(); i++)
185                if (bitString.charAt(i) == '1')
186                    ret.set(i);
187            return ret;
188        }
189    
190        /** Load the file */
191        @Override
192        public void load() throws Exception {
193            sLogger.debug("Reading XML data from " + iInputFile);
194    
195            Document document = (new SAXReader()).read(iInputFile);
196            Element root = document.getRootElement();
197            sLogger.debug("Root element: " + root.getName());
198            if (!"sectioning".equals(root.getName())) {
199                sLogger.error("Given XML file is not student sectioning problem.");
200                return;
201            }
202            
203            if (iLoadOfferings && getModel().getDistanceConflict() != null && root.element("travel-times") != null) {
204                for (Iterator<?> i = root.element("travel-times").elementIterator("travel-time"); i.hasNext();) {
205                    Element travelTimeEl = (Element)i.next();
206                    getModel().getDistanceConflict().getDistanceMetric().addTravelTime(
207                            Long.valueOf(travelTimeEl.attributeValue("id1")),
208                            Long.valueOf(travelTimeEl.attributeValue("id2")),
209                            Integer.valueOf(travelTimeEl.attributeValue("minutes")));
210                }
211            }
212            
213            HashMap<Long, Placement> timetable = null;
214            if (iTimetableFile != null) {
215                sLogger.info("Reading timetable from " + iTimetableFile + " ...");
216                Document timetableDocument = (new SAXReader()).read(iTimetableFile);
217                Element timetableRoot = timetableDocument.getRootElement();
218                if (!"timetable".equals(timetableRoot.getName())) {
219                    sLogger.error("Given XML file is not course timetabling problem.");
220                    return;
221                }
222                timetable = new HashMap<Long, Placement>();
223                HashMap<Long, RoomLocation> rooms = new HashMap<Long, RoomLocation>();
224                for (Iterator<?> i = timetableRoot.element("rooms").elementIterator("room"); i.hasNext();) {
225                    Element roomEl = (Element)i.next();
226                    Long roomId = Long.valueOf(roomEl.attributeValue("id"));
227                    Double posX = null, posY = null;
228                    if (roomEl.attributeValue("location") != null) {
229                        String loc = roomEl.attributeValue("location");
230                        posX = Double.valueOf(loc.substring(0, loc.indexOf(',')));
231                        posY = Double.valueOf(loc.substring(loc.indexOf(',') + 1));
232                    }
233                    RoomLocation room = new RoomLocation(Long.valueOf(roomEl.attributeValue("id")), roomEl
234                            .attributeValue("name", "R" + roomEl.attributeValue("id")), roomEl
235                            .attributeValue("building") == null ? null : Long.valueOf(roomEl
236                            .attributeValue("building")), 0, Integer.parseInt(roomEl
237                            .attributeValue("capacity")), posX, posY, "true".equals(roomEl
238                            .attributeValue("ignoreTooFar")), null);
239                    rooms.put(roomId, room);
240                }
241                for (Iterator<?> i = timetableRoot.element("classes").elementIterator("class"); i.hasNext();) {
242                    Element classEl = (Element)i.next();
243                    Long classId = Long.valueOf(classEl.attributeValue("id"));
244                    TimeLocation time = null;
245                    Element timeEl = null;
246                    for (Iterator<?> j = classEl.elementIterator("time"); j.hasNext(); ) {
247                        Element e = (Element)j.next();
248                        if ("true".equals(e.attributeValue("solution", "false"))) { timeEl = e; break; }
249                    }
250                    if (timeEl != null) {
251                        time = new TimeLocation(Integer.parseInt(timeEl.attributeValue("days"), 2), Integer
252                                .parseInt(timeEl.attributeValue("start")), Integer.parseInt(timeEl
253                                .attributeValue("length")), 0, 0,
254                                classEl.attributeValue("datePattern") == null ? null : Long.valueOf(classEl
255                                        .attributeValue("datePattern")), classEl.attributeValue(
256                                        "datePatternName", ""), createBitSet(classEl.attributeValue("dates")),
257                                Integer.parseInt(timeEl.attributeValue("breakTime", "0")));
258                        if (timeEl.attributeValue("pattern") != null)
259                            time.setTimePatternId(Long.valueOf(timeEl.attributeValue("pattern")));
260                    }
261                    List<RoomLocation> room = new ArrayList<RoomLocation>();
262                    for (Iterator<?> j = classEl.elementIterator("room"); j.hasNext();) {
263                        Element roomEl = (Element) j.next();
264                        if (!"true".equals(roomEl.attributeValue("solution", "false"))) continue;
265                        room.add(rooms.get(Long.valueOf(roomEl.attributeValue("id"))));
266                    }
267                    Placement placement = (time == null ? null : new Placement(null, time, room));
268                    if (placement != null)
269                        timetable.put(classId, placement);
270                }
271            }
272    
273            Progress.getInstance(getModel()).load(root, true);
274            Progress.getInstance(getModel()).message(Progress.MSGLEVEL_STAGE, "Restoring from backup ...");
275    
276            if (root.attributeValue("term") != null)
277                getModel().getProperties().setProperty("Data.Term", root.attributeValue("term"));
278            if (root.attributeValue("year") != null)
279                getModel().getProperties().setProperty("Data.Year", root.attributeValue("year"));
280            if (root.attributeValue("initiative") != null)
281                getModel().getProperties().setProperty("Data.Initiative", root.attributeValue("initiative"));
282    
283            HashMap<Long, Offering> offeringTable = new HashMap<Long, Offering>();
284            HashMap<Long, Course> courseTable = new HashMap<Long, Course>();
285    
286            if (iLoadOfferings && root.element("offerings") != null) {
287                HashMap<Long, Config> configTable = new HashMap<Long, Config>();
288                HashMap<Long, Subpart> subpartTable = new HashMap<Long, Subpart>();
289                HashMap<Long, Section> sectionTable = new HashMap<Long, Section>();
290                for (Iterator<?> i = root.element("offerings").elementIterator("offering"); i.hasNext();) {
291                    Element offeringEl = (Element) i.next();
292                    Offering offering = new Offering(Long.parseLong(offeringEl.attributeValue("id")), offeringEl
293                            .attributeValue("name", "O" + offeringEl.attributeValue("id")));
294                    offeringTable.put(new Long(offering.getId()), offering);
295                    getModel().addOffering(offering);
296                    for (Iterator<?> j = offeringEl.elementIterator("course"); j.hasNext();) {
297                        Element courseEl = (Element) j.next();
298                        Course course = new Course(Long.parseLong(courseEl.attributeValue("id")), courseEl.attributeValue(
299                                "subjectArea", ""), courseEl.attributeValue("courseNbr", "C"
300                                + courseEl.attributeValue("id")), offering, Integer.parseInt(courseEl.attributeValue(
301                                "limit", "-1")), Integer.parseInt(courseEl.attributeValue("projected", "0")));
302                        courseTable.put(new Long(course.getId()), course);
303                    }
304                    for (Iterator<?> j = offeringEl.elementIterator("config"); j.hasNext();) {
305                        Element configEl = (Element) j.next();
306                        Config config = new Config(Long.parseLong(configEl.attributeValue("id")),
307                                Integer.parseInt(configEl.attributeValue("limit", "-1")),
308                                configEl.attributeValue("name", "G" + configEl.attributeValue("id")),
309                                offering);
310                        configTable.put(config.getId(), config);
311                        for (Iterator<?> k = configEl.elementIterator("subpart"); k.hasNext();) {
312                            Element subpartEl = (Element) k.next();
313                            Subpart parentSubpart = null;
314                            if (subpartEl.attributeValue("parent") != null)
315                                parentSubpart = subpartTable.get(Long.valueOf(subpartEl.attributeValue("parent")));
316                            Subpart subpart = new Subpart(Long.parseLong(subpartEl.attributeValue("id")), subpartEl
317                                    .attributeValue("itype"), subpartEl.attributeValue("name", "P"
318                                    + subpartEl.attributeValue("id")), config, parentSubpart);
319                            subpart.setAllowOverlap("true".equals(subpartEl.attributeValue("allowOverlap", "false")));
320                            subpartTable.put(new Long(subpart.getId()), subpart);
321                            for (Iterator<?> l = subpartEl.elementIterator("section"); l.hasNext();) {
322                                Element sectionEl = (Element) l.next();
323                                Section parentSection = null;
324                                if (sectionEl.attributeValue("parent") != null)
325                                    parentSection = sectionTable.get(Long.valueOf(sectionEl.attributeValue("parent")));
326                                Placement placement = null;
327                                if (timetable != null) {
328                                    placement = timetable.get(Long.parseLong(sectionEl.attributeValue("id")));
329                                } else {
330                                    TimeLocation time = null;
331                                    Element timeEl = sectionEl.element("time");
332                                    if (timeEl != null) {
333                                        time = new TimeLocation(Integer.parseInt(timeEl.attributeValue("days"), 2), Integer
334                                                .parseInt(timeEl.attributeValue("start")), Integer.parseInt(timeEl
335                                                .attributeValue("length")), 0, 0,
336                                                timeEl.attributeValue("datePattern") == null ? null : Long.valueOf(timeEl
337                                                        .attributeValue("datePattern")), timeEl.attributeValue(
338                                                        "datePatternName", ""), createBitSet(timeEl.attributeValue("dates")),
339                                                Integer.parseInt(timeEl.attributeValue("breakTime", "0")));
340                                        if (timeEl.attributeValue("pattern") != null)
341                                            time.setTimePatternId(Long.valueOf(timeEl.attributeValue("pattern")));
342                                    }
343                                    List<RoomLocation> rooms = new ArrayList<RoomLocation>();
344                                    for (Iterator<?> m = sectionEl.elementIterator("room"); m.hasNext();) {
345                                        Element roomEl = (Element) m.next();
346                                        Double posX = null, posY = null;
347                                        if (roomEl.attributeValue("location") != null) {
348                                            String loc = roomEl.attributeValue("location");
349                                            posX = Double.valueOf(loc.substring(0, loc.indexOf(',')));
350                                            posY = Double.valueOf(loc.substring(loc.indexOf(',') + 1));
351                                        }
352                                        RoomLocation room = new RoomLocation(Long.valueOf(roomEl.attributeValue("id")), roomEl
353                                                .attributeValue("name", "R" + roomEl.attributeValue("id")), roomEl
354                                                .attributeValue("building") == null ? null : Long.valueOf(roomEl
355                                                .attributeValue("building")), 0, Integer.parseInt(roomEl
356                                                .attributeValue("capacity")), posX, posY, "true".equals(roomEl
357                                                .attributeValue("ignoreTooFar")), null);
358                                        rooms.add(room);
359                                    }
360                                    placement = (time == null ? null : new Placement(null, time, rooms));
361                                }
362                                Section section = new Section(Long.parseLong(sectionEl.attributeValue("id")), Integer
363                                        .parseInt(sectionEl.attributeValue("limit")), sectionEl.attributeValue("name", "S"
364                                        + sectionEl.attributeValue("id")), subpart, placement, sectionEl
365                                        .attributeValue("instructorIds"), sectionEl.attributeValue("instructorNames"),
366                                        parentSection);
367                                sectionTable.put(new Long(section.getId()), section);
368                                section.setSpaceHeld(Double.parseDouble(sectionEl.attributeValue("hold", "0.0")));
369                                section.setSpaceExpected(Double.parseDouble(sectionEl.attributeValue("expect", "0.0")));
370                                for (Iterator<?> m = sectionEl.elementIterator("cname"); m.hasNext(); ) {
371                                    Element cNameEl = (Element)m.next();
372                                    section.setName(Long.parseLong(cNameEl.attributeValue("id")), cNameEl.getText());
373                                }
374                                Element ignoreEl = sectionEl.element("no-conflicts");
375                                if (ignoreEl != null) {
376                                    for (Iterator<?> m = ignoreEl.elementIterator("section"); m.hasNext(); )
377                                        section.addIgnoreConflictWith(Long.parseLong(((Element)m.next()).attributeValue("id")));
378                                }
379                            }
380                        }
381                    }
382                    for (Iterator<?> j = offeringEl.elementIterator("reservation"); j.hasNext(); ) {
383                        Element reservationEl = (Element)j.next();
384                        Reservation r = null;
385                        if ("individual".equals(reservationEl.attributeValue("type"))) {
386                            Set<Long> studentIds = new HashSet<Long>();
387                            for (Iterator<?> k = reservationEl.elementIterator("student"); k.hasNext(); ) {
388                                Element studentEl = (Element)k.next();
389                                studentIds.add(Long.parseLong(studentEl.attributeValue("id")));
390                            }
391                            r = new IndividualReservation(Long.valueOf(reservationEl.attributeValue("id")), offering, studentIds);
392                        } else if ("group".equals(reservationEl.attributeValue("type"))) {
393                            Set<Long> studentIds = new HashSet<Long>();
394                            for (Iterator<?> k = reservationEl.elementIterator("student"); k.hasNext(); ) {
395                                Element studentEl = (Element)k.next();
396                                studentIds.add(Long.parseLong(studentEl.attributeValue("id")));
397                            }
398                            r = new GroupReservation(Long.valueOf(reservationEl.attributeValue("id")),
399                                    Double.parseDouble(reservationEl.attributeValue("limit", "-1")),
400                                    offering, studentIds);
401                        } else if ("curriculum".equals(reservationEl.attributeValue("type"))) {
402                            List<String> classifications = new ArrayList<String>();
403                            for (Iterator<?> k = reservationEl.elementIterator("classification"); k.hasNext(); ) {
404                                Element clasfEl = (Element)k.next();
405                                classifications.add(clasfEl.attributeValue("code"));
406                            }
407                            List<String> majors = new ArrayList<String>();
408                            for (Iterator<?> k = reservationEl.elementIterator("major"); k.hasNext(); ) {
409                                Element majorEl = (Element)k.next();
410                                majors.add(majorEl.attributeValue("code"));
411                            }
412                            r = new CurriculumReservation(Long.valueOf(reservationEl.attributeValue("id")),
413                                    Double.parseDouble(reservationEl.attributeValue("limit", "-1")),
414                                    offering,
415                                    reservationEl.attributeValue("area"),
416                                    classifications, majors);
417                        } else if ("course".equals(reservationEl.attributeValue("type"))) {
418                            long courseId = Long.parseLong(reservationEl.attributeValue("course"));
419                            for (Course course: offering.getCourses()) {
420                                if (course.getId() == courseId)
421                                    r = new CourseReservation(Long.valueOf(reservationEl.attributeValue("id")), course);
422                            }
423                        } else if ("dummy".equals(reservationEl.attributeValue("type"))) {
424                            r = new DummyReservation(offering);
425                        }
426                        if (r == null) {
427                            sLogger.error("Unknown reservation type "+ reservationEl.attributeValue("type"));
428                            continue;
429                        }
430                        r.setExpired("true".equals(reservationEl.attributeValue("expired", "false")));
431                        for (Iterator<?> k = reservationEl.elementIterator("config"); k.hasNext(); ) {
432                            Element configEl = (Element)k.next();
433                            r.addConfig(configTable.get(Long.parseLong(configEl.attributeValue("id"))));
434                        }
435                        for (Iterator<?> k = reservationEl.elementIterator("section"); k.hasNext(); ) {
436                            Element sectionEl = (Element)k.next();
437                            r.addSection(sectionTable.get(Long.parseLong(sectionEl.attributeValue("id"))));
438                        }
439                    } 
440                }
441            } else {
442                for (Offering offering : getModel().getOfferings()) {
443                    offeringTable.put(new Long(offering.getId()), offering);
444                    for (Course course : offering.getCourses()) {
445                        courseTable.put(new Long(course.getId()), course);
446                    }
447                }
448            }
449    
450            if (iLoadStudents && root.element("students") != null) {
451                List<Enrollment> bestEnrollments = new ArrayList<Enrollment>();
452                List<Enrollment> currentEnrollments = new ArrayList<Enrollment>();
453                for (Iterator<?> i = root.element("students").elementIterator("student"); i.hasNext();) {
454                    Element studentEl = (Element) i.next();
455                    Student student = new Student(Long.parseLong(studentEl.attributeValue("id")), "true".equals(studentEl.attributeValue("dummy")));
456                    student.setExternalId(studentEl.attributeValue("externalId"));
457                    student.setName(studentEl.attributeValue("name"));
458                    student.setStatus(studentEl.attributeValue("status"));
459                    for (Iterator<?> j = studentEl.elementIterator(); j.hasNext();) {
460                        Element requestEl = (Element) j.next();
461                        if ("classification".equals(requestEl.getName())) {
462                            student.getAcademicAreaClasiffications()
463                                    .add(
464                                            new AcademicAreaCode(requestEl.attributeValue("area"), requestEl
465                                                    .attributeValue("code")));
466                        } else if ("major".equals(requestEl.getName())) {
467                            student.getMajors()
468                                    .add(
469                                            new AcademicAreaCode(requestEl.attributeValue("area"), requestEl
470                                                    .attributeValue("code")));
471                        } else if ("minor".equals(requestEl.getName())) {
472                            student.getMinors()
473                                    .add(
474                                            new AcademicAreaCode(requestEl.attributeValue("area"), requestEl
475                                                    .attributeValue("code")));
476                        }
477                    }
478                    if (iStudentFilter != null && !iStudentFilter.accept(student))
479                        continue;
480                    for (Iterator<?> j = studentEl.elementIterator(); j.hasNext();) {
481                        Element requestEl = (Element) j.next();
482                        if ("freeTime".equals(requestEl.getName())) {
483                            TimeLocation time = new TimeLocation(Integer.parseInt(requestEl.attributeValue("days"), 2),
484                                    Integer.parseInt(requestEl.attributeValue("start")), Integer.parseInt(requestEl
485                                            .attributeValue("length")), 0, 0,
486                                    requestEl.attributeValue("datePattern") == null ? null : Long.valueOf(requestEl
487                                            .attributeValue("datePattern")), "", createBitSet(requestEl
488                                            .attributeValue("dates")), 0);
489                            FreeTimeRequest request = new FreeTimeRequest(Long.parseLong(requestEl.attributeValue("id")),
490                                    Integer.parseInt(requestEl.attributeValue("priority")), "true".equals(requestEl
491                                            .attributeValue("alternative")), student, time);
492                            if (requestEl.attributeValue("weight") != null)
493                                request.setWeight(Double.parseDouble(requestEl.attributeValue("weight")));
494                            if (iLoadBest && requestEl.element("best") != null)
495                                bestEnrollments.add(request.createEnrollment());
496                            if (iLoadInitial && requestEl.element("initial") != null)
497                                request.setInitialAssignment(request.createEnrollment());
498                            if (iLoadCurrent && requestEl.element("current") != null)
499                                currentEnrollments.add(request.createEnrollment());
500                        } else if ("course".equals(requestEl.getName())) {
501                            List<Course> courses = new ArrayList<Course>();
502                            courses.add(courseTable.get(Long.valueOf(requestEl.attributeValue("course"))));
503                            for (Iterator<?> k = requestEl.elementIterator("alternative"); k.hasNext();)
504                                courses.add(courseTable.get(Long.valueOf(((Element) k.next()).attributeValue("course"))));
505                            Long timeStamp = null;
506                            if (requestEl.attributeValue("timeStamp") != null)
507                                timeStamp = Long.valueOf(requestEl.attributeValue("timeStamp"));
508                            CourseRequest courseRequest = new CourseRequest(
509                                    Long.parseLong(requestEl.attributeValue("id")),
510                                    Integer.parseInt(requestEl.attributeValue("priority")),
511                                    "true".equals(requestEl.attributeValue("alternative")), 
512                                    student, courses,
513                                    "true".equals(requestEl.attributeValue("waitlist", "false")), timeStamp);
514                            if (requestEl.attributeValue("weight") != null)
515                                courseRequest.setWeight(Double.parseDouble(requestEl.attributeValue("weight")));
516                            for (Iterator<?> k = requestEl.elementIterator("waitlisted"); k.hasNext();) {
517                                Element choiceEl = (Element) k.next();
518                                courseRequest.getWaitlistedChoices().add(
519                                        new Choice(offeringTable.get(Long.valueOf(choiceEl.attributeValue("offering"))),
520                                                choiceEl.getText()));
521                            }
522                            for (Iterator<?> k = requestEl.elementIterator("selected"); k.hasNext();) {
523                                Element choiceEl = (Element) k.next();
524                                courseRequest.getSelectedChoices().add(
525                                        new Choice(offeringTable.get(Long.valueOf(choiceEl.attributeValue("offering"))),
526                                                choiceEl.getText()));
527                            }
528                            Element initialEl = requestEl.element("initial");
529                            if (iLoadInitial && initialEl != null) {
530                                HashSet<Section> sections = new HashSet<Section>();
531                                for (Iterator<?> k = initialEl.elementIterator("section"); k.hasNext();) {
532                                    Element sectionEl = (Element) k.next();
533                                    Section section = courseRequest.getSection(Long.parseLong(sectionEl
534                                            .attributeValue("id")));
535                                    sections.add(section);
536                                }
537                                Reservation reservation = null;
538                                if (initialEl.attributeValue("reservation", null) != null) {
539                                    long reservationId = Long.valueOf(initialEl.attributeValue("reservation"));
540                                    for (Course course: courseRequest.getCourses())
541                                        for (Reservation r: course.getOffering().getReservations())
542                                            if (r.getId() == reservationId) { reservation = r; break; }
543                                }
544                                if (!sections.isEmpty())
545                                    courseRequest.setInitialAssignment(courseRequest.createEnrollment(sections, reservation));
546                            }
547                            Element currentEl = requestEl.element("current");
548                            if (iLoadCurrent && currentEl != null) {
549                                HashSet<Section> sections = new HashSet<Section>();
550                                for (Iterator<?> k = currentEl.elementIterator("section"); k.hasNext();) {
551                                    Element sectionEl = (Element) k.next();
552                                    Section section = courseRequest.getSection(Long.parseLong(sectionEl
553                                            .attributeValue("id")));
554                                    sections.add(section);
555                                }
556                                Reservation reservation = null;
557                                if (currentEl.attributeValue("reservation", null) != null) {
558                                    long reservationId = Long.valueOf(currentEl.attributeValue("reservation"));
559                                    for (Course course: courseRequest.getCourses())
560                                        for (Reservation r: course.getOffering().getReservations())
561                                            if (r.getId() == reservationId) { reservation = r; break; }
562                                }
563                                if (!sections.isEmpty())
564                                    currentEnrollments.add(courseRequest.createEnrollment(sections, reservation));
565                            }
566                            Element bestEl = requestEl.element("best");
567                            if (iLoadBest && bestEl != null) {
568                                HashSet<Section> sections = new HashSet<Section>();
569                                for (Iterator<?> k = bestEl.elementIterator("section"); k.hasNext();) {
570                                    Element sectionEl = (Element) k.next();
571                                    Section section = courseRequest.getSection(Long.parseLong(sectionEl
572                                            .attributeValue("id")));
573                                    sections.add(section);
574                                }
575                                Reservation reservation = null;
576                                if (bestEl.attributeValue("reservation", null) != null) {
577                                    long reservationId = Long.valueOf(bestEl.attributeValue("reservation"));
578                                    for (Course course: courseRequest.getCourses())
579                                        for (Reservation r: course.getOffering().getReservations())
580                                            if (r.getId() == reservationId) { reservation = r; break; }
581                                }
582                                if (!sections.isEmpty())
583                                    bestEnrollments.add(courseRequest.createEnrollment(sections, reservation));
584                            }
585                        }
586                    }
587                    getModel().addStudent(student);
588                }
589    
590                if (!bestEnrollments.isEmpty()) {
591                    // Enrollments with a reservation must go first
592                    for (Enrollment enrollment : bestEnrollments) {
593                        if (enrollment.getReservation() == null) continue;
594                        Map<Constraint<Request, Enrollment>, Set<Enrollment>> conflicts = getModel().conflictConstraints(enrollment);
595                        if (conflicts.isEmpty())
596                            enrollment.variable().assign(0, enrollment);
597                        else
598                            sLogger.warn("Enrollment " + enrollment + " conflicts with " + conflicts);
599                    }
600                    for (Enrollment enrollment : bestEnrollments) {
601                        if (enrollment.getReservation() != null) continue;
602                        Map<Constraint<Request, Enrollment>, Set<Enrollment>> conflicts = getModel().conflictConstraints(enrollment);
603                        if (conflicts.isEmpty())
604                            enrollment.variable().assign(0, enrollment);
605                        else
606                            sLogger.warn("Enrollment " + enrollment + " conflicts with " + conflicts);
607                    }
608                    getModel().saveBest();
609                }
610    
611                if (!currentEnrollments.isEmpty()) {
612                    for (Request request : getModel().variables()) {
613                        if (request.getAssignment() != null)
614                            request.unassign(0);
615                    }
616                    for (Enrollment enrollment : currentEnrollments) {
617                        enrollment.variable().assign(0, enrollment);
618                    }
619                }
620            }
621            
622            if (iLoadOfferings && root.element("constraints") != null) {
623                for (Iterator<?> i = root.element("constraints").elementIterator("linked-sections"); i.hasNext();) {
624                    Element linkedEl = (Element) i.next();
625                    List<Section> sections = new ArrayList<Section>();
626                    for (Iterator<?> j = linkedEl.elementIterator("section"); j.hasNext();) {
627                        Element sectionEl = (Element) j.next();
628                        Offering offering = offeringTable.get(Long.valueOf(sectionEl.attributeValue("offering")));
629                        sections.add(offering.getSection(Long.valueOf(sectionEl.attributeValue("id"))));
630                    }
631                    getModel().addLinkedSections(sections);
632                }
633            }
634            
635            sLogger.debug("Model successfully loaded.");
636        }
637    
638    }