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