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