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 (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                            }
375                        }
376                    }
377                    for (Iterator<?> j = offeringEl.elementIterator("reservation"); j.hasNext(); ) {
378                        Element reservationEl = (Element)j.next();
379                        Reservation r = null;
380                        if ("individual".equals(reservationEl.attributeValue("type"))) {
381                            Set<Long> studentIds = new HashSet<Long>();
382                            for (Iterator<?> k = reservationEl.elementIterator("student"); k.hasNext(); ) {
383                                Element studentEl = (Element)k.next();
384                                studentIds.add(Long.parseLong(studentEl.attributeValue("id")));
385                            }
386                            r = new IndividualReservation(Long.valueOf(reservationEl.attributeValue("id")), offering, studentIds);
387                        } else if ("group".equals(reservationEl.attributeValue("type"))) {
388                            Set<Long> studentIds = new HashSet<Long>();
389                            for (Iterator<?> k = reservationEl.elementIterator("student"); k.hasNext(); ) {
390                                Element studentEl = (Element)k.next();
391                                studentIds.add(Long.parseLong(studentEl.attributeValue("id")));
392                            }
393                            r = new GroupReservation(Long.valueOf(reservationEl.attributeValue("id")),
394                                    Double.parseDouble(reservationEl.attributeValue("limit", "-1")),
395                                    offering, studentIds);
396                        } else if ("curriculum".equals(reservationEl.attributeValue("type"))) {
397                            List<String> classifications = new ArrayList<String>();
398                            for (Iterator<?> k = reservationEl.elementIterator("classification"); k.hasNext(); ) {
399                                Element clasfEl = (Element)k.next();
400                                classifications.add(clasfEl.attributeValue("code"));
401                            }
402                            List<String> majors = new ArrayList<String>();
403                            for (Iterator<?> k = reservationEl.elementIterator("major"); k.hasNext(); ) {
404                                Element majorEl = (Element)k.next();
405                                majors.add(majorEl.attributeValue("code"));
406                            }
407                            r = new CurriculumReservation(Long.valueOf(reservationEl.attributeValue("id")),
408                                    Double.parseDouble(reservationEl.attributeValue("limit", "-1")),
409                                    offering,
410                                    reservationEl.attributeValue("area"),
411                                    classifications, majors);
412                        } else if ("course".equals(reservationEl.attributeValue("type"))) {
413                            long courseId = Long.parseLong(reservationEl.attributeValue("course"));
414                            for (Course course: offering.getCourses()) {
415                                if (course.getId() == courseId)
416                                    r = new CourseReservation(Long.valueOf(reservationEl.attributeValue("id")), course);
417                            }
418                        } else if ("dummy".equals(reservationEl.attributeValue("type"))) {
419                            r = new DummyReservation(offering);
420                        }
421                        if (r == null) {
422                            sLogger.error("Unknown reservation type "+ reservationEl.attributeValue("type"));
423                            continue;
424                        }
425                        r.setExpired("true".equals(reservationEl.attributeValue("expired", "false")));
426                        for (Iterator<?> k = reservationEl.elementIterator("config"); k.hasNext(); ) {
427                            Element configEl = (Element)k.next();
428                            r.addConfig(configTable.get(Long.parseLong(configEl.attributeValue("id"))));
429                        }
430                        for (Iterator<?> k = reservationEl.elementIterator("section"); k.hasNext(); ) {
431                            Element sectionEl = (Element)k.next();
432                            r.addSection(sectionTable.get(Long.parseLong(sectionEl.attributeValue("id"))));
433                        }
434                    } 
435                }
436            } else {
437                for (Offering offering : getModel().getOfferings()) {
438                    offeringTable.put(new Long(offering.getId()), offering);
439                    for (Course course : offering.getCourses()) {
440                        courseTable.put(new Long(course.getId()), course);
441                    }
442                }
443            }
444    
445            if (iLoadStudents && root.element("students") != null) {
446                List<Enrollment> bestEnrollments = new ArrayList<Enrollment>();
447                List<Enrollment> currentEnrollments = new ArrayList<Enrollment>();
448                for (Iterator<?> i = root.element("students").elementIterator("student"); i.hasNext();) {
449                    Element studentEl = (Element) i.next();
450                    Student student = new Student(Long.parseLong(studentEl.attributeValue("id")), "true".equals(studentEl.attributeValue("dummy")));
451                    student.setExternalId(studentEl.attributeValue("externalId"));
452                    student.setName(studentEl.attributeValue("name"));
453                    student.setStatus(studentEl.attributeValue("status"));
454                    for (Iterator<?> j = studentEl.elementIterator(); j.hasNext();) {
455                        Element requestEl = (Element) j.next();
456                        if ("classification".equals(requestEl.getName())) {
457                            student.getAcademicAreaClasiffications()
458                                    .add(
459                                            new AcademicAreaCode(requestEl.attributeValue("area"), requestEl
460                                                    .attributeValue("code")));
461                        } else if ("major".equals(requestEl.getName())) {
462                            student.getMajors()
463                                    .add(
464                                            new AcademicAreaCode(requestEl.attributeValue("area"), requestEl
465                                                    .attributeValue("code")));
466                        } else if ("minor".equals(requestEl.getName())) {
467                            student.getMinors()
468                                    .add(
469                                            new AcademicAreaCode(requestEl.attributeValue("area"), requestEl
470                                                    .attributeValue("code")));
471                        }
472                    }
473                    if (iStudentFilter != null && !iStudentFilter.accept(student))
474                        continue;
475                    for (Iterator<?> j = studentEl.elementIterator(); j.hasNext();) {
476                        Element requestEl = (Element) j.next();
477                        if ("freeTime".equals(requestEl.getName())) {
478                            TimeLocation time = new TimeLocation(Integer.parseInt(requestEl.attributeValue("days"), 2),
479                                    Integer.parseInt(requestEl.attributeValue("start")), Integer.parseInt(requestEl
480                                            .attributeValue("length")), 0, 0,
481                                    requestEl.attributeValue("datePattern") == null ? null : Long.valueOf(requestEl
482                                            .attributeValue("datePattern")), "", createBitSet(requestEl
483                                            .attributeValue("dates")), 0);
484                            FreeTimeRequest request = new FreeTimeRequest(Long.parseLong(requestEl.attributeValue("id")),
485                                    Integer.parseInt(requestEl.attributeValue("priority")), "true".equals(requestEl
486                                            .attributeValue("alternative")), student, time);
487                            if (requestEl.attributeValue("weight") != null)
488                                request.setWeight(Double.parseDouble(requestEl.attributeValue("weight")));
489                            if (iLoadBest && requestEl.element("best") != null)
490                                bestEnrollments.add(request.createEnrollment());
491                            if (iLoadInitial && requestEl.element("initial") != null)
492                                request.setInitialAssignment(request.createEnrollment());
493                            if (iLoadCurrent && requestEl.element("current") != null)
494                                currentEnrollments.add(request.createEnrollment());
495                        } else if ("course".equals(requestEl.getName())) {
496                            List<Course> courses = new ArrayList<Course>();
497                            courses.add(courseTable.get(Long.valueOf(requestEl.attributeValue("course"))));
498                            for (Iterator<?> k = requestEl.elementIterator("alternative"); k.hasNext();)
499                                courses.add(courseTable.get(Long.valueOf(((Element) k.next()).attributeValue("course"))));
500                            Long timeStamp = null;
501                            if (requestEl.attributeValue("timeStamp") != null)
502                                timeStamp = Long.valueOf(requestEl.attributeValue("timeStamp"));
503                            CourseRequest courseRequest = new CourseRequest(
504                                    Long.parseLong(requestEl.attributeValue("id")),
505                                    Integer.parseInt(requestEl.attributeValue("priority")),
506                                    "true".equals(requestEl.attributeValue("alternative")), 
507                                    student, courses,
508                                    "true".equals(requestEl.attributeValue("waitlist", "false")), timeStamp);
509                            if (requestEl.attributeValue("weight") != null)
510                                courseRequest.setWeight(Double.parseDouble(requestEl.attributeValue("weight")));
511                            for (Iterator<?> k = requestEl.elementIterator("waitlisted"); k.hasNext();) {
512                                Element choiceEl = (Element) k.next();
513                                courseRequest.getWaitlistedChoices().add(
514                                        new Choice(offeringTable.get(Long.valueOf(choiceEl.attributeValue("offering"))),
515                                                choiceEl.getText()));
516                            }
517                            for (Iterator<?> k = requestEl.elementIterator("selected"); k.hasNext();) {
518                                Element choiceEl = (Element) k.next();
519                                courseRequest.getSelectedChoices().add(
520                                        new Choice(offeringTable.get(Long.valueOf(choiceEl.attributeValue("offering"))),
521                                                choiceEl.getText()));
522                            }
523                            Element initialEl = requestEl.element("initial");
524                            if (iLoadInitial && initialEl != null) {
525                                HashSet<Section> sections = new HashSet<Section>();
526                                for (Iterator<?> k = initialEl.elementIterator("section"); k.hasNext();) {
527                                    Element sectionEl = (Element) k.next();
528                                    Section section = courseRequest.getSection(Long.parseLong(sectionEl
529                                            .attributeValue("id")));
530                                    sections.add(section);
531                                }
532                                Reservation reservation = null;
533                                if (initialEl.attributeValue("reservation", null) != null) {
534                                    long reservationId = Long.valueOf(initialEl.attributeValue("reservation"));
535                                    for (Course course: courseRequest.getCourses())
536                                        for (Reservation r: course.getOffering().getReservations())
537                                            if (r.getId() == reservationId) { reservation = r; break; }
538                                }
539                                if (!sections.isEmpty())
540                                    courseRequest.setInitialAssignment(courseRequest.createEnrollment(sections, reservation));
541                            }
542                            Element currentEl = requestEl.element("current");
543                            if (iLoadCurrent && currentEl != null) {
544                                HashSet<Section> sections = new HashSet<Section>();
545                                for (Iterator<?> k = currentEl.elementIterator("section"); k.hasNext();) {
546                                    Element sectionEl = (Element) k.next();
547                                    Section section = courseRequest.getSection(Long.parseLong(sectionEl
548                                            .attributeValue("id")));
549                                    sections.add(section);
550                                }
551                                Reservation reservation = null;
552                                if (currentEl.attributeValue("reservation", null) != null) {
553                                    long reservationId = Long.valueOf(currentEl.attributeValue("reservation"));
554                                    for (Course course: courseRequest.getCourses())
555                                        for (Reservation r: course.getOffering().getReservations())
556                                            if (r.getId() == reservationId) { reservation = r; break; }
557                                }
558                                if (!sections.isEmpty())
559                                    currentEnrollments.add(courseRequest.createEnrollment(sections, reservation));
560                            }
561                            Element bestEl = requestEl.element("best");
562                            if (iLoadBest && bestEl != null) {
563                                HashSet<Section> sections = new HashSet<Section>();
564                                for (Iterator<?> k = bestEl.elementIterator("section"); k.hasNext();) {
565                                    Element sectionEl = (Element) k.next();
566                                    Section section = courseRequest.getSection(Long.parseLong(sectionEl
567                                            .attributeValue("id")));
568                                    sections.add(section);
569                                }
570                                Reservation reservation = null;
571                                if (bestEl.attributeValue("reservation", null) != null) {
572                                    long reservationId = Long.valueOf(bestEl.attributeValue("reservation"));
573                                    for (Course course: courseRequest.getCourses())
574                                        for (Reservation r: course.getOffering().getReservations())
575                                            if (r.getId() == reservationId) { reservation = r; break; }
576                                }
577                                if (!sections.isEmpty())
578                                    bestEnrollments.add(courseRequest.createEnrollment(sections, reservation));
579                            }
580                        }
581                    }
582                    getModel().addStudent(student);
583                }
584    
585                if (!bestEnrollments.isEmpty()) {
586                    // Enrollments with a reservation must go first
587                    for (Enrollment enrollment : bestEnrollments) {
588                        if (enrollment.getReservation() == null) continue;
589                        Map<Constraint<Request, Enrollment>, Set<Enrollment>> conflicts = getModel().conflictConstraints(enrollment);
590                        if (conflicts.isEmpty())
591                            enrollment.variable().assign(0, enrollment);
592                        else
593                            sLogger.warn("Enrollment " + enrollment + " conflicts with " + conflicts);
594                    }
595                    for (Enrollment enrollment : bestEnrollments) {
596                        if (enrollment.getReservation() != null) continue;
597                        Map<Constraint<Request, Enrollment>, Set<Enrollment>> conflicts = getModel().conflictConstraints(enrollment);
598                        if (conflicts.isEmpty())
599                            enrollment.variable().assign(0, enrollment);
600                        else
601                            sLogger.warn("Enrollment " + enrollment + " conflicts with " + conflicts);
602                    }
603                    getModel().saveBest();
604                }
605    
606                if (!currentEnrollments.isEmpty()) {
607                    for (Request request : getModel().variables()) {
608                        if (request.getAssignment() != null)
609                            request.unassign(0);
610                    }
611                    for (Enrollment enrollment : currentEnrollments) {
612                        enrollment.variable().assign(0, enrollment);
613                    }
614                }
615            }
616            
617            if (root.element("constraints") != null) {
618                for (Iterator<?> i = root.element("constraints").elementIterator("linked-sections"); i.hasNext();) {
619                    Element linkedEl = (Element) i.next();
620                    List<Section> sections = new ArrayList<Section>();
621                    for (Iterator<?> j = linkedEl.elementIterator("section"); j.hasNext();) {
622                        Element sectionEl = (Element) j.next();
623                        Offering offering = offeringTable.get(Long.valueOf(sectionEl.attributeValue("offering")));
624                        sections.add(offering.getSection(Long.valueOf(sectionEl.attributeValue("id"))));
625                    }
626                    getModel().addLinkedSections(sections);
627                }
628            }
629            
630            sLogger.debug("Model successfully loaded.");
631        }
632    
633    }