001package org.cpsolver.coursett;
002
003import java.io.BufferedReader;
004import java.io.File;
005import java.io.FileReader;
006import java.io.StringReader;
007import java.util.ArrayList;
008import java.util.HashMap;
009import java.util.Iterator;
010import java.util.List;
011import java.util.Map;
012import java.util.TreeSet;
013
014
015import org.apache.log4j.BasicConfigurator;
016import org.cpsolver.coursett.model.Lecture;
017import org.cpsolver.coursett.model.Placement;
018import org.cpsolver.coursett.model.TimetableModel;
019import org.cpsolver.ifs.assignment.DefaultSingleAssignment;
020import org.cpsolver.ifs.solution.Solution;
021import org.cpsolver.ifs.util.CSVFile;
022import org.cpsolver.ifs.util.DataProperties;
023import org.cpsolver.ifs.util.Progress;
024import org.dom4j.Document;
025import org.dom4j.Element;
026import org.dom4j.io.SAXReader;
027
028/**
029 * Process all solutions (files solution.xml or output.csv) in all subfolders of
030 * the given folder and create a CSV (comma separated values text file) with
031 * solution infos of the found solutions.
032 * 
033 * @version CourseTT 1.3 (University Course Timetabling)<br>
034 *          Copyright (C) 2007 - 2014 Tomáš Müller<br>
035 *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
036 *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
037 * <br>
038 *          This library is free software; you can redistribute it and/or modify
039 *          it under the terms of the GNU Lesser General Public License as
040 *          published by the Free Software Foundation; either version 3 of the
041 *          License, or (at your option) any later version. <br>
042 * <br>
043 *          This library is distributed in the hope that it will be useful, but
044 *          WITHOUT ANY WARRANTY; without even the implied warranty of
045 *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
046 *          Lesser General Public License for more details. <br>
047 * <br>
048 *          You should have received a copy of the GNU Lesser General Public
049 *          License along with this library; if not see
050 *          <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
051 */
052public class GetInfo {
053
054    public static HashMap<String, String> getInfoOfASolution(File file) {
055        try {
056            DataProperties properties = new DataProperties();
057            properties.setProperty("General.Input", file.getPath());
058            TimetableXMLLoader loader = new TimetableXMLLoader(new TimetableModel(properties), new DefaultSingleAssignment<Lecture, Placement>());
059            loader.load();
060            File newOutputFile = new File(file.getParentFile(), "new-output.csv");
061            Test.saveOutputCSV(new Solution<Lecture, Placement>(loader.getModel(), loader.getAssignment()), newOutputFile);
062            Progress.removeInstance(loader.getModel());
063            System.out.println("  Reading " + newOutputFile + " ...");
064            HashMap<String, String> info = getInfo(newOutputFile);
065            File outputFile = new File(file.getParentFile(), "output.csv");
066            if (outputFile.exists()) {
067                System.out.println("  Reading " + outputFile + " ...");
068                HashMap<String, String> info2 = getInfo(outputFile);
069                if (info2.containsKey("000.002 Time [sec]"))
070                    info.put("000.002 Time [sec]", info2.get("000.002 Time [sec]"));
071            }
072            return info;
073        } catch (Exception e) {
074            System.err.println("Error reading info, message: " + e.getMessage());
075            e.printStackTrace();
076            return null;
077        }
078    }
079
080    public static HashMap<String, String> getInfo(String comment) {
081        try {
082            BufferedReader reader = new BufferedReader(new StringReader(comment));
083            String line = null;
084            HashMap<String, String> info = new HashMap<String, String>();
085            while ((line = reader.readLine()) != null) {
086                int idx = line.indexOf(':');
087                if (idx >= 0) {
088                    String key = line.substring(0, idx).trim();
089                    String value = line.substring(idx + 1).trim();
090                    if (value.indexOf('(') >= 0 && value.indexOf(')') >= 0) {
091                        value = value.substring(value.indexOf('(') + 1, value.indexOf(')'));
092                        if (value.indexOf('/') >= 0) {
093                            String bound = value.substring(value.indexOf('/') + 1);
094                            if (bound.indexOf("..") >= 0) {
095                                String min = bound.substring(0, bound.indexOf(".."));
096                                String max = bound.substring(bound.indexOf("..") + 2);
097                                info.put(key + " Min", min);
098                                info.put(key + " Max", max);
099                            } else {
100                                info.put(key + " Bound", bound);
101                            }
102                            value = value.substring(0, value.indexOf('/'));
103                        }
104                    }
105                    if (value.length() > 0)
106                        info.put(key, value);
107                }
108            }
109            reader.close();
110            return info;
111        } catch (Exception e) {
112            System.err.println("Error reading info, message: " + e.getMessage());
113            e.printStackTrace();
114            return null;
115        }
116    }
117
118    public static HashMap<String, String> getInfo(File outputFile) {
119        try {
120            BufferedReader reader = new BufferedReader(new FileReader(outputFile));
121            String line = null;
122            HashMap<String, String> info = new HashMap<String, String>();
123            while ((line = reader.readLine()) != null) {
124                int idx = line.indexOf(',');
125                if (idx >= 0) {
126                    String key = line.substring(0, idx).trim();
127                    String value = line.substring(idx + 1).trim();
128                    if (value.indexOf('(') >= 0 && value.indexOf(')') >= 0) {
129                        value = value.substring(value.indexOf('(') + 1, value.indexOf(')'));
130                        if (value.indexOf('/') >= 0) {
131                            String bound = value.substring(value.indexOf('/') + 1);
132                            if (bound.indexOf("..") >= 0) {
133                                String min = bound.substring(0, bound.indexOf(".."));
134                                String max = bound.substring(bound.indexOf("..") + 2);
135                                info.put(key + " Min", min);
136                                info.put(key + " Max", max);
137                            } else {
138                                info.put(key + " Bound", bound);
139                            }
140                            value = value.substring(0, value.indexOf('/'));
141                        }
142                    }
143                    if (value.length() > 0)
144                        info.put(key, value);
145                }
146            }
147            reader.close();
148            return info;
149        } catch (Exception e) {
150            System.err.println("Error reading info, message: " + e.getMessage());
151            e.printStackTrace();
152            return null;
153        }
154    }
155
156    public static HashMap<String, String> getInfo(Element root) {
157        try {
158            HashMap<String, String> info = new HashMap<String, String>();
159            for (Iterator<?> i = root.elementIterator("property"); i.hasNext();) {
160                Element property = (Element) i.next();
161                String key = property.attributeValue("name");
162                String value = property.getText();
163                if (key == null || value == null)
164                    continue;
165                if (value.indexOf('(') >= 0 && value.indexOf(')') >= 0) {
166                    value = value.substring(value.indexOf('(') + 1, value.indexOf(')'));
167                    if (value.indexOf('/') >= 0) {
168                        String bound = value.substring(value.indexOf('/') + 1);
169                        if (bound.indexOf("..") >= 0) {
170                            String min = bound.substring(0, bound.indexOf(".."));
171                            String max = bound.substring(bound.indexOf("..") + 2);
172                            info.put(key + " Min", min);
173                            info.put(key + " Max", max);
174                        } else {
175                            info.put(key + " Bound", bound);
176                        }
177                        value = value.substring(0, value.indexOf('/'));
178                    }
179                }
180                if (value.length() > 0)
181                    info.put(key, value);
182
183            }
184            return info;
185        } catch (Exception e) {
186            System.err.println("Error reading info, message: " + e.getMessage());
187            return null;
188        }
189    }
190
191    public static void getInfo(File folder, List<Info> infos, String prefix) {
192        File infoFile = new File(folder, "info.xml");
193        if (infoFile.exists()) {
194            System.out.println("Reading " + infoFile + " ...");
195            try {
196                Document document = (new SAXReader()).read(infoFile);
197                HashMap<String, String> info = getInfo(document.getRootElement());
198                if (info != null && !info.isEmpty()) {
199                    infos.add(new Info(prefix, info));
200                    return;
201                }
202            } catch (Exception e) {
203                System.err.println("Error reading file " + infoFile + ", message: " + e.getMessage());
204            }
205        }
206        File solutionFile = new File(folder, "solution.xml");
207        if (solutionFile.exists()) {
208            /*
209             * File newOutputFile = new File(folder, "new-output.csv"); if
210             * (newOutputFile.exists()) {
211             * System.out.println("Reading "+newOutputFile+" ..."); try {
212             * HashMap info = getInfo(newOutputFile); if (info!=null &&
213             * !info.isEmpty()) { infos.addElement(new Object[]{prefix,info});
214             * return; } } catch (Exception e) {
215             * System.err.println("Error reading file "
216             * +infoFile+", message: "+e.getMessage()); } }
217             */
218            System.out.println("Reading " + solutionFile + " ...");
219            try {
220                HashMap<String, String> info = getInfoOfASolution(solutionFile);
221                if (info != null && !info.isEmpty()) {
222                    infos.add(new Info(prefix, info));
223                    return;
224                }
225            } catch (Exception e) {
226                System.err.println("Error reading file " + infoFile + ", message: " + e.getMessage());
227            }
228        }
229        File outputFile = new File(folder, "output.csv");
230        if (outputFile.exists()) {
231            System.out.println("Reading " + outputFile + " ...");
232            try {
233                HashMap<String, String> info = getInfo(outputFile);
234                if (info != null && !info.isEmpty()) {
235                    infos.add(new Info(prefix, info));
236                    return;
237                }
238            } catch (Exception e) {
239                System.err.println("Error reading file " + infoFile + ", message: " + e.getMessage());
240            }
241        }
242    }
243
244    public static void getInfos(File folder, List<Info> infos, String prefix) {
245        System.out.println("Checking " + folder + " ...");
246        File[] files = folder.listFiles();
247        getInfo(folder, infos, (prefix == null ? "" : prefix));
248        for (int i = 0; i < files.length; i++)
249            if (files[i].isDirectory())
250                getInfos(files[i], infos, (prefix == null ? "" : prefix + "/") + files[i].getName());
251    }
252
253    public static void writeInfos(List<Info> infos, File file) {
254        try {
255            System.out.println("Writing " + file + " ...");
256            TreeSet<String> keys = new TreeSet<String>();
257            ArrayList<CSVFile.CSVField> headers = new ArrayList<CSVFile.CSVField>();
258            headers.add(new CSVFile.CSVField(""));
259            for (Info o : infos) {
260                keys.addAll(o.getInfo().keySet());
261                headers.add(new CSVFile.CSVField(o.getPrefix()));
262            }
263            CSVFile csvFile = new CSVFile();
264            csvFile.setHeader(headers);
265            for (String key : keys) {
266                ArrayList<CSVFile.CSVField> line = new ArrayList<CSVFile.CSVField>();
267                line.add(new CSVFile.CSVField(key));
268                for (Info o : infos) {
269                    Map<String, String> info = o.getInfo();
270                    String value = info.get(key);
271                    line.add(new CSVFile.CSVField(value == null ? "" : value));
272                }
273                csvFile.addLine(line);
274            }
275            csvFile.save(file);
276        } catch (Exception e) {
277            System.err.println("Error writing file " + file + ", message: " + e.getMessage());
278        }
279    }
280
281    public static void main(String[] args) {
282        try {
283            BasicConfigurator.configure();
284            File folder = new File(args[0]);
285            List<Info> infos = new ArrayList<Info>();
286            getInfos(folder, infos, null);
287            if (!infos.isEmpty())
288                writeInfos(infos, new File(folder, "info.csv"));
289        } catch (Exception e) {
290            e.printStackTrace();
291        }
292    }
293
294    public static class Info {
295        private String iPrefix;
296        private HashMap<String, String> iInfo;
297
298        public Info(String prefix, HashMap<String, String> info) {
299            iPrefix = prefix;
300            iInfo = info;
301        }
302
303        public String getPrefix() {
304            return iPrefix;
305        }
306
307        public Map<String, String> getInfo() {
308            return iInfo;
309        }
310    }
311}