Index: trunk/quest-plugin-mfc/src/main/java/de/ugoe/cs/quest/plugin/mfc/MFCLogParser.java
===================================================================
--- trunk/quest-plugin-mfc/src/main/java/de/ugoe/cs/quest/plugin/mfc/MFCLogParser.java	(revision 581)
+++ trunk/quest-plugin-mfc/src/main/java/de/ugoe/cs/quest/plugin/mfc/MFCLogParser.java	(revision 619)
@@ -1,2 +1,3 @@
+
 package de.ugoe.cs.quest.plugin.mfc;
 
@@ -8,6 +9,8 @@
 import java.security.InvalidParameterException;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
 import java.util.SortedMap;
 import java.util.TreeMap;
@@ -24,6 +27,9 @@
 
 import de.ugoe.cs.quest.eventcore.Event;
-import de.ugoe.cs.quest.plugin.mfc.eventcore.WindowTree;
+import de.ugoe.cs.quest.eventcore.guimodel.GUIModel;
 import de.ugoe.cs.quest.plugin.mfc.eventcore.WindowsMessage;
+import de.ugoe.cs.quest.plugin.mfc.eventcore.WindowsMessageType;
+import de.ugoe.cs.quest.plugin.mfc.guimodel.MFCGUIElement;
+import de.ugoe.cs.quest.plugin.mfc.guimodel.WindowTree;
 import de.ugoe.cs.util.StringTools;
 import de.ugoe.cs.util.console.Console;
@@ -31,9 +37,8 @@
 /**
  * <p>
- * This class provides functionality to parse XML log files generated by the
- * MFCUsageMonitor of EventBench. The result of parsing a file is a collection
- * of event sequences. It uses the {@link SequenceSplitter} and the
- * {@link EventGenerator} as well as custom defined {@link MessageHandler} for
- * the parsing.
+ * This class provides functionality to parse XML log files generated by the MFCUsageMonitor of
+ * EventBench. The result of parsing a file is a collection of event sequences. It uses the
+ * {@link SequenceSplitter} and the {@link EventGenerator} as well as custom defined
+ * {@link MessageHandler} for the parsing.
  * </p>
  * 
@@ -43,235 +48,302 @@
 public class MFCLogParser extends DefaultHandler {
 
-	/**
-	 * <p>
-	 * If a custom message handler is used, this field contains its handle.
-	 * Otherwise this field is {@code null}.
-	 * </p>
-	 */
-	private MessageHandler currentHandler;
-
-	/**
-	 * <p>
-	 * Handle to the message that is currently parsed.
-	 * </p>
-	 */
-	private WindowsMessage currentMessage;
-
-	/**
-	 * <p>
-	 * {@link SequenceSplitter} instance used by the {@link MFCLogParser}.
-	 * </p>
-	 */
-	private SequenceSplitter sequenceSplitter;
-
-	/**
-	 * <p>
-	 * Collection of event sequences that is contained in the log file, which is
-	 * parsed.
-	 * </p>
-	 */
-	private Collection<List<Event>> sequences;
-
-	/**
-	 * <p>
-	 * Debugging variable that allows the analysis which message type occurs how
-	 * often in the log file. Can be used to enhance the message filter.
-	 * </p>
-	 */
-	private SortedMap<Integer, Integer> typeCounter;
-
-	/**
-	 * <p>
-	 * Debugging variable that enables the counting of the occurrences of each
-	 * message. Used in combination with {@link #typeCounter}.
-	 * </p>
-	 */
-	private boolean countMessageOccurences;
-
-	/**
-	 * <p>
-	 * Constructor. Creates a new LogParser that does not count message
-	 * occurrences.
-	 * </p>
-	 */
-	public MFCLogParser() {
-		this(false);
-	}
-
-	/**
-	 * <p>
-	 * Constructor. Creates a new LogParser.
-	 * </p>
-	 * 
-	 * @param countMessageOccurences
-	 *            if true, the occurrences of each message type in the log is
-	 *            counted.
-	 */
-	public MFCLogParser(boolean countMessageOccurences) {
-		sequenceSplitter = new SequenceSplitter();
-		sequences = new LinkedList<List<Event>>();
-		currentHandler = null;
-		this.countMessageOccurences = countMessageOccurences;
-		if (countMessageOccurences) {
-			typeCounter = new TreeMap<Integer, Integer>();
-		}
-
-	}
-
-	/**
-	 * <p>
-	 * Returns the collection of event sequences that is obtained from parsing
-	 * log files.
-	 * </p>
-	 * 
-	 * @return collection of event sequences
-	 */
-	public Collection<List<Event>> getSequences() {
-		return sequences;
-	}
-
-	/*
-	 * (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")) {
-			Console.traceln("start of session");
-			sequenceSplitter = new SequenceSplitter();
-		} else if (qName.equals("msg")) {
-			String msgType = atts.getValue("type");
-			int msgInt = -1;
-			try {
-				msgInt = Integer.parseInt(msgType);
-
-				if (countMessageOccurences) {
-					Integer currentCount = typeCounter.get(msgInt);
-					if (currentCount == null) {
-						typeCounter.put(msgInt, 1);
-					} else {
-						typeCounter.put(msgInt, currentCount + 1);
-					}
-				}
-
-				if (msgInt == MessageDefs.WM_CREATE) {
-					currentHandler = new HandlerCreate();
-					currentHandler.onStartElement();
-				} else if (msgInt == MessageDefs.WM_DESTROY) {
-					currentHandler = new HandlerDestroy();
-					currentHandler.onStartElement();
-				} else if (msgInt == MessageDefs.WM_SETTEXT) {
-					currentHandler = new HandlerSetText();
-					currentHandler.onStartElement();
-				} else {
-					currentMessage = new WindowsMessage(msgInt);
-				}
-			} catch (NumberFormatException e) {
-				Console.printerrln("Invalid message type: type not a number");
-				e.printStackTrace();
-			}
-		} else if (qName.equals("param")) {
-			if (currentHandler != null) {
-				currentHandler.onParameter(atts.getValue("name"),
-						atts.getValue("value"));
-			} else {
-				currentMessage.addParameter(atts.getValue("name"),
-						atts.getValue("value"));
-			}
-		}
-	}
-
-	/*
-	 * (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("msg")) {
-			if (currentHandler != null) {
-				currentHandler.onEndElement();
-				currentHandler = null;
-			} else {
-				try {
-					currentMessage.setTarget(WindowTree.getInstance());
-					sequenceSplitter.addMessage(currentMessage);
-				} catch (InvalidParameterException e) {
-					Console.traceln(e.getMessage() + " WindowsMessage "
-							+ currentMessage + " ignored.");
-				}
-			}
-		} else if (qName.equals("session")) {
-			sequenceSplitter.endSession();
-			List<Event> seq = sequenceSplitter.getSequence();
-			if( seq!=null && !seq.isEmpty() ) {
-				sequences.add(seq);
-			}
-			Console.traceln("end of session");
-		}
-	}
-
-	/**
-	 * <p>
-	 * Parses a given log file created by the MFCMonitor and adds its contents
-	 * to the collection of event sequences.
-	 * </p>
-	 * 
-	 * @param filename
-	 *            name and path of the log file
-	 */
-	public void parseFile(String filename) {
-		if (filename == null) {
-			throw new InvalidParameterException("filename 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(filename)));//, "UTF-8"));
-		//} catch (UnsupportedEncodingException e) {
-		//	e.printStackTrace();
-		} catch (ParserConfigurationException e) {
-			e.printStackTrace();
-		} catch (SAXException e) {
-			e.printStackTrace();
-		} catch (FileNotFoundException e) {
-			e.printStackTrace();
-		}
-		if (inputSource != null) {
-			inputSource.setSystemId("file://"
-					+ new File(filename).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()
-						+ ".");
-				e.printStackTrace();
-			} catch (SAXException e) {
-				e.printStackTrace();
-			} catch (IOException e) {
-				e.printStackTrace();
-			}
-		}
-		if (countMessageOccurences) {
-			Console.println("Message statistics:");
-			Console.println(typeCounter.toString()
-					.replace(" ", StringTools.ENDLINE)
-					.replaceAll("[\\{\\}]", ""));
-		}
-	}
+    /**
+     * <p>
+     * If a custom message handler is used, this field contains its handle. Otherwise this field is
+     * {@code null}.
+     * </p>
+     */
+    private MessageHandler currentHandler;
+
+    /**
+     * <p>
+     * internal handle to the current window tree
+     * </p>
+     */
+    private WindowTree currentWindowTree;
+
+    /**
+     * <p>
+     * the type of the currently parsed message
+     * </p>
+     */
+    private WindowsMessageType currentMessageType;
+    
+    /**
+     * <p>
+     * the parameters of the currently parsed message
+     * </p>
+     */
+    private Map<String, Object> currentMessageParameters = new HashMap<String, Object>();
+    
+    /**
+     * <p>
+     * {@link SequenceSplitter} instance used by the {@link MFCLogParser}.
+     * </p>
+     */
+    private SequenceSplitter sequenceSplitter;
+
+    /**
+     * <p>
+     * Collection of message sequences that is contained in the log file, which is parsed.
+     * </p>
+     */
+    private Collection<List<Event>> sequences;
+
+    /**
+     * <p>
+     * Debugging variable that allows the analysis which message type occurs how often in the log
+     * file. Can be used to enhance the message filter.
+     * </p>
+     */
+    private SortedMap<WindowsMessageType, Integer> typeCounter;
+
+    /**
+     * <p>
+     * Debugging variable that enables the counting of the occurrences of each message. Used in
+     * combination with {@link #typeCounter}.
+     * </p>
+     */
+    private boolean countMessageOccurences;
+
+    /**
+     * <p>
+     * Constructor. Creates a new LogParser that does not count message occurrences.
+     * </p>
+     */
+    public MFCLogParser() {
+        this(false);
+    }
+
+    /**
+     * <p>
+     * Constructor. Creates a new LogParser.
+     * </p>
+     * 
+     * @param countMessageOccurences
+     *            if true, the occurrences of each message type in the log is counted.
+     */
+    public MFCLogParser(boolean countMessageOccurences) {
+        sequences = new LinkedList<List<Event>>();
+        currentHandler = null;
+        this.countMessageOccurences = countMessageOccurences;
+        if (countMessageOccurences) {
+            typeCounter = new TreeMap<WindowsMessageType, Integer>();
+        }
+    }
+
+    /**
+     * <p>
+     * Parses a log file written by the MFCMonitor 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 InvalidParameterException("filename must not be null");
+        }
+
+        parseFile(new File(filename));
+    }
+
+    /**
+     * <p>
+     * Parses a log file written by the MFCMonitor and creates a collection of event sequences.
+     * </p>
+     * 
+     * @param file
+     *            name and path of the log file
+     */
+    public void parseFile(File file) {
+        if (file == null) {
+            throw new InvalidParameterException("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) {
+            // e.printStackTrace();
+        }
+        catch (ParserConfigurationException e) {
+            // TODO handle Exception
+            e.printStackTrace();
+        }
+        catch (SAXException e) {
+            // TODO handle Exception
+            e.printStackTrace();
+        }
+        catch (FileNotFoundException e) {
+            // TODO handle Exception
+            e.printStackTrace();
+        }
+        
+        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() + ".");
+                e.printStackTrace();
+            }
+            catch (SAXException e) {
+                // TODO handle Exception
+                e.printStackTrace();
+            }
+            catch (IOException e) {
+                // TODO handle Exception
+                e.printStackTrace();
+            }
+        }
+        
+        if (countMessageOccurences) {
+            Console.println("Message statistics:");
+            Console.println
+                (typeCounter.toString().replace(" ", StringTools.ENDLINE).replaceAll("[\\{\\}]", ""));
+        }
+    }
+    
+    /**
+     * <p>
+     * Returns the collection of event sequences that is obtained from parsing log files.
+     * </p>
+     * 
+     * @return collection of event sequences
+     */
+    public Collection<List<Event>> getSequences() {
+        return sequences;
+    }
+
+    /**
+     * <p>
+     * Returns the gui model that is obtained from parsing log files.
+     * </p>
+     * 
+     * @return collection of event sequences
+     */
+    public GUIModel getGuiModel() {
+        return currentWindowTree.getGUIModel();
+    }
+
+    /*
+     * (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")) {
+            Console.traceln("start of session");
+            // in some logs, the session end may be marked in between the log. This is because
+            // of thread problems. So instead of creating a new GUI model, preserve it.
+            if (currentWindowTree == null) {
+                currentWindowTree = new WindowTree();
+            }
+            sequenceSplitter = new SequenceSplitter(currentWindowTree);
+        }
+        else if (qName.equals("msg")) {
+            currentMessageType = WindowsMessageType.parseMessageType(atts.getValue("type"));
+
+            if (countMessageOccurences) {
+                Integer currentCount = typeCounter.get(currentMessageType);
+                if (currentCount == null) {
+                    typeCounter.put(currentMessageType, 1);
+                }
+                else {
+                    typeCounter.put(currentMessageType, currentCount + 1);
+                }
+            }
+
+            if (currentMessageType == WindowsMessageType.WM_CREATE) {
+                currentHandler = new HandlerCreate(currentWindowTree);
+                currentHandler.onStartElement();
+            }
+            else if (currentMessageType == WindowsMessageType.WM_DESTROY) {
+                currentHandler = new HandlerDestroy(currentWindowTree);
+                currentHandler.onStartElement();
+            }
+            else if (currentMessageType == WindowsMessageType.WM_SETTEXT) {
+                currentHandler = new HandlerSetText(currentWindowTree);
+                currentHandler.onStartElement();
+            }
+        }
+        else if (qName.equals("param")) {
+            if (currentHandler != null) {
+                currentHandler.onParameter(atts.getValue("name"), atts.getValue("value"));
+            }
+            else {
+                // provide the parameters directly in the correct type
+                String paramName = atts.getValue("name");
+                if (("window.hwnd".equals(paramName)) ||
+                    ("source".equals(paramName)) ||
+                    ("LPARAM".equals(paramName)) ||
+                    ("WPARAM".equals(paramName)) ||
+                    ("scrollPos".equals(paramName)) ||
+                    ("scrollBarHandle".equals(paramName)))
+                {
+                    Long paramValue = Long.parseLong(atts.getValue("value"));
+                    currentMessageParameters.put(paramName, paramValue);
+                }
+                else {
+                    currentMessageParameters.put(paramName, atts.getValue("value"));
+                }
+            }
+        }
+    }
+
+    /*
+     * (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("msg")) {
+            if (currentHandler != null) {
+                currentHandler.onEndElement();
+                currentHandler = null;
+            }
+            else {
+                try {
+                    long hwnd = (Long) currentMessageParameters.get("window.hwnd");
+                    MFCGUIElement target = currentWindowTree.find(hwnd);
+                    
+                    WindowsMessage message = new WindowsMessage
+                        (currentMessageType, target, currentMessageParameters);
+                    
+                    sequenceSplitter.addMessage(message);
+                }
+                catch (InvalidParameterException e) {
+                    Console.traceln(e.getMessage() + " WindowsMessage " + currentMessageType +
+                                    " ignored.");
+                }
+            }
+        }
+        else if (qName.equals("session")) {
+            sequenceSplitter.endSession();
+            List<Event> seq = sequenceSplitter.getSequence();
+            if (seq != null && !seq.isEmpty()) {
+                sequences.add(seq);
+            }
+            Console.traceln("end of session");
+        }
+    }
+
 }
