001package net.sf.cpsolver.studentsct; 002 003import java.io.File; 004import java.io.FileOutputStream; 005import java.io.IOException; 006import java.math.RoundingMode; 007import java.text.DecimalFormat; 008import java.text.DecimalFormatSymbols; 009import java.util.BitSet; 010import java.util.Date; 011import java.util.Locale; 012import java.util.Map; 013import java.util.Set; 014import java.util.TreeSet; 015 016import org.dom4j.Document; 017import org.dom4j.DocumentHelper; 018import org.dom4j.Element; 019import org.dom4j.io.OutputFormat; 020import org.dom4j.io.XMLWriter; 021 022import net.sf.cpsolver.coursett.IdConvertor; 023import net.sf.cpsolver.coursett.model.RoomLocation; 024import net.sf.cpsolver.coursett.model.TimeLocation; 025import net.sf.cpsolver.ifs.solver.Solver; 026import net.sf.cpsolver.ifs.util.Progress; 027import net.sf.cpsolver.studentsct.constraint.LinkedSections; 028import net.sf.cpsolver.studentsct.model.AcademicAreaCode; 029import net.sf.cpsolver.studentsct.model.Choice; 030import net.sf.cpsolver.studentsct.model.Config; 031import net.sf.cpsolver.studentsct.model.Course; 032import net.sf.cpsolver.studentsct.model.CourseRequest; 033import net.sf.cpsolver.studentsct.model.Enrollment; 034import net.sf.cpsolver.studentsct.model.FreeTimeRequest; 035import net.sf.cpsolver.studentsct.model.Offering; 036import net.sf.cpsolver.studentsct.model.Request; 037import net.sf.cpsolver.studentsct.model.Section; 038import net.sf.cpsolver.studentsct.model.Student; 039import net.sf.cpsolver.studentsct.model.Subpart; 040import net.sf.cpsolver.studentsct.reservation.CourseReservation; 041import net.sf.cpsolver.studentsct.reservation.CurriculumReservation; 042import net.sf.cpsolver.studentsct.reservation.DummyReservation; 043import net.sf.cpsolver.studentsct.reservation.GroupReservation; 044import net.sf.cpsolver.studentsct.reservation.IndividualReservation; 045import net.sf.cpsolver.studentsct.reservation.Reservation; 046 047/** 048 * Save student sectioning solution into an XML file. 049 * 050 * <br> 051 * <br> 052 * Parameters: 053 * <table border='1'> 054 * <tr> 055 * <th>Parameter</th> 056 * <th>Type</th> 057 * <th>Comment</th> 058 * </tr> 059 * <tr> 060 * <td>General.Output</td> 061 * <td>{@link String}</td> 062 * <td>Folder with the output solution in XML format (solution.xml)</td> 063 * </tr> 064 * <tr> 065 * <td>Xml.ConvertIds</td> 066 * <td>{@link Boolean}</td> 067 * <td>If true, ids are converted (to be able to make input data public)</td> 068 * </tr> 069 * <tr> 070 * <td>Xml.ShowNames</td> 071 * <td>{@link Boolean}</td> 072 * <td>If false, names are not exported (to be able to make input data public)</td> 073 * </tr> 074 * <tr> 075 * <td>Xml.SaveBest</td> 076 * <td>{@link Boolean}</td> 077 * <td>If true, best solution is saved.</td> 078 * </tr> 079 * <tr> 080 * <td>Xml.SaveInitial</td> 081 * <td>{@link Boolean}</td> 082 * <td>If true, initial solution is saved.</td> 083 * </tr> 084 * <tr> 085 * <td>Xml.SaveCurrent</td> 086 * <td>{@link Boolean}</td> 087 * <td>If true, current solution is saved.</td> 088 * </tr> 089 * <tr> 090 * <td>Xml.SaveOnlineSectioningInfo</td> 091 * <td>{@link Boolean}</td> 092 * <td>If true, save online sectioning info (i.e., expected and held space of 093 * each section)</td> 094 * </tr> 095 * <tr> 096 * <td>Xml.SaveStudentInfo</td> 097 * <td>{@link Boolean}</td> 098 * <td>If true, save student information (i.e., academic area classification, 099 * major, minor)</td> 100 * </tr> 101 * </table> 102 * <br> 103 * <br> 104 * Usage:<br> 105 * <code> 106 * new StudentSectioningXMLSaver(solver).save(new File("solution.xml"));<br> 107 * </code> 108 * 109 * @version StudentSct 1.2 (Student Sectioning)<br> 110 * Copyright (C) 2007 - 2010 Tomáš Müller<br> 111 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 112 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 113 * <br> 114 * This library is free software; you can redistribute it and/or modify 115 * it under the terms of the GNU Lesser General Public License as 116 * published by the Free Software Foundation; either version 3 of the 117 * License, or (at your option) any later version. <br> 118 * <br> 119 * This library is distributed in the hope that it will be useful, but 120 * WITHOUT ANY WARRANTY; without even the implied warranty of 121 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 122 * Lesser General Public License for more details. <br> 123 * <br> 124 * You should have received a copy of the GNU Lesser General Public 125 * License along with this library; if not see 126 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 127 */ 128 129public class StudentSectioningXMLSaver extends StudentSectioningSaver { 130 private static org.apache.log4j.Logger sLogger = org.apache.log4j.Logger.getLogger(StudentSectioningXMLSaver.class); 131 private static DecimalFormat[] sDF = { new DecimalFormat(""), new DecimalFormat("0"), new DecimalFormat("00"), 132 new DecimalFormat("000"), new DecimalFormat("0000"), new DecimalFormat("00000"), 133 new DecimalFormat("000000"), new DecimalFormat("0000000") }; 134 private static DecimalFormat sStudentWeightFormat = new DecimalFormat("0.0000", new DecimalFormatSymbols(Locale.US)); 135 private File iOutputFolder = null; 136 137 private boolean iSaveBest = false; 138 private boolean iSaveInitial = false; 139 private boolean iSaveCurrent = false; 140 private boolean iSaveOnlineSectioningInfo = false; 141 private boolean iSaveStudentInfo = true; 142 143 private boolean iConvertIds = false; 144 private boolean iShowNames = false; 145 146 static { 147 sStudentWeightFormat.setRoundingMode(RoundingMode.DOWN); 148 } 149 150 /** 151 * Constructor 152 * 153 * @param solver 154 * student sectioning solver 155 */ 156 public StudentSectioningXMLSaver(Solver<Request, Enrollment> solver) { 157 super(solver); 158 iOutputFolder = new File(getModel().getProperties().getProperty("General.Output", 159 "." + File.separator + "output")); 160 iSaveBest = getModel().getProperties().getPropertyBoolean("Xml.SaveBest", true); 161 iSaveInitial = getModel().getProperties().getPropertyBoolean("Xml.SaveInitial", true); 162 iSaveCurrent = getModel().getProperties().getPropertyBoolean("Xml.SaveCurrent", false); 163 iSaveOnlineSectioningInfo = getModel().getProperties().getPropertyBoolean("Xml.SaveOnlineSectioningInfo", true); 164 iSaveStudentInfo = getModel().getProperties().getPropertyBoolean("Xml.SaveStudentInfo", true); 165 iShowNames = getModel().getProperties().getPropertyBoolean("Xml.ShowNames", true); 166 iConvertIds = getModel().getProperties().getPropertyBoolean("Xml.ConvertIds", false); 167 } 168 169 /** Convert bitset to a bit string */ 170 private static String bitset2string(BitSet b) { 171 StringBuffer sb = new StringBuffer(); 172 for (int i = 0; i < b.length(); i++) 173 sb.append(b.get(i) ? "1" : "0"); 174 return sb.toString(); 175 } 176 177 /** Generate id for given object with the given id */ 178 private String getId(String type, String id) { 179 if (!iConvertIds) 180 return id.toString(); 181 return IdConvertor.getInstance().convert(type, id); 182 } 183 184 /** Generate id for given object with the given id */ 185 private String getId(String type, Number id) { 186 return getId(type, id.toString()); 187 } 188 189 /** Generate id for given object with the given id */ 190 private String getId(String type, long id) { 191 return getId(type, String.valueOf(id)); 192 } 193 194 /** Save an XML file */ 195 @Override 196 public void save() throws Exception { 197 save(null); 198 } 199 200 /** 201 * Save an XML file 202 * 203 * @param outFile 204 * output file 205 */ 206 public void save(File outFile) throws Exception { 207 if (outFile == null) { 208 outFile = new File(iOutputFolder, "solution.xml"); 209 } else if (outFile.getParentFile() != null) { 210 outFile.getParentFile().mkdirs(); 211 } 212 sLogger.debug("Writting XML data to:" + outFile); 213 214 Document document = DocumentHelper.createDocument(); 215 document.addComment("Student Sectioning"); 216 217 populate(document); 218 219 FileOutputStream fos = null; 220 try { 221 fos = new FileOutputStream(outFile); 222 (new XMLWriter(fos, OutputFormat.createPrettyPrint())).write(document); 223 fos.flush(); 224 fos.close(); 225 fos = null; 226 } finally { 227 try { 228 if (fos != null) 229 fos.close(); 230 } catch (IOException e) { 231 } 232 } 233 234 if (iConvertIds) 235 IdConvertor.getInstance().save(); 236 } 237 238 /** 239 * Fill in all the data into the given document 240 * @param document document to be populated 241 */ 242 protected void populate(Document document) { 243 if ((iSaveCurrent || iSaveBest)) { 244 StringBuffer comments = new StringBuffer("Solution Info:\n"); 245 Map<String, String> solutionInfo = (getSolution() == null ? getModel().getExtendedInfo() : getSolution() 246 .getExtendedInfo()); 247 for (String key : new TreeSet<String>(solutionInfo.keySet())) { 248 String value = solutionInfo.get(key); 249 comments.append(" " + key + ": " + value + "\n"); 250 } 251 document.addComment(comments.toString()); 252 } 253 254 Element root = document.addElement("sectioning"); 255 root.addAttribute("version", "1.0"); 256 root.addAttribute("initiative", getModel().getProperties().getProperty("Data.Initiative")); 257 root.addAttribute("term", getModel().getProperties().getProperty("Data.Term")); 258 root.addAttribute("year", getModel().getProperties().getProperty("Data.Year")); 259 root.addAttribute("created", String.valueOf(new Date())); 260 261 saveOfferings(root); 262 263 saveStudents(root); 264 265 saveLinkedSections(root); 266 267 saveTravelTimes(root); 268 269 if (iShowNames) { 270 Progress.getInstance(getModel()).save(root); 271 } 272 } 273 274 /** 275 * Save offerings 276 * @param root document root 277 */ 278 protected void saveOfferings(Element root) { 279 Element offeringsEl = root.addElement("offerings"); 280 for (Offering offering : getModel().getOfferings()) { 281 Element offeringEl = offeringsEl.addElement("offering"); 282 saveOffering(offeringEl, offering); 283 saveReservations(offeringEl, offering); 284 } 285 } 286 287 /** 288 * Save given offering 289 * @param offeringEl offering element to be populated 290 * @param offering offering to be saved 291 */ 292 protected void saveOffering(Element offeringEl, Offering offering) { 293 offeringEl.addAttribute("id", getId("offering", offering.getId())); 294 if (iShowNames) 295 offeringEl.addAttribute("name", offering.getName()); 296 for (Course course : offering.getCourses()) { 297 Element courseEl = offeringEl.addElement("course"); 298 saveCourse(courseEl, course); 299 } 300 for (Config config : offering.getConfigs()) { 301 Element configEl = offeringEl.addElement("config"); 302 saveConfig(configEl, config); 303 } 304 } 305 306 /** 307 * Save given course 308 * @param courseEl course element to be populated 309 * @param course course to be saved 310 */ 311 protected void saveCourse(Element courseEl, Course course) { 312 courseEl.addAttribute("id", getId("course", course.getId())); 313 if (iShowNames) 314 courseEl.addAttribute("subjectArea", course.getSubjectArea()); 315 if (iShowNames) 316 courseEl.addAttribute("courseNbr", course.getCourseNumber()); 317 if (iShowNames && course.getLimit() >= 0) 318 courseEl.addAttribute("limit", String.valueOf(course.getLimit())); 319 if (iShowNames && course.getProjected() != 0) 320 courseEl.addAttribute("projected", String.valueOf(course.getProjected())); 321 } 322 323 /** 324 * Save given config 325 * @param configEl config element to be populated 326 * @param config config to be saved 327 */ 328 protected void saveConfig(Element configEl, Config config) { 329 configEl.addAttribute("id", getId("config", config.getId())); 330 if (config.getLimit() >= 0) 331 configEl.addAttribute("limit", String.valueOf(config.getLimit())); 332 if (iShowNames) 333 configEl.addAttribute("name", config.getName()); 334 for (Subpart subpart : config.getSubparts()) { 335 Element subpartEl = configEl.addElement("subpart"); 336 saveSubpart(subpartEl, subpart); 337 } 338 } 339 340 /** 341 * Save scheduling subpart 342 * @param subpartEl subpart element to be populated 343 * @param subpart subpart to be saved 344 */ 345 protected void saveSubpart(Element subpartEl, Subpart subpart) { 346 subpartEl.addAttribute("id", getId("subpart", subpart.getId())); 347 subpartEl.addAttribute("itype", subpart.getInstructionalType()); 348 if (subpart.getParent() != null) 349 subpartEl.addAttribute("parent", getId("subpart", subpart.getParent().getId())); 350 if (iShowNames) 351 subpartEl.addAttribute("name", subpart.getName()); 352 if (subpart.isAllowOverlap()) 353 subpartEl.addAttribute("allowOverlap", "true"); 354 for (Section section : subpart.getSections()) { 355 Element sectionEl = subpartEl.addElement("section"); 356 saveSection(sectionEl, section); 357 } 358 } 359 360 /** 361 * Save section 362 * @param sectionEl section element to be populated 363 * @param section section to be saved 364 */ 365 protected void saveSection(Element sectionEl, Section section) { 366 sectionEl.addAttribute("id", getId("section", section.getId())); 367 sectionEl.addAttribute("limit", String.valueOf(section.getLimit())); 368 if (section.getNameByCourse() != null) 369 for (Map.Entry<Long, String> entry: section.getNameByCourse().entrySet()) 370 sectionEl.addElement("cname").addAttribute("id", entry.getKey().toString()).setText(entry.getValue()); 371 if (section.getParent() != null) 372 sectionEl.addAttribute("parent", getId("section", section.getParent().getId())); 373 if (iShowNames && section.getChoice().getInstructorIds() != null) 374 sectionEl.addAttribute("instructorIds", section.getChoice().getInstructorIds()); 375 if (iShowNames && section.getChoice().getInstructorNames() != null) 376 sectionEl.addAttribute("instructorNames", section.getChoice().getInstructorNames()); 377 if (iShowNames) 378 sectionEl.addAttribute("name", section.getName()); 379 if (section.getPlacement() != null) { 380 TimeLocation tl = section.getPlacement().getTimeLocation(); 381 if (tl != null) { 382 Element timeLocationEl = sectionEl.addElement("time"); 383 timeLocationEl.addAttribute("days", sDF[7].format(Long.parseLong(Integer 384 .toBinaryString(tl.getDayCode())))); 385 timeLocationEl.addAttribute("start", String.valueOf(tl.getStartSlot())); 386 timeLocationEl.addAttribute("length", String.valueOf(tl.getLength())); 387 if (tl.getBreakTime() != 0) 388 timeLocationEl.addAttribute("breakTime", String.valueOf(tl.getBreakTime())); 389 if (iShowNames && tl.getTimePatternId() != null) 390 timeLocationEl.addAttribute("pattern", getId("timePattern", tl.getTimePatternId())); 391 if (iShowNames && tl.getDatePatternId() != null) 392 timeLocationEl.addAttribute("datePattern", tl.getDatePatternId().toString()); 393 if (iShowNames && tl.getDatePatternName() != null 394 && tl.getDatePatternName().length() > 0) 395 timeLocationEl.addAttribute("datePatternName", tl.getDatePatternName()); 396 timeLocationEl.addAttribute("dates", bitset2string(tl.getWeekCode())); 397 if (iShowNames) 398 timeLocationEl.setText(tl.getLongName()); 399 } 400 for (RoomLocation rl : section.getRooms()) { 401 Element roomLocationEl = sectionEl.addElement("room"); 402 roomLocationEl.addAttribute("id", getId("room", rl.getId())); 403 if (iShowNames && rl.getBuildingId() != null) 404 roomLocationEl.addAttribute("building", getId("building", rl.getBuildingId())); 405 if (iShowNames && rl.getName() != null) 406 roomLocationEl.addAttribute("name", rl.getName()); 407 roomLocationEl.addAttribute("capacity", String.valueOf(rl.getRoomSize())); 408 if (rl.getPosX() != null && rl.getPosY() != null) 409 roomLocationEl.addAttribute("location", rl.getPosX() + "," + rl.getPosY()); 410 if (rl.getIgnoreTooFar()) 411 roomLocationEl.addAttribute("ignoreTooFar", "true"); 412 } 413 } 414 if (iSaveOnlineSectioningInfo) { 415 if (section.getSpaceHeld() != 0.0) 416 sectionEl.addAttribute("hold", sStudentWeightFormat.format(section.getSpaceHeld())); 417 if (section.getSpaceExpected() != 0.0) 418 sectionEl.addAttribute("expect", sStudentWeightFormat 419 .format(section.getSpaceExpected())); 420 } 421 if (section.getIgnoreConflictWithSectionIds() != null && !section.getIgnoreConflictWithSectionIds().isEmpty()) { 422 Element ignoreEl = sectionEl.addElement("no-conflicts"); 423 for (Long sectionId: section.getIgnoreConflictWithSectionIds()) 424 ignoreEl.addElement("section").addAttribute("id", getId("section", sectionId)); 425 } 426 } 427 428 /** 429 * Save reservations of the given offering 430 * @param offeringEl offering element to be populated with reservations 431 * @param offering offering which reservations are to be saved 432 */ 433 protected void saveReservations(Element offeringEl, Offering offering) { 434 if (!offering.getReservations().isEmpty()) { 435 for (Reservation r: offering.getReservations()) { 436 saveReservation(offeringEl.addElement("reservation"), r); 437 } 438 } 439 } 440 441 /** 442 * Save reservation 443 * @param reservationEl reservation element to be populated 444 * @param reservation reservation to be saved 445 */ 446 protected void saveReservation(Element reservationEl, Reservation reservation) { 447 reservationEl.addAttribute("id", getId("reservation", reservation.getId())); 448 reservationEl.addAttribute("expired", reservation.isExpired() ? "true" : "false"); 449 if (reservation instanceof GroupReservation) { 450 GroupReservation gr = (GroupReservation)reservation; 451 reservationEl.addAttribute("type", "group"); 452 for (Long studentId: gr.getStudentIds()) 453 reservationEl.addElement("student").addAttribute("id", getId("student", studentId)); 454 if (gr.getReservationLimit() >= 0.0) 455 reservationEl.addAttribute("limit", String.valueOf(gr.getReservationLimit())); 456 } else if (reservation instanceof IndividualReservation) { 457 reservationEl.addAttribute("type", "individual"); 458 for (Long studentId: ((IndividualReservation)reservation).getStudentIds()) 459 reservationEl.addElement("student").addAttribute("id", getId("student", studentId)); 460 } else if (reservation instanceof CurriculumReservation) { 461 reservationEl.addAttribute("type", "curriculum"); 462 CurriculumReservation cr = (CurriculumReservation)reservation; 463 if (cr.getReservationLimit() >= 0.0) 464 reservationEl.addAttribute("limit", String.valueOf(cr.getReservationLimit())); 465 reservationEl.addAttribute("area", cr.getAcademicArea()); 466 for (String clasf: cr.getClassifications()) 467 reservationEl.addElement("classification").addAttribute("code", clasf); 468 for (String major: cr.getMajors()) 469 reservationEl.addElement("major").addAttribute("code", major); 470 } else if (reservation instanceof CourseReservation) { 471 reservationEl.addAttribute("type", "course"); 472 CourseReservation cr = (CourseReservation)reservation; 473 reservationEl.addAttribute("course", getId("course",cr.getCourse().getId())); 474 } else if (reservation instanceof DummyReservation) { 475 reservationEl.addAttribute("type", "dummy"); 476 } 477 for (Config config: reservation.getConfigs()) 478 reservationEl.addElement("config").addAttribute("id", getId("config", config.getId())); 479 for (Map.Entry<Subpart, Set<Section>> entry: reservation.getSections().entrySet()) { 480 for (Section section: entry.getValue()) { 481 reservationEl.addElement("section").addAttribute("id", getId("section", section.getId())); 482 } 483 } 484 } 485 486 /** 487 * Save students 488 * @param root document root 489 */ 490 protected void saveStudents(Element root) { 491 Element studentsEl = root.addElement("students"); 492 for (Student student : getModel().getStudents()) { 493 Element studentEl = studentsEl.addElement("student"); 494 saveStudent(studentEl, student); 495 for (Request request : student.getRequests()) { 496 saveRequest(studentEl, request); 497 } 498 } 499 } 500 501 /** 502 * Save student 503 * @param studentEl student element to be populated 504 * @param student student to be saved 505 */ 506 protected void saveStudent(Element studentEl, Student student) { 507 studentEl.addAttribute("id", getId("student", student.getId())); 508 if (iShowNames) { 509 if (student.getExternalId() != null && !student.getExternalId().isEmpty()) 510 studentEl.addAttribute("externalId", student.getExternalId()); 511 if (student.getName() != null && !student.getName().isEmpty()) 512 studentEl.addAttribute("name", student.getName()); 513 if (student.getStatus() != null && !student.getStatus().isEmpty()) 514 studentEl.addAttribute("status", student.getStatus()); 515 } 516 if (student.isDummy()) 517 studentEl.addAttribute("dummy", "true"); 518 if (iSaveStudentInfo) { 519 for (AcademicAreaCode aac : student.getAcademicAreaClasiffications()) { 520 Element aacEl = studentEl.addElement("classification"); 521 if (aac.getArea() != null) 522 aacEl.addAttribute("area", aac.getArea()); 523 if (aac.getCode() != null) 524 aacEl.addAttribute("code", aac.getCode()); 525 } 526 for (AcademicAreaCode aac : student.getMajors()) { 527 Element aacEl = studentEl.addElement("major"); 528 if (aac.getArea() != null) 529 aacEl.addAttribute("area", aac.getArea()); 530 if (aac.getCode() != null) 531 aacEl.addAttribute("code", aac.getCode()); 532 } 533 for (AcademicAreaCode aac : student.getMinors()) { 534 Element aacEl = studentEl.addElement("minor"); 535 if (aac.getArea() != null) 536 aacEl.addAttribute("area", aac.getArea()); 537 if (aac.getCode() != null) 538 aacEl.addAttribute("code", aac.getCode()); 539 } 540 } 541 } 542 543 /** 544 * Save request 545 * @param studentEl student element to be populated 546 * @param request request to be saved 547 */ 548 protected void saveRequest(Element studentEl, Request request) { 549 if (request instanceof FreeTimeRequest) { 550 saveFreeTimeRequest(studentEl.addElement("freeTime"), (FreeTimeRequest) request); 551 } else if (request instanceof CourseRequest) { 552 saveCourseRequest(studentEl.addElement("course"), (CourseRequest) request); 553 } 554 } 555 556 /** 557 * Save free time request 558 * @param requestEl request element to be populated 559 * @param request free time request to be saved 560 */ 561 protected void saveFreeTimeRequest(Element requestEl, FreeTimeRequest request) { 562 requestEl.addAttribute("id", getId("request", request.getId())); 563 requestEl.addAttribute("priority", String.valueOf(request.getPriority())); 564 if (request.isAlternative()) 565 requestEl.addAttribute("alternative", "true"); 566 if (request.getWeight() != 1.0) 567 requestEl.addAttribute("weight", sStudentWeightFormat.format(request.getWeight())); 568 TimeLocation tl = request.getTime(); 569 if (tl != null) { 570 requestEl.addAttribute("days", sDF[7].format(Long.parseLong(Integer.toBinaryString(tl 571 .getDayCode())))); 572 requestEl.addAttribute("start", String.valueOf(tl.getStartSlot())); 573 requestEl.addAttribute("length", String.valueOf(tl.getLength())); 574 if (iShowNames && tl.getDatePatternId() != null) 575 requestEl.addAttribute("datePattern", tl.getDatePatternId().toString()); 576 requestEl.addAttribute("dates", bitset2string(tl.getWeekCode())); 577 if (iShowNames) 578 requestEl.setText(tl.getLongName()); 579 } 580 if (iSaveInitial && request.getInitialAssignment() != null) { 581 requestEl.addElement("initial"); 582 } 583 if (iSaveCurrent && request.getAssignment() != null) { 584 requestEl.addElement("current"); 585 } 586 if (iSaveBest && request.getBestAssignment() != null) { 587 requestEl.addElement("best"); 588 } 589 } 590 591 /** 592 * Save course request 593 * @param requestEl request element to be populated 594 * @param request course request to be saved 595 */ 596 protected void saveCourseRequest(Element requestEl, CourseRequest request) { 597 requestEl.addAttribute("id", getId("request", request.getId())); 598 requestEl.addAttribute("priority", String.valueOf(request.getPriority())); 599 if (request.isAlternative()) 600 requestEl.addAttribute("alternative", "true"); 601 if (request.getWeight() != 1.0) 602 requestEl.addAttribute("weight", sStudentWeightFormat.format(request.getWeight())); 603 requestEl.addAttribute("waitlist", request.isWaitlist() ? "true" : "false"); 604 if (request.getTimeStamp() != null) 605 requestEl.addAttribute("timeStamp", request.getTimeStamp().toString()); 606 boolean first = true; 607 for (Course course : request.getCourses()) { 608 if (first) 609 requestEl.addAttribute("course", getId("course", course.getId())); 610 else 611 requestEl.addElement("alternative").addAttribute("course", getId("course", course.getId())); 612 first = false; 613 } 614 for (Choice choice : request.getWaitlistedChoices()) { 615 Element choiceEl = requestEl.addElement("waitlisted"); 616 choiceEl.addAttribute("offering", getId("offering", choice.getOffering().getId())); 617 choiceEl.setText(choice.getId()); 618 } 619 for (Choice choice : request.getSelectedChoices()) { 620 Element choiceEl = requestEl.addElement("selected"); 621 choiceEl.addAttribute("offering", getId("offering", choice.getOffering().getId())); 622 choiceEl.setText(choice.getId()); 623 } 624 if (iSaveInitial && request.getInitialAssignment() != null) { 625 saveEnrollment(requestEl.addElement("initial"), request.getInitialAssignment()); 626 } 627 if (iSaveCurrent && request.getAssignment() != null) { 628 saveEnrollment(requestEl.addElement("current"), request.getAssignment()); 629 } 630 if (iSaveBest && request.getBestAssignment() != null) { 631 saveEnrollment(requestEl.addElement("best"), request.getBestAssignment()); 632 } 633 } 634 635 /** 636 * Save enrollment 637 * @param assignmentEl assignment element to be populated 638 * @param enrollment enrollment to be saved 639 */ 640 protected void saveEnrollment(Element assignmentEl, Enrollment enrollment) { 641 if (enrollment.getReservation() != null) 642 assignmentEl.addAttribute("reservation", getId("reservation", enrollment.getReservation().getId())); 643 for (Section section : enrollment.getSections()) { 644 Element sectionEl = assignmentEl.addElement("section").addAttribute("id", 645 getId("section", section.getId())); 646 if (iShowNames) 647 sectionEl.setText(section.getName() + " " + 648 (section.getTime() == null ? " Arr Hrs" : " " + section.getTime().getLongName()) + 649 (section.getNrRooms() == 0 ? "" : " " + section.getPlacement().getRoomName(",")) + 650 (section.getChoice().getInstructorNames() == null ? "" : " " + section.getChoice().getInstructorNames())); 651 } 652 } 653 654 /** 655 * Save linked sections 656 * @param root document root 657 */ 658 protected void saveLinkedSections(Element root) { 659 Element constrainstEl = root.addElement("constraints"); 660 for (LinkedSections linkedSections: getModel().getLinkedSections()) { 661 Element linkEl = constrainstEl.addElement("linked-sections"); 662 for (Offering offering: linkedSections.getOfferings()) 663 for (Subpart subpart: linkedSections.getSubparts(offering)) 664 for (Section section: linkedSections.getSections(subpart)) 665 linkEl.addElement("section") 666 .addAttribute("offering", getId("offering", offering.getId())) 667 .addAttribute("id", getId("section", section.getId())); 668 } 669 } 670 671 /** 672 * Save travel times 673 * @param root document root 674 */ 675 protected void saveTravelTimes(Element root) { 676 if (getModel().getDistanceConflict() != null) { 677 Map<Long, Map<Long, Integer>> travelTimes = getModel().getDistanceConflict().getDistanceMetric().getTravelTimes(); 678 if (travelTimes != null) { 679 Element travelTimesEl = root.addElement("travel-times"); 680 for (Map.Entry<Long, Map<Long, Integer>> e1: travelTimes.entrySet()) 681 for (Map.Entry<Long, Integer> e2: e1.getValue().entrySet()) 682 travelTimesEl.addElement("travel-time") 683 .addAttribute("id1", getId("room", e1.getKey().toString())) 684 .addAttribute("id2", getId("room", e2.getKey().toString())) 685 .addAttribute("minutes", e2.getValue().toString()); 686 } 687 } 688 } 689 690}