Index: trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/HTMLLogParser.java
===================================================================
--- trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/HTMLLogParser.java	(revision 1064)
+++ trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/HTMLLogParser.java	(revision 1064)
@@ -0,0 +1,421 @@
+//   Copyright 2012 Georg-August-Universität Göttingen, Germany
+//
+//   Licensed under the Apache License, Version 2.0 (the "License");
+//   you may not use this file except in compliance with the License.
+//   You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+package de.ugoe.cs.autoquest.plugin.html;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import de.ugoe.cs.autoquest.eventcore.Event;
+import de.ugoe.cs.autoquest.eventcore.IEventType;
+import de.ugoe.cs.autoquest.eventcore.guimodel.GUIElementTree;
+import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModel;
+import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement;
+import de.ugoe.cs.autoquest.plugin.html.eventcore.HTMLEventTypeFactory;
+import de.ugoe.cs.autoquest.plugin.html.guimodel.HTMLGUIElement;
+import de.ugoe.cs.autoquest.plugin.html.guimodel.HTMLGUIElementSpec;
+import de.ugoe.cs.autoquest.plugin.html.guimodel.HTMLPageElementSpec;
+import de.ugoe.cs.autoquest.plugin.html.guimodel.HTMLPageSpec;
+import de.ugoe.cs.autoquest.plugin.html.guimodel.HTMLServerSpec;
+import de.ugoe.cs.util.console.Console;
+
+/**
+ * <p>
+ * This class provides the functionality to parse XML log files generated by the HTMLMonitor of
+ * autoquest. The result of parsing a file is a collection of event sequences.
+ * </p>
+ * 
+ * @author Fabian Glaser
+ * @version 1.0
+ * 
+ */
+public class HTMLLogParser extends DefaultHandler {
+    /**
+     * <p>
+     * Constructor. Creates a new HTMLLogParser.
+     * </p>
+     */
+    public HTMLLogParser() {
+        sequences = new LinkedList<List<Event>>();
+    }
+
+    /**
+     * <p>
+     * Collection of event sequences that is contained in the parsed log file.
+     * </p>
+     */
+    private Collection<List<Event>> sequences;
+
+    /**
+     * <p>
+     * Internal handle to the parsed GUI structure, stored in a GUIElementTree
+     * </p>
+     */
+    private GUIElementTree<String> currentGUIElementTree;
+
+    /**
+     * <p>
+     * Path of the GUI element currently being parsed.
+     * </p>
+     */
+    private String currentGUIElementPath;
+
+    /**
+     * <p>
+     * Path of the parent of the GUI element currently being parsed.
+     * </p>
+     */
+    private String currentParentPath;
+
+    /**
+     * <p>
+     * Source of the GUI element currently being parsed.
+     * </p>
+     */
+    private String currentEventSource;
+
+    /**
+     * <p>
+     * Timestamp of the event currently being parsed.
+     * </p>
+     */
+    private Long currentEventTimestamp;
+
+    /**
+     * <p>
+     * Internal handle to the parameters of the event currently being parsed.
+     * </p>
+     */
+    private Map<String, String> currentEventParameters;
+
+    /**
+     * <p>
+     * Internal handle to the parameters of the GUI element currently being parsed.
+     * </p>
+     */
+    private Map<String, String> currentGUIElementParameters;
+    /**
+     * <p>
+     * Internal handle to the sequence currently being parsed.
+     * </p>
+     */
+    private List<Event> currentSequence;
+
+    /**
+     * <p>
+     * Internal handle to type of the event currently being parsed.
+     * </p>
+     */
+    private String currentEventType;
+
+    /**
+     * <p>
+     * Class of the GUI element currently being parsed.
+     * </p>
+     */
+    private String currentGUIElementClass;
+
+    /**
+     * <p>
+     * Index of the GUI element currently being parsed.
+     * </p>
+     */
+    private String currentGUIElementIndex;
+
+    /**
+     * <p>
+     * internal handle to the GUI element of the previous event to be potentially reused for the
+     * current
+     * </p>
+     */
+    private IGUIElement lastGUIElement;
+
+    /**
+     * <p>
+     * internal handle to the server specification currently being used.
+     * </p>
+     */
+    private HTMLServerSpec currentServerSpec;
+
+    /**
+     * <p>
+     * Parses a log file written by the HTMLMonitor and creates a collection of event sequences.
+     * </p>
+     * 
+     * @param filename
+     *            name and path of the log file
+     */
+    public void parseFile(String filename) {
+        if (filename == null) {
+            throw new IllegalArgumentException("filename must not be null");
+        }
+
+        parseFile(new File(filename));
+    }
+
+    /**
+     * <p>
+     * Parses a log file written by the HTMLMonitor and creates a collection of event sequences.
+     * </p>
+     * 
+     * @param file
+     *            file to be parsed
+     */
+    public void parseFile(File file) {
+        if (file == null) {
+            throw new IllegalArgumentException("file must not be null");
+        }
+        SAXParserFactory spf = SAXParserFactory.newInstance();
+        spf.setValidating(true);
+        SAXParser saxParser = null;
+        InputSource inputSource = null;
+        try {
+            saxParser = spf.newSAXParser();
+            inputSource =
+                new InputSource(new InputStreamReader(new FileInputStream(file), "UTF-8"));
+        }
+        catch (UnsupportedEncodingException e) {
+            Console.printerr("Error parsing file " + file.getName());
+            Console.logException(e);
+            return;
+        }
+        catch (ParserConfigurationException e) {
+            Console.printerr("Error parsing file " + file.getName());
+            Console.logException(e);
+            return;
+        }
+        catch (SAXException e) {
+            Console.printerr("Error parsing file " + file.getName());
+            Console.logException(e);
+        }
+        catch (FileNotFoundException e) {
+            Console.printerr("Error parsing file " + file.getName());
+            Console.logException(e);
+        }
+        if (inputSource != null) {
+            inputSource.setSystemId("file://" + file.getAbsolutePath());
+            try {
+                if (saxParser == null) {
+                    throw new RuntimeException("SaxParser creation failed");
+                }
+                saxParser.parse(inputSource, this);
+            }
+            catch (SAXParseException e) {
+                Console.printerrln("Failure parsing file in line " + e.getLineNumber() +
+                    ", column " + e.getColumnNumber() + ".");
+                Console.logException(e);
+            }
+            catch (SAXException e) {
+                Console.printerr("Error parsing file " + file.getName());
+                Console.logException(e);
+                return;
+            }
+            catch (IOException e) {
+                Console.printerr("Error parsing file " + file.getName());
+                Console.logException(e);
+                return;
+            }
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String,
+     * java.lang.String, org.xml.sax.Attributes)
+     */
+    @Override
+    public void startElement(String uri, String localName, String qName, Attributes atts)
+        throws SAXException
+    {
+        if (qName.equals("session")) {
+            currentSequence = new LinkedList<Event>();
+            if (currentGUIElementTree == null)
+                currentGUIElementTree = new GUIElementTree<String>();
+        }
+        else if (qName.equals("component")) {
+            currentGUIElementPath = atts.getValue("path");
+            currentGUIElementParameters = new HashMap<String, String>();
+        }
+        else if (qName.equals("event")) {
+            currentEventType = atts.getValue("type");
+            currentEventParameters = new HashMap<String, String>();
+        }
+        else if (qName.equals("param")) {
+            String paramName = atts.getValue("name");
+            if (currentGUIElementPath != null) {
+                if ("parent".equals(paramName)) {
+                    currentParentPath = atts.getValue("value");
+                }
+                if ("class".equals(paramName)) {
+                    currentGUIElementClass = atts.getValue("value");
+                }
+                if ("index".equals(paramName)) {
+                    currentGUIElementIndex = atts.getValue("value");
+                }
+                currentGUIElementParameters.put(paramName, atts.getValue("value"));
+            }
+            else if (currentEventType != null) {
+                if ("target".equals(paramName)) {
+                    currentEventSource = atts.getValue("value");
+                }
+                if ("timestamp".equals(paramName)) {
+                    currentEventTimestamp = Long.parseLong(atts.getValue("value"));
+                }
+                currentEventParameters.put(paramName, atts.getValue("value"));
+            }
+            else {
+                throw new SAXException("param tag found where it should not be.");
+            }
+        }
+        else {
+            throw new SAXException("unknown tag found: " + qName);
+        }
+
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String,
+     * java.lang.String)
+     */
+    @Override
+    public void endElement(String uri, String localName, String qName) throws SAXException {
+        if (qName.equals("session")) {
+            if (currentSequence != null && !currentSequence.isEmpty()) {
+                sequences.add(currentSequence);
+            }
+            currentSequence = null;
+        }
+        else if (qName.equals("component") && currentGUIElementPath != null) {
+            HTMLGUIElementSpec guiElementSpec =
+                getGUIElementSpec(currentGUIElementClass, currentGUIElementParameters);
+            currentGUIElementTree.add(currentGUIElementPath, currentParentPath, guiElementSpec);
+
+            currentParentPath = null;
+            currentGUIElementPath = null;
+            currentGUIElementParameters = null;
+        }
+        else if (qName.equals("event")) {
+            IGUIElement currentGUIElement;
+            currentGUIElement = currentGUIElementTree.find(currentEventSource);
+
+            IEventType eventType =
+                HTMLEventTypeFactory.getInstance().getEventType(currentEventType,
+                                                                currentEventParameters,
+                                                                currentGUIElement);
+            Event event =
+                new Event(eventType, (currentGUIElement == null ? lastGUIElement
+                    : currentGUIElement));
+
+            event.setTimestamp(currentEventTimestamp);
+            HTMLGUIElement currentEventTarget = (HTMLGUIElement) event.getTarget();
+            currentEventTarget.markUsed();
+            currentSequence.add(event);
+
+            currentEventSource = null;
+            currentEventTimestamp = -1l;
+            currentEventParameters = null;
+            currentEventType = null;
+
+            if (currentGUIElement != null) {
+                lastGUIElement = currentGUIElement;
+            }
+
+            currentGUIElement = null;
+        }
+    }
+
+    /**
+     * <p>
+     * Returns a collection of event sequences that was obtained from parsing log files.
+     * </p>
+     * 
+     * @return
+     */
+    public Collection<List<Event>> getSequences() {
+        return sequences;
+    }
+
+    /**
+     * <p>
+     * Returns the GUI model that is obtained from parsing log files.
+     * </p>
+     * 
+     * @return GUIModel
+     */
+    public GUIModel getGuiModel() {
+        return currentGUIElementTree.getGUIModel();
+    }
+
+    /**
+     * Returns the HTMLGUIElementSpecification for a GUI Element described
+     * by its class name and its parameters.
+     * @param guiElementClass
+     * @param guiElementParameters
+     * @return
+     */
+    private HTMLGUIElementSpec getGUIElementSpec(String guiElementClass,
+                                                 Map<String, String> guiElementParameters)
+    {
+        HTMLGUIElementSpec specification = null;
+        if ("server".equals(guiElementClass)) {
+            // TODO: add correct port handling
+            specification = new HTMLServerSpec(guiElementParameters.get("htmlId"), 0);
+            currentServerSpec = (HTMLServerSpec) specification;
+        }
+
+        else {
+            String id = guiElementParameters.get("htmlId");
+            if (id == null) {
+                HTMLPageElementSpec parentSpec =
+                    (HTMLPageElementSpec) currentGUIElementTree.find(currentParentPath)
+                        .getSpecification();
+                id = parentSpec.getPage().getPagePath();
+            }
+
+            int index = -1;
+            String indexStr = guiElementParameters.get("index");
+
+            if ((indexStr != null) && (!"".equals(indexStr))) {
+                index = Integer.parseInt(indexStr);
+            }
+            String title = guiElementParameters.get("title");
+            HTMLPageSpec page = new HTMLPageSpec(currentServerSpec, id, title);
+            specification = new HTMLPageElementSpec(page, guiElementClass, id, index);
+        }
+
+        return specification;
+    }
+}
