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