001package net.sf.cpsolver.studentsct;
002
003import java.io.File;
004import java.util.ArrayList;
005import java.util.BitSet;
006import java.util.HashSet;
007import java.util.HashMap;
008import java.util.Iterator;
009import java.util.List;
010import java.util.Map;
011import java.util.Set;
012
013import net.sf.cpsolver.coursett.model.Placement;
014import net.sf.cpsolver.coursett.model.RoomLocation;
015import net.sf.cpsolver.coursett.model.TimeLocation;
016import net.sf.cpsolver.ifs.model.Constraint;
017import net.sf.cpsolver.ifs.util.Progress;
018import net.sf.cpsolver.studentsct.filter.StudentFilter;
019import net.sf.cpsolver.studentsct.model.AcademicAreaCode;
020import net.sf.cpsolver.studentsct.model.Choice;
021import net.sf.cpsolver.studentsct.model.Config;
022import net.sf.cpsolver.studentsct.model.Course;
023import net.sf.cpsolver.studentsct.model.CourseRequest;
024import net.sf.cpsolver.studentsct.model.Enrollment;
025import net.sf.cpsolver.studentsct.model.FreeTimeRequest;
026import net.sf.cpsolver.studentsct.model.Offering;
027import net.sf.cpsolver.studentsct.model.Request;
028import net.sf.cpsolver.studentsct.model.Section;
029import net.sf.cpsolver.studentsct.model.Student;
030import net.sf.cpsolver.studentsct.model.Subpart;
031import net.sf.cpsolver.studentsct.reservation.CourseReservation;
032import net.sf.cpsolver.studentsct.reservation.CurriculumReservation;
033import net.sf.cpsolver.studentsct.reservation.DummyReservation;
034import net.sf.cpsolver.studentsct.reservation.GroupReservation;
035import net.sf.cpsolver.studentsct.reservation.IndividualReservation;
036import net.sf.cpsolver.studentsct.reservation.Reservation;
037
038import org.dom4j.Document;
039import org.dom4j.Element;
040import 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
120public 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}