    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    }