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 1069)
@@ -15,407 +15,271 @@
 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 java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
 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.HTMLDocumentSpec;
 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.
+ * AutoQUEST. The result of parsing a file is a collection of event sequences and a GUI model
  * </p>
  * 
- * @author Fabian Glaser
+ * @author Fabian Glaser, Patrick Harms
  * @version 1.0
  * 
  */
-public class HTMLLogParser extends DefaultHandler {
+public class HTMLLogParser extends AbstractDefaultLogParser {
+    
+    /**
+     *
+     */
+    private Pattern htmlElementPattern =
+        Pattern.compile("(\\w+)(\\[(\\d+)\\]|\\(htmlId=([\\w-]+)\\))");
+
+    /* (non-Javadoc)
+     * @see de.ugoe.cs.autoquest.plugin.html.AbstractDefaultLogParser#handleGUIElement(java.lang.String, java.util.Map)
+     */
+    @Override
+    protected boolean handleGUIElement(String id, Map<String, String> parameters)
+        throws SAXException
+    {
+        HTMLGUIElementSpec specification = null;
+        
+        String parentId = parameters.get("parent");
+        IGUIElement parent = super.getGUIElementTree().find(parentId);
+
+        if (parameters.containsKey("host")) {
+            // this is a server specification
+            int port = 80;
+            String portStr = parameters.get(port);
+            
+            if (portStr != null) {
+                port = Integer.parseInt(portStr);
+            }
+            
+            specification = new HTMLServerSpec(parameters.get("host"), port);
+        }
+        else if (parameters.containsKey("path")) {
+            // this is a document specification
+            
+            if (parent != null) {
+                if (!(parent.getSpecification() instanceof HTMLServerSpec)) {
+                    throw new SAXException
+                        ("invalid log: parent GUI element of a document is not of type server");
+                }
+                
+                specification = new HTMLDocumentSpec
+                    ((HTMLServerSpec) parent.getSpecification(), parameters.get("path"),
+                     parameters.get("query"), parameters.get("title"));
+            }
+            else if (parentId == null) {
+                throw new SAXException("invalid log: a document has no parent id");
+            }
+        }
+        else if (parameters.containsKey("tagname")) {
+            String tagName = parameters.get("tagname");
+            
+            if (!tagNameMustBeConsidered(tagName)) {
+                return true;
+            }
+
+            if (parent != null) {
+                IGUIElement document = parent;
+                
+                while ((document != null) &&
+                       (!(document.getSpecification() instanceof HTMLDocumentSpec)))
+                {
+                    document = document.getParent();
+                }
+                
+                if (document == null) {
+                    throw new SAXException
+                        ("invalid log: parent hierarchy of a page element does not contain a " +
+                         "document");
+                }
+                
+                int index = -1;
+                String indexStr = parameters.get("index");
+
+                if ((indexStr != null) && (!"".equals(indexStr))) {
+                    index = Integer.parseInt(indexStr);
+                }
+
+                specification = new HTMLPageElementSpec
+                    ((HTMLDocumentSpec) document.getSpecification(), tagName,
+                     parameters.get("htmlid"), index);
+            }
+            else if (parentId == null) {
+                throw new SAXException("invalid log: a page element has no parent id");
+            }
+        }
+        else {
+            throw new SAXException("invalid log: unknown GUI element");
+        }
+
+        if (specification != null) {
+            super.getGUIElementTree().add(id, parentId, specification);
+            return true;
+        }
+        else {
+            return false;
+        }
+    }
+
+    /* (non-Javadoc)
+     * @see de.ugoe.cs.autoquest.plugin.html.AbstractDefaultLogParser#handleEvent(java.lang.String, java.util.Map)
+     */
+    @Override
+    protected boolean handleEvent(String type, Map<String, String> parameters) throws SAXException {
+        String targetId = parameters.get("target");
+        
+        if (targetId == null) {
+            String targetDocument = parameters.get("targetDocument");
+            String targetDOMPath = parameters.get("targetDOMPath");
+            
+            if ((targetDocument == null) || (targetDOMPath == null)) {
+                throw new SAXException("event has no target defined");
+            }
+            
+            targetId = determineTargetId(targetDocument, targetDOMPath);
+            
+            if (targetId == null) {
+                // the target id can not be determined yet
+                return false;
+            }
+        }
+        
+        IGUIElement target = super.getGUIElementTree().find(targetId);
+        
+        if (target == null) {
+            // event not processable yet
+            return false;
+        }
+
+        IEventType eventType =
+            HTMLEventTypeFactory.getInstance().getEventType(type, parameters, target);
+        
+        Event event = new Event(eventType, target);
+
+        String timestampStr = parameters.get("timestamp");
+        
+        if (timestampStr != null) {
+            event.setTimestamp(Long.parseLong(timestampStr));
+        }
+
+        ((HTMLGUIElement) event.getTarget()).markUsed();
+        
+        super.addToSequence(event);
+
+        return true;
+    }
+
     /**
      * <p>
-     * Constructor. Creates a new HTMLLogParser.
+     * TODO: comment
      * </p>
-     */
-    public HTMLLogParser() {
-        sequences = new LinkedList<List<Event>>();
+     *
+     * @param targetDocument
+     * @param targetDOMPath
+     * @return
+     */
+    private String determineTargetId(String targetDocument, String targetDOMPath)
+        throws SAXException
+    {
+        IGUIElement document = super.getGUIElementTree().find(targetDocument);
+        
+        if (document == null) {
+            return null;
+        }
+        
+        if (!(document.getSpecification() instanceof HTMLDocumentSpec)) {
+            throw new SAXException("an id that should refer to an HTML document refers to" +
+                                   "something else");
+        }
+        
+        GUIModel model = super.getGUIElementTree().getGUIModel();
+        IGUIElement child = document;
+        String[] pathElements = targetDOMPath.split("/");
+        int pathIndex = 0;
+        
+        HTMLPageElementSpec compareSpec;
+        String tagName;
+        int index;
+        String htmlId;
+        
+        while ((pathIndex < pathElements.length) && (child != null)) {
+            if ((pathElements[pathIndex] != null) && (!"".equals(pathElements[pathIndex]))) {           
+                Matcher matcher = htmlElementPattern.matcher(pathElements[pathIndex]);
+                if (!matcher.matches()) {
+                    throw new SAXException
+                        ("could not parse target DOM path element " + pathElements[pathIndex]);
+                }
+
+                tagName = matcher.group(1);
+                String indexStr = matcher.group(3);
+                htmlId = matcher.group(4);
+
+                index = -1;
+                if ((indexStr != null) && (!"".equals(indexStr))) {
+                    index = Integer.parseInt(indexStr);
+                }
+
+                compareSpec = new HTMLPageElementSpec
+                    ((HTMLDocumentSpec) document.getSpecification(), tagName, htmlId, index);
+
+                List<IGUIElement> children = model.getChildren(child);
+                child = null;
+
+                for (IGUIElement candidate : children) {
+                    if (compareSpec.getSimilarity(candidate.getSpecification())) {
+                        child = candidate;
+                        break;
+                    }
+                }
+            }
+            
+            pathIndex++;
+        }
+        
+        if (child != null) {
+            return super.getGUIElementTree().find(child);
+        }
+        else {
+            return null;
+        }
     }
 
     /**
      * <p>
-     * Collection of event sequences that is contained in the parsed log file.
+     * checks if tags with the provided name must be handled in the GUI model. As an example,
+     * it is not necessary to handle "head" tags and anything included in them. 
      * </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>
-     * 
+     *
+     * @param tagName
      * @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;
-    }
+    private boolean tagNameMustBeConsidered(String tagName) {
+        return
+            !"head".equals(tagName) && !"title".equals(tagName) && !"script".equals(tagName) &&
+            !"style".equals(tagName) && !"link".equals(tagName) && !"meta".equals(tagName) &&
+            !"iframe".equals(tagName) && !"input_hidden".equals(tagName) &&
+            !"option".equals(tagName) && !"tt".equals(tagName) && !"br".equals(tagName) &&
+            !"colgroup".equals(tagName) && !"col".equals(tagName);
+
+    }
+
 }
