001 package ttsolver;
002
003 import ifs.model.*;
004 import ifs.util.*;
005 import ifs.solution.*;
006
007 import java.io.*;
008 import java.util.*;
009 import java.text.*;
010 import org.dom4j.*;
011 import org.dom4j.io.*;
012 import java.sql.Statement;
013
014 import ttsolver.constraint.*;
015 import ttsolver.model.*;
016 import edu.purdue.smas.timetable.data.*;
017 import edu.purdue.smas.timetable.data.pattern.*;
018 import edu.purdue.smas.timetable.util.Constants;
019 import edu.purdue.smas.timetable.util.Database;
020
021 /**
022 * This class saves the resultant solution in the XML format.
023 * <br><br>
024 * Parameters:
025 * <table border='1'><tr><th>Parameter</th><th>Type</th><th>Comment</th></tr>
026 * <tr><td>General.Output</td><td>{@link String}</td><td>Folder with the output solution in XML format (solution.xml)</td></tr>
027 * <tr><td>General.ConvertIds</td><td>{@link Boolean}</td><td>If true, ids are converted (to be able to make input data public)</td></tr>
028 * </table>
029 *
030 * @author <a href="mailto:muller@ktiml.mff.cuni.cz">Tomáš Müller</a>
031 * @version 1.0
032 */
033
034 public class TimetableXMLSaver extends TimetableSaver {
035 private static org.apache.log4j.Logger sLogger = org.apache.log4j.Logger.getLogger(TimetableXMLSaver.class);
036 private static DecimalFormat[] sDF = {new DecimalFormat(""),new DecimalFormat("0"),new DecimalFormat("00"),new DecimalFormat("000"),new DecimalFormat("0000"),new DecimalFormat("00000"),new DecimalFormat("000000"),new DecimalFormat("0000000")};
037 public static boolean DEBUG = false;
038
039 private TimetableModel iModel = null;
040 private Solution iSolution = null;
041 private boolean iConvertIds = false;
042 private File iOutputFolder = null;
043
044 public TimetableXMLSaver(Solution solution) {
045 super(solution);
046 iConvertIds = getModel().getProperties().getPropertyBoolean("General.ConvertIds",false);
047 iOutputFolder = new File(getModel().getProperties().getProperty("General.Output"));
048 iSolution = solution; iModel = (TimetableModel)iSolution.getModel();
049 }
050
051 public void setSolution(Solution solution) { iSolution = solution; iModel = (TimetableModel)iSolution.getModel(); }
052
053 private static String getId(Hashtable conversion, boolean convert, Object id) {
054 String newId = (String)conversion.get(id);
055 if (newId==null) {
056 newId = String.valueOf(conversion.size()+1);
057 conversion.put(id, newId);
058 }
059 return (convert?newId:id.toString());
060 }
061
062 public void save(PrintWriter out) throws Exception {
063 iOutputFolder.mkdirs();
064 File outFile = new File(iOutputFolder,"solution.xml");
065 sLogger.debug("Writting XML data to:"+outFile);
066
067 Document document = DocumentHelper.createDocument();
068 document.addComment("Large Lecture Room Timetabling");
069
070 if (!iModel.assignedVariables().isEmpty()) {
071 StringBuffer comments = new StringBuffer("Solution Info:\n");
072 Dictionary solutionInfo=(iSolution==null?iModel.getInfo():iSolution.getInfo());
073 for (Enumeration e=edu.purdue.smas.timetable.util.ToolBox.sortEnumeration(solutionInfo.keys());e.hasMoreElements();) {
074 String key = (String)e.nextElement();
075 Object value = solutionInfo.get(key);
076 comments.append(" "+key+": "+value+"\n");
077 }
078 document.addComment(comments.toString());
079 }
080
081 Element root = document.addElement("llrt");
082 root.addAttribute("semester", iModel.getProperties().getProperty("Data.Semester"));
083 root.addAttribute("year", iModel.getProperties().getProperty("Data.Year"));
084 root.addAttribute("version", iModel.getProperties().getProperty("Data.Version"));
085 root.addAttribute("created", String.valueOf(new Date()));
086 root.addAttribute("nrDays", String.valueOf(Constants.DAY_CODES.length));
087 root.addAttribute("halfHoursPerDay", String.valueOf(Constants.SLOTS_PER_DAY));
088
089 Element instructorsEl = root.addElement("instructors").addAttribute("count", String.valueOf(iModel.getInstructorConstraints().size()));
090 Element departmentsEl = root.addElement("departments");
091 HashSet depts = new HashSet();
092
093 Element roomsEl = root.addElement("rooms").addAttribute("count", String.valueOf(iModel.getRoomConstraints().size()));
094 Hashtable roomConv = new Hashtable();
095 Hashtable roomElements = new Hashtable();
096 for (Enumeration e=iModel.getRoomConstraints().elements();e.hasMoreElements();) {
097 RoomConstraint rc = (RoomConstraint)e.nextElement();
098 Element roomEl = roomsEl.addElement("room").addAttribute("id", getId(roomConv, iConvertIds, rc.getResourceId()));
099 roomElements.put(getId(roomConv, iConvertIds, rc.getResourceId()), roomEl);
100 }
101
102 Element classesEl = root.addElement("classes").addAttribute("count", String.valueOf(iModel.variables().size()));
103 Hashtable classConv = new Hashtable();
104 Hashtable courseConv = new Hashtable();
105 Hashtable deptConv = new Hashtable();
106 Hashtable instructorConv = new Hashtable();
107 HashSet filledRooms = new HashSet();
108 iModel.variables().addAll(iModel.ignoredClasses());
109 for (Enumeration e1=iModel.variables().elements();e1.hasMoreElements();) {
110 Lecture lecture = (Lecture)e1.nextElement();
111 Placement placement = (Placement)lecture.getAssignment();
112 Element classEl = classesEl.addElement("class").addAttribute("id", getId(classConv, iConvertIds, String.valueOf(lecture.getClassId())));
113 classEl.addAttribute("course", getId(courseConv, true, lecture.sameLectures()));
114 classEl.addAttribute("expectedCapacity", String.valueOf(lecture.countStudents()));
115 if (lecture.getDepartment()!=null) {
116 classEl.addAttribute("department", getId(deptConv, iConvertIds, lecture.getDepartment()));
117 depts.add(lecture.getDepartment());
118 }
119 if (lecture.getInstructorConstraint()!=null) {
120 Element instrEl = classEl.addElement("instructor").addAttribute("id", getId(instructorConv, iConvertIds, lecture.getInstructorConstraint().getResourceId()));
121 if (placement!=null) instrEl.addAttribute("solution","true");
122 }
123 for (Enumeration e2=lecture.roomLocations().elements();e2.hasMoreElements();) {
124 RoomLocation rl = (RoomLocation)e2.nextElement();
125 Element roomLocationEl = (Element)classEl.addElement("room");
126 roomLocationEl.addAttribute("id", getId(roomConv, iConvertIds, rl.getId()));
127 roomLocationEl.addAttribute("pref", String.valueOf(rl.getPreference()));
128 if (placement!=null && placement.getRoomLocation().equals(rl)) roomLocationEl.addAttribute("solution", "true");
129 if (filledRooms.add(rl)) {
130 Element roomEl = (Element)roomElements.get(rl.getId());
131 roomEl.addAttribute("capacity", String.valueOf(rl.getRoomSize()));
132 if (rl.getPosX()>0 || rl.getPosY()>0)
133 roomEl.addAttribute("location", rl.getPosX()+","+rl.getPosY());
134 }
135 }
136 for (Enumeration e2=lecture.timeLocations().elements();e2.hasMoreElements();) {
137 TimeLocation tl = (TimeLocation)e2.nextElement();
138 Element timeLocationEl = (Element)classEl.addElement("time");
139 timeLocationEl.addAttribute("days", sDF[7].format(Long.parseLong(Integer.toBinaryString(tl.getDayCode()))));
140 timeLocationEl.addAttribute("start", String.valueOf(tl.getStartSlot()));
141 timeLocationEl.addAttribute("length", String.valueOf(tl.getLength()));
142 timeLocationEl.addAttribute("pref", String.valueOf((int)tl.getNormalizedPreference()));
143 if (placement!=null && placement.getTimeLocation().equals(tl)) timeLocationEl.addAttribute("solution", "true");
144 }
145 }
146 classesEl.addAttribute("courses",String.valueOf(courseConv.size()));
147
148 Element grConstraintsEl = root.addElement("groupConstraints").addAttribute("count", String.valueOf(iModel.getGroupConstraints().size()));
149 Hashtable grConv = new Hashtable();
150 for (Enumeration e1=iModel.getGroupConstraints().elements();e1.hasMoreElements();) {
151 ttsolver.constraint.GroupConstraint gc = (ttsolver.constraint.GroupConstraint)e1.nextElement();
152 Element grEl = grConstraintsEl.addElement("constraint").addAttribute("id", getId(grConv, iConvertIds, String.valueOf(gc.getId())));
153 grEl.addAttribute("type", gc.getTypeStr());
154 grEl.addAttribute("pref", gc.getPrologPreference());
155 for (Enumeration e2=gc.variables().elements(); e2.hasMoreElements();) {
156 Lecture l = (Lecture)e2.nextElement();
157 grEl.addElement("class").addAttribute("id",getId(classConv, iConvertIds, String.valueOf(l.getId())));
158 }
159 }
160
161 Hashtable students = new Hashtable();
162 for (Enumeration e1=iModel.variables().elements();e1.hasMoreElements();) {
163 Lecture lecture = (Lecture)e1.nextElement();
164 for (Enumeration e2=lecture.students().elements();e2.hasMoreElements();) {
165 String student = (String)e2.nextElement();
166 Vector enrls = (Vector)students.get(student);
167 if (enrls==null) {
168 enrls = new Vector();
169 students.put(student, enrls);
170 }
171 enrls.add(getId(classConv, iConvertIds, String.valueOf(lecture.getId())));
172 }
173 }
174
175 Element studentsEl = root.addElement("students").addAttribute("count", String.valueOf(students.size()));
176 Hashtable studentConv = new Hashtable();
177 for (Enumeration e1=ToolBox.sortEnumeration(students.keys(), new IdComparator());e1.hasMoreElements();) {
178 String student = (String)e1.nextElement();
179 Element stEl = studentsEl.addElement("student").addAttribute("id", getId(studentConv, iConvertIds, student));
180 Vector lectures = (Vector)students.get(student);
181 Collections.sort(lectures);
182 for (Enumeration e2=lectures.elements();e2.hasMoreElements();) {
183 stEl.addElement("class").addAttribute("id", (String)e2.nextElement());
184 }
185 }
186
187 departmentsEl.addAttribute("count", String.valueOf(depts.size()));
188
189 FileOutputStream fos = new FileOutputStream(outFile);
190 (new XMLWriter(fos,OutputFormat.createPrettyPrint())).write(document);
191 fos.flush();fos.close();
192 }
193
194 private static class IdComparator implements Comparator {
195 public int compare(Object a, Object b) {
196 return Long.valueOf((String)a).compareTo(Long.valueOf((String)b));
197 }
198 }
199 }