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