Index: trunk/quest-plugin-mfc/src/main/java/de/ugoe/cs/quest/plugin/mfc/EventGenerator.java
===================================================================
--- trunk/quest-plugin-mfc/src/main/java/de/ugoe/cs/quest/plugin/mfc/EventGenerator.java	(revision 581)
+++ trunk/quest-plugin-mfc/src/main/java/de/ugoe/cs/quest/plugin/mfc/EventGenerator.java	(revision 619)
@@ -1,6 +1,8 @@
+
 package de.ugoe.cs.quest.plugin.mfc;
 
 import java.io.IOException;
 import java.security.InvalidParameterException;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -18,15 +20,19 @@
 
 import de.ugoe.cs.quest.eventcore.Event;
-import de.ugoe.cs.quest.plugin.mfc.eventcore.MFCEventTarget;
-import de.ugoe.cs.quest.plugin.mfc.eventcore.MFCEventType;
-import de.ugoe.cs.quest.plugin.mfc.eventcore.WindowTree;
-import de.ugoe.cs.quest.plugin.mfc.eventcore.WindowTreeNode;
+import de.ugoe.cs.quest.eventcore.IEventType;
+import de.ugoe.cs.quest.plugin.mfc.EventGenerationRule.Term;
+import de.ugoe.cs.quest.plugin.mfc.eventcore.MFCEvent;
+import de.ugoe.cs.quest.plugin.mfc.eventcore.MFCEventTypeFactory;
+import de.ugoe.cs.quest.plugin.mfc.eventcore.ReplayWindowsMessage;
 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.console.Console;
 
 /**
  * <p>
- * Translates sequences of windows messages into {@link WindowsEvent}s that can
- * be used by the EventBench core libraries.
+ * Translates sequences of windows messages into {@link WindowsEvent}s that can be used by the
+ * EventBench core libraries.
  * </p>
  * 
@@ -36,966 +42,1069 @@
 public class EventGenerator {
 
-	/**
-	 * <p>
-	 * Helper method that fetches the document node of an XML file.
-	 * </p>
-	 * 
-	 * @param filename
-	 *            name of the XML file
-	 * @return the document node
-	 */
-	private static Document getDocument(String filename) {
-		SAXBuilder builder = new SAXBuilder();
-		Document doc = null;
-
-		try {
-			doc = builder.build(filename);
-			rulesNamespace = Namespace.getNamespace("ul:rules");
-		} catch (JDOMException e) {
-			Console.printerrln("Invalid rules file.");
-			e.printStackTrace();
-		} catch (IOException e) {
-			Console.printerrln("Invalid rules file.");
-			e.printStackTrace();
-		}
-
-		return doc;
-	}
-
-	/**
-	 * <p>
-	 * Name and path of the XML files containing the rules.
-	 * </p>
-	 */
-	private String rulesFile;
-
-	/**
-	 * <p>
-	 * Iterator used for the current sequence.
-	 * </p>
-	 */
-	private ListIterator<WindowsMessage> sequenceIterator;
-
-	/**
-	 * <p>
-	 * Token that is currently being generated.
-	 * </p>
-	 */
-	private Event currentToken;
-	
-	/**
-	 * <p>
-	 * Event type of the current token. Stored as a member to be able to update it during the parsing of the idinfo tag.
-	 * </p>
-	 */
-	private MFCEventType currentType;
-
-	/**
-	 * <p>
-	 * Reference to the ul:rules namespace.
-	 * </p>
-	 */
-	private static Namespace rulesNamespace;
-
-	/**
-	 * <p>
-	 * The name of the rule that is currently being evaluated.
-	 * </p>
-	 */
-	private String currentRuleName;
-
-	/**
-	 * <p>
-	 * Internal message storage. Used to implement the
-	 * <code>{@literal <store>}</code> and <code>{@literal <storeSeq>}</code>
-	 * tags.
-	 * </p>
-	 */
-	private Map<String, Object> messageStorage;
-
-	/**
-	 * <p>
-	 * Creates a new EventGenerator. Sets "data/rules.xml" as default file for
-	 * the rules.
-	 * </p>
-	 */
-	public EventGenerator() {
-		rulesFile = "data/rules.xml";
-	}
-
-	/**
-	 * <p>
-	 * Tries to match the rules to the given sequence to generate an
-	 * {@link WindowsEvent}.
-	 * </p>
-	 * <p>
-	 * The rules are matched the order, in which they are defined in the XML
-	 * file. Therefore, the order of the rules in the file defines priorities,
-	 * when multiple rules could be matched to the same sequence.
-	 * </p>
-	 * 
-	 * @param sequence
-	 *            sequence of message for which an event will be generated
-	 * @return event that matches the messages; null, if no rule can be matched
-	 */
-	@SuppressWarnings("unchecked")
-	public Event generateEvent(List<WindowsMessage> sequence) {
-		Document rulesDoc = getDocument(rulesFile);
-		Element rulesRoot = rulesDoc.getRootElement();
-
-		List<Element> ruleElements = rulesRoot.getChildren("rule",
-				rulesNamespace);
-
-		boolean isMatch = false;
-
-		for (int ruleIndex = 0; ruleIndex < ruleElements.size() && !isMatch; ruleIndex++) {
-			Element currentRule = ruleElements.get(ruleIndex);
-			currentRuleName = currentRule.getAttributeValue("name");
-			currentType = new MFCEventType(currentRuleName);
-			currentToken = new Event(currentType);
-			
-			isMatch = true;
-			messageStorage = new HashMap<String, Object>();
-			sequenceIterator = sequence.listIterator();
-			List<Element> ruleChildrenMsg = currentRule.getChildren("msg",
-					rulesNamespace);
-
-			int i = 0;
-			while (isMatch && i < ruleChildrenMsg.size()) {
-				Element messageElement = ruleChildrenMsg.get(i);
-				if ("true".equals(messageElement.getAttributeValue("multiple"))) {
-					Element nextMessageElement = null;
-					if (i + 1 < ruleChildrenMsg.size()) {
-						nextMessageElement = ruleChildrenMsg.get(i + 1);
-					}
-					try {
-						isMatch = matchMultipleMessages(messageElement,
-								nextMessageElement);
-					} catch (InvalidParameterException e) {
-						Console.printerrln(e.getMessage());
-					}
-				} else {
-					try {
-						isMatch = matchSingleMessage(messageElement);
-					} catch (InvalidParameterException e) {
-						Console.printerrln(e.getMessage());
-					}
-				}
-				i++;
-			}
-			if (isMatch) {
-				List<Element> ruleChildren = currentRule.getChildren();
-				for (Element genMsgElement : ruleChildren) {
-					if (genMsgElement.getName().equals("genMsg")) {
-						try {
-							generateReplayMessage(genMsgElement);
-						} catch (InvalidParameterException e) {
-							Console.printerrln(e.getMessage());
-							// TODO currentToken.invalidateReplay();
-						}
-					} else if (genMsgElement.getName().equals("genMsgSeq")) {
-						try {
-							generateReplaySequence(genMsgElement);
-							// TODO currentToken.invalidateReplay();
-						} catch (InvalidParameterException e) {
-							Console.printerrln(e.getMessage());
-							// TODO currentToken.invalidateReplay();
-						}
-					}
-				}
-				Element idinfoElement = currentRule.getChild("idinfo",
-						rulesNamespace);
-				if (idinfoElement != null) {
-					// cannot be empty if document is valid
-					List<Element> valueElements = idinfoElement.getChildren();
-					currentType.setInfo(getTermValue(null,
-							valueElements.get(0)));
-				}
-				Console.traceln(currentToken.getType().toString() + " matched");
-			} else {
-				currentToken = null;
-			}
-		}
-		if (!isMatch) {
-			Console.traceln("no match found for sequence: "
-					+ sequence.toString());
-		}
-		return currentToken;
-	}
-
-	// ////////////////////////////////////////////////////////////
-	// Helper functions for matching of events, i.e., msg-nodes //
-	// ////////////////////////////////////////////////////////////
-
-	/**
-	 * <p>
-	 * Handles msg-nodes where multiple is not true, i.e., not a sequences.
-	 * </p>
-	 * 
-	 * @param messageElement
-	 *            {@link Element} representing the msg-node
-	 * @return true, if a match is found; false otherwise
-	 */
-	private boolean matchSingleMessage(Element messageElement) {
-		boolean isMatch = false;
-		WindowsMessage currentMessage = null;
-
-		int type = Integer.parseInt(messageElement.getAttributeValue("type"));
-
-		while (!isMatch && sequenceIterator.hasNext()) {
-			/*
-			 * traverses the messages from the current position forward till a
-			 * message with the correct type is found
-			 */
-			currentMessage = sequenceIterator.next();
-			if (type == currentMessage.getType()) {
-				// message with the correct type found
-				// eval child nodes for further matching/storing
-				isMatch = evalEqualRestrictions(currentMessage, messageElement);
-
-				// in case the message is a match, eval storage children
-				if (isMatch) {
-					handleStorage(messageElement, currentMessage);
-					currentToken.setTarget(new MFCEventTarget(currentMessage
-							.getXmlWindowDescription()));
-					// TODO currentToken.setTargetShort(currentMessage.getParentNames());
-				}
-			}
-		}
-
-		return isMatch;
-	}
-
-	/**
-	 * <p>
-	 * Handles msg-nodes where multiple is true, i.e., sequences. Requires
-	 * knowledge about the next msg-node to determine the end of the sequence.
-	 * </p>
-	 * 
-	 * @param messageElement
-	 *            {@link Element} representing the msg-node
-	 * @param nextMessageElement
-	 *            {@link Element} representing the next msg-node; {@code null}
-	 *            if the current node is the last one
-	 * @return true, if a sequence is matched; false otherwise
-	 */
-	private boolean matchMultipleMessages(Element messageElement,
-			Element nextMessageElement) {
-		boolean isMatch = false;
-		boolean isCurrentMatch = false;
-		boolean nextMatchFound = false;
-		WindowsMessage currentMessage = null;
-		WindowsMessage nextMessage = null;
-
-		int type = Integer.parseInt(messageElement.getAttributeValue("type"));
-
-		int nextType = -1;
-		if (nextMessageElement != null) {
-			nextType = Integer.parseInt(nextMessageElement
-					.getAttributeValue("type"));
-		}
-
-		while (!nextMatchFound && sequenceIterator.hasNext()) {
-			currentMessage = sequenceIterator.next();
-			if (type == currentMessage.getType()) {
-				isCurrentMatch = evalEqualRestrictions(currentMessage,
-						messageElement);
-				isMatch = isMatch || isCurrentMatch;
-
-				if (isCurrentMatch) {
-					handleStorage(messageElement, currentMessage);
-					currentToken.setTarget(new MFCEventTarget(currentMessage
-							.getXmlWindowDescription()));
-					// TODO currentToken.setTargetShort(currentMessage.getParentNames());
-				}
-			}
-			if (nextMessageElement != null && isMatch) {
-				// peek next message to check if the sequence ends and the next
-				// match is found
-				if (!sequenceIterator.hasNext()) {
-					return false; // sequence is over, but not all messages are
-									// found
-				}
-				nextMessage = sequenceIterator.next();
-				sequenceIterator.previous();
-
-				if (nextType == nextMessage.getType()) {
-					nextMatchFound = evalEqualRestrictions(nextMessage,
-							nextMessageElement);
-				}
-
-			}
-		}
-
-		return isMatch;
-	}
-
-	/**
-	 * <p>
-	 * Handles equals-nodes.
-	 * </p>
-	 * 
-	 * @param currentMessage
-	 *            {@link Element} representing the msg-node the equals-node
-	 *            belongs to
-	 * @param messageElement
-	 *            {@link Element} representing the equals-node to be evaluated
-	 * @return true, if constraint is fulfilled; false otherwise
-	 */
-	@SuppressWarnings("unchecked")
-	private boolean evalEqualRestrictions(WindowsMessage currentMessage,
-			Element messageElement) {
-		boolean isMatch = true;
-		for (Element childElement : (List<Element>) messageElement.getChildren(
-				"equals", rulesNamespace)) {
-			List<Element> termElements = childElement.getChildren();
-			// the size 2 of termElements is guaranteed by the XML schema
-			String value1 = getTermValue(currentMessage, termElements.get(0));
-			String value2 = getTermValue(currentMessage, termElements.get(1));
-			if (value1 == null || value2 == null) {
-				isMatch = false;
-			} else {
-				isMatch = isMatch && value1.equals(value2);
-			}
-		}
-		for (Element childElement : (List<Element>) messageElement.getChildren(
-				"equalsSeq", rulesNamespace)) {
-			List<Element> termElements = childElement.getChildren();
-			List<String> values1 = getTermValueSeq(termElements.get(0));
-			List<String> values2 = getTermValueSeq(termElements.get(0));
-			if (values1 == null || values2 == null) {
-				isMatch = false;
-			} else {
-				isMatch = isMatch && values1.equals(values2);
-			}
-		}
-		return isMatch;
-	}
-
-	/**
-	 * <p>
-	 * Handles store-nodes and storeSeq-nodes.
-	 * </p>
-	 * 
-	 * @param messageElement
-	 *            {@link Element} representing the msg-node that is currently
-	 *            being evaluated
-	 * @param currentMessage
-	 *            current message in the message sequence that is matched; this
-	 *            is the message that is stored
-	 */
-	@SuppressWarnings("unchecked")
-	private void handleStorage(Element messageElement,
-			WindowsMessage currentMessage) {
-		for (Element childElement : (List<Element>) messageElement.getChildren(
-				"store", rulesNamespace)) {
-			String identifier = childElement.getAttributeValue("var");
-			messageStorage.put(identifier, currentMessage);
-			resolveHwnd(currentMessage, childElement);
-		}
-		for (Element childElement : (List<Element>) messageElement.getChildren(
-				"storeSeq", rulesNamespace)) {
-			String identifier = childElement.getAttributeValue("varSeq");
-			Object tmp = messageStorage.get(identifier);
-			List<WindowsMessage> storedSequence;
-			if (tmp == null || tmp instanceof WindowsMessage) {
-				storedSequence = new LinkedList<WindowsMessage>();
-				storedSequence.add(currentMessage);
-				messageStorage.put(identifier, storedSequence);
-			} else if (tmp instanceof List<?>) {
-				storedSequence = (List<WindowsMessage>) tmp;
-				storedSequence.add(currentMessage);
-				messageStorage.put(identifier, storedSequence);
-			}
-			resolveHwnd(currentMessage, childElement);
-		}
-	}
-
-	/**
-	 * <p>
-	 * Resolves a parameter that contains a HWND of a message to the target
-	 * string of the HWND and stores it.
-	 * </p>
-	 * 
-	 * @param currentMessage
-	 *            message whose HWND is resolved
-	 * @param childElement
-	 *            child element of the store node that represents the resolve
-	 */
-	@SuppressWarnings("unchecked")
-	private void resolveHwnd(WindowsMessage currentMessage, Element childElement) {
-		List<Element> resolveElements = childElement.getChildren("resolveHwnd",
-				rulesNamespace);
-		for (Element resolveElement : resolveElements) {
-			String param = resolveElement.getAttributeValue("param");
-			String storeParam = resolveElement.getAttributeValue("storeParam");
-			int paramHwnd = Integer
-					.parseInt(currentMessage.getParameter(param));
-			WindowTreeNode node = WindowTree.getInstance().find(paramHwnd);
-			if (node != null) {
-				currentMessage.addParameter(storeParam,
-						node.xmlRepresentation());
-			}
-		}
-	}
-
-	// /////////////////////////////////////////////////////
-	// Helper functions for generating the replay, i.e.,
-	// parsing of genMsg und genMsgSeq-nodes
-	// /////////////////////////////////////////////////////
-
-	/**
-	 * <p>
-	 * Handles genMsg-nodes and adds the replay to the {@link Event} that is
-	 * generated.
-	 * </p>
-	 * 
-	 * @param genMsgElement
-	 *            {@link Element} representing the genMsg-node
-	 */
-	@SuppressWarnings("unchecked")
-	private void generateReplayMessage(Element genMsgElement) {
-		List<Element> genMsgChildren = genMsgElement.getChildren();
-		WindowsMessage generatedMessage = null;
-		if (genMsgChildren.size() == 1) { // replay stored message without
-											// change
-			String obj = genMsgChildren.get(0).getAttributeValue("obj");
-			generatedMessage = getStoredMessageVariable(null, obj);
-		} else { // generate message according to the rule
-			for (Element genMsgChild : genMsgChildren) {
-				Element termElement = (Element) genMsgChild.getChildren()
-						.get(0);
-				if (genMsgChild.getName().equals("type")) {
-					try {
-						int msgType = Integer.parseInt(getTermValue(null,
-								termElement));
-						generatedMessage = new WindowsMessage(msgType);
-					} catch (NumberFormatException e) {
-						throw new InvalidParameterException(
-								"Failure generating replay sequence for rule "
-										+ currentRuleName
-										+ ": Defined type is not an integer.");
-					}
-				} else if (genMsgChild.getName().equals("target")) {
-					String targetString = getTermValue(null, termElement);
-					generatedMessage.setXmlWindowDescription(targetString);
-				} else if (genMsgChild.getName().equals("LPARAM")) {
-					String paramValueStr = getTermValue(null, termElement);
-					long paramValue = 0;
-					Element loword = genMsgChild.getChild("LOWORD",
-							rulesNamespace);
-					if (loword != null) {
-						paramValue = loHiWord(genMsgChild);
-						generatedMessage.setLPARAM(paramValue);
-					} else {
-						try {
-							paramValue = Integer.parseInt(paramValueStr);
-							generatedMessage.setLPARAM(paramValue);
-						} catch (NumberFormatException e) {
-							generatedMessage
-									.setLPARAMasWindowDesc(paramValueStr);
-						}
-					}
-				} else if (genMsgChild.getName().equals("WPARAM")) {
-					String paramValueStr = getTermValue(null, termElement);
-					long paramValue = 0;
-					Element loword = genMsgChild.getChild("LOWORD",
-							rulesNamespace);
-					if (loword != null) {
-						paramValue = loHiWord(genMsgChild);
-						generatedMessage.setWPARAM(paramValue);
-					} else {
-						try {
-							paramValue = Integer.parseInt(paramValueStr);
-							generatedMessage.setWPARAM(paramValue);
-						} catch (NumberFormatException e) {
-							generatedMessage
-									.setWPARAMasWindowDesc(paramValueStr);
-						}
-					}
-				}
-			}
-		}
-		if (generatedMessage != null) {
-			int delay = Integer.parseInt(genMsgElement
-					.getAttributeValue("delay"));
-			generatedMessage.setDelay(delay);
-		} else {
-			// TODO currentToken.invalidateReplay();
-		}
-		currentToken.addReplayable(generatedMessage);
-	}
-
-	/**
-	 * Handles genMsgSeq-nodes and adds the replay to the {@link Event} that is
-	 * generated.</p>
-	 * 
-	 * @param genMsgElement
-	 *            {@link Element} representing the genMsgSeq-node.
-	 */
-	@SuppressWarnings("unchecked")
-	private void generateReplaySequence(Element genMsgElement) {
-		List<Element> genMsgSeqChildren = genMsgElement.getChildren();
-		List<WindowsMessage> generatedMessageSeq = new LinkedList<WindowsMessage>();
-		if (genMsgSeqChildren.size() == 1) {
-			String obj = genMsgSeqChildren.get(0).getAttributeValue("seqObj");
-			generatedMessageSeq = getStoredSeqVariable(obj);
-		} else {
-			boolean msgsGenerated = false;
-			int constMsgType = 0;
-			for (Element genMsgSeqChild : genMsgSeqChildren) {
-				Element termElement = (Element) genMsgSeqChild.getChildren()
-						.get(0);
-				if (genMsgSeqChild.getName().equals("type")) {
-					// note: cannot easily be extracted because of mulitple
-					// return values
-					if (termElement.getName().equals("seqValue")) {
-						String obj = termElement.getAttributeValue("seqObj");
-						List<WindowsMessage> seqVar = getStoredSeqVariable(obj);
-						for (WindowsMessage msg : seqVar) {
-							generatedMessageSeq.add(new WindowsMessage(msg
-									.getType()));
-						}
-						msgsGenerated = true;
-					} else { // constValue type
-						constMsgType = Integer.parseInt(getTermValue(null,
-								termElement));
-					}
-				} else if (genMsgSeqChild.getName().equals("target")) {
-					msgsGenerated = createSequenceTarget(generatedMessageSeq,
-							msgsGenerated, constMsgType, termElement);
-				} else if (genMsgSeqChild.getName().equals("LPARAM")) {
-					msgsGenerated = createSequenceLParam(generatedMessageSeq,
-							msgsGenerated, constMsgType, termElement);
-				} else if (genMsgSeqChild.getName().equals("WPARAM")) {
-					msgsGenerated = createSequenceWParam(generatedMessageSeq,
-							msgsGenerated, constMsgType, termElement);
-				}
-			}
-		}
-		currentToken.addReplayableSequence(generatedMessageSeq);
-	}
-
-	/**
-	 * <p>
-	 * Creates the targets for replay sequences generated with genMsgSeq-nodes.
-	 * </p>
-	 * 
-	 * @param generatedMessageSeq
-	 *            list of the messages that is being generated
-	 * @param msgsGenerated
-	 *            boolean stating if the list of messages is already generated
-	 *            or if the generation has to be handles by this method
-	 * @param constMsgType
-	 *            a constant message type that is used for message generation,
-	 *            in case the list of message is generated by this method
-	 * @param termElement
-	 *            {@link Element} representing the term-node describing the
-	 *            target
-	 * @return true, if the list of message is generated after calling this
-	 *         method; false otherwise
-	 * @throws NoSuchElementException
-	 *             thrown if the seqVar referred to in the termElement contains
-	 *             a different number of messages than is contained in
-	 *             messageSeq
-	 */
-	private boolean createSequenceTarget(
-			List<WindowsMessage> generatedMessageSeq, boolean msgsGenerated,
-			int constMsgType, Element termElement)
-			throws NoSuchElementException {
-		Iterator<WindowsMessage> seqIterator = generatedMessageSeq.iterator();
-		if (termElement.getName().equals("seqValue")) {
-			String obj = termElement.getAttributeValue("seqObj");
-			List<WindowsMessage> seqVar = getStoredSeqVariable(obj);
-			if (msgsGenerated && seqVar.size() != generatedMessageSeq.size()) {
-				throw new InvalidParameterException(
-						"Failure generating replay sequence for rule "
-								+ currentRuleName
-								+ ": One or more of the sequence variables used to generate a sequence have different lenghts.");
-			}
-			for (WindowsMessage msg : seqVar) {
-				WindowsMessage currentSeqMsg = getCurrentSeqMsg(
-						generatedMessageSeq, msgsGenerated, constMsgType,
-						seqIterator);
-				String targetString = msg.getParameter(termElement
-						.getAttributeValue("param"));
-				currentSeqMsg.setXmlWindowDescription(targetString);
-			}
-			msgsGenerated = true;
-		} else { // const value
-			throw new AssertionError("target must be a sequence variable!");
-			/*
-			 * If target would not be a variable, the message-elements could not
-			 * yet be created and the whole sequence might be broken. If this is
-			 * to be changed, createSequenceLParam and createSequenceWParam need
-			 * to be addepted, too.
-			 */
-		}
-		return msgsGenerated;
-	}
-
-	/**
-	 * <p>
-	 * Creates the LPARAMs for replay sequences generated with genMsgSeq-nodes.
-	 * </p>
-	 * 
-	 * @param generatedMessageSeq
-	 *            list of the messages that is being generated
-	 * @param msgsGenerated
-	 *            boolean stating if the list of messages is already generated
-	 *            or if the generation has to be handles by this method
-	 * @param constMsgType
-	 *            a constant message type that is used for message generation,
-	 *            in case the list of message is generated by this method
-	 * @param termElement
-	 *            {@link Element} representing the term-node describing the
-	 *            LPARAM
-	 * @return true, if the list of message is generated after calling this
-	 *         method; false otherwise
-	 * @throws NoSuchElementException
-	 *             thrown if the seqVar referred to in the termElement contains
-	 *             a different number of messages than is contained in
-	 *             messageSeq
-	 */
-	private boolean createSequenceLParam(
-			List<WindowsMessage> generatedMessageSeq, boolean msgsGenerated,
-			int constMsgType, Element termElement)
-			throws NoSuchElementException {
-		Iterator<WindowsMessage> seqIterator = generatedMessageSeq.iterator();
-		if (termElement.getName().equals("seqValue")) {
-			String obj = termElement.getAttributeValue("seqObj");
-			List<WindowsMessage> seqVar = getStoredSeqVariable(obj);
-			if (msgsGenerated && seqVar.size() != generatedMessageSeq.size()) {
-				throw new InvalidParameterException(
-						"Failure generating replay sequence for rule "
-								+ currentRuleName
-								+ ": One or more of the sequence variables used to generate a sequence have different lenghts.");
-			}
-			for (WindowsMessage msg : seqVar) {
-				WindowsMessage currentSeqMsg = getCurrentSeqMsg(
-						generatedMessageSeq, msgsGenerated, constMsgType,
-						seqIterator);
-				String paramValueStr = msg.getParameter(termElement
-						.getAttributeValue("param"));
-				int paramValue = 0;
-				try {
-					paramValue = Integer.parseInt(paramValueStr);
-					currentSeqMsg.setLPARAM(paramValue);
-				} catch (NumberFormatException e) {
-					currentSeqMsg.setLPARAMasWindowDesc(paramValueStr);
-				}
-			}
-			if (seqIterator.hasNext()) {
-				// the first seq-var has a different number of elements than the
-				// current one
-				throw new NoSuchElementException();
-			}
-			msgsGenerated = true;
-		} else { // const value
-			int paramValue = Integer.parseInt(getTermValue(null, termElement));
-			while (seqIterator.hasNext()) {
-				seqIterator.next().setLPARAM(paramValue);
-			}
-		}
-		return msgsGenerated;
-	}
-
-	/**
-	 * <p>
-	 * Creates the WPARAMs for replay sequences generated with genMsgSeq-nodes.
-	 * </p>
-	 * 
-	 * @param generatedMessageSeq
-	 *            list of the messages that is being generated
-	 * @param msgsGenerated
-	 *            boolean stating if the list of messages is already generated
-	 *            or if the generation has to be handles by this method
-	 * @param constMsgType
-	 *            a constant message type that is used for message generation,
-	 *            in case the list of message is generated by this method
-	 * @param termElement
-	 *            {@link Element} representing the term-node describing the
-	 *            WPARAM
-	 * @return true, if the list of message is generated after calling this
-	 *         method; false otherwise
-	 * @throws NoSuchElementException
-	 *             thrown if the seqVar referred to in the termElement contains
-	 *             a different number of messages than is contained in
-	 *             messageSeq
-	 */
-	private boolean createSequenceWParam(
-			List<WindowsMessage> generatedMessageSeq, boolean msgsGenerated,
-			int constMsgType, Element termElement)
-			throws NoSuchElementException {
-		Iterator<WindowsMessage> seqIterator = generatedMessageSeq.iterator();
-		if (termElement.getName().equals("seqValue")) {
-			String obj = termElement.getAttributeValue("seqObj");
-			List<WindowsMessage> seqVar = getStoredSeqVariable(obj);
-			if (msgsGenerated && seqVar.size() != generatedMessageSeq.size()) {
-				throw new InvalidParameterException(
-						"Failure generating replay sequence for rule "
-								+ currentRuleName
-								+ ": One or more of the sequence variables used to generate a sequence have different lenghts.");
-			}
-			for (WindowsMessage msg : seqVar) {
-				WindowsMessage currentSeqMsg = getCurrentSeqMsg(
-						generatedMessageSeq, msgsGenerated, constMsgType,
-						seqIterator);
-				String paramValueStr = msg.getParameter(termElement
-						.getAttributeValue("param"));
-				int paramValue = 0;
-				try {
-					paramValue = Integer.parseInt(paramValueStr);
-					currentSeqMsg.setWPARAM(paramValue);
-				} catch (NumberFormatException e) {
-					currentSeqMsg.setWPARAMasWindowDesc(paramValueStr);
-				}
-			}
-			if (seqIterator.hasNext()) {
-				// the first seq-var has a different number of elements than the
-				// current one
-				throw new NoSuchElementException();
-			}
-			msgsGenerated = true;
-		} else { // const value
-			int paramValue = Integer.parseInt(getTermValue(null, termElement));
-			while (seqIterator.hasNext()) {
-				seqIterator.next().setWPARAM(paramValue);
-			}
-		}
-		return msgsGenerated;
-	}
-
-	/**
-	 * <p>
-	 * If a message sequence is already generated, i.e., msgsGenerated is true,
-	 * the seqIterator is used to iterate through these messages and return the
-	 * current one. If the message sequence is not yet generated, i.e.,
-	 * msgsGenerated is false, the message sequence is generated on the fly
-	 * during each call of this message and the newly generated messages are
-	 * returned.
-	 * </p>
-	 * 
-	 * @param generatedMessageSeq
-	 *            message sequence
-	 * @param msgsGenerated
-	 *            indicates if generatedMessageSeq is already generated or has
-	 *            to be generated on the fly by this method
-	 * @param constMsgType
-	 *            type of the message to be used for message generation
-	 * @param seqIterator
-	 *            iterates through an already generated message sequence; must
-	 *            not be {@code null}, if msgsGenerated is true
-	 * @return current message
-	 */
-	private WindowsMessage getCurrentSeqMsg(
-			List<WindowsMessage> generatedMessageSeq, boolean msgsGenerated,
-			int constMsgType, Iterator<WindowsMessage> seqIterator) {
-		WindowsMessage currentSeqMsg = null;
-		if (msgsGenerated) {
-			currentSeqMsg = seqIterator.next();
-		} else {
-			currentSeqMsg = new WindowsMessage(constMsgType);
-			generatedMessageSeq.add(currentSeqMsg);
-		}
-		return currentSeqMsg;
-	}
-
-	// ////////////////////////////
-	// General helper functions //
-	// ////////////////////////////
-
-	/**
-	 * <p>
-	 * Retrieves a message from the storage for, e.g., comparison or replay.
-	 * "this" is used to refer to the current message.
-	 * </p>
-	 * 
-	 * @param currentMessage
-	 *            current message during the parsing; passed to handle "this"
-	 * @param obj
-	 *            object identifier in the storage
-	 * @return message retrieved from the storage
-	 * @throws InvalidParameterException
-	 *             thrown in case of invalid uses of "this" or if no message
-	 *             with the identifier obj is found in the storage
-	 */
-	private WindowsMessage getStoredMessageVariable(
-			WindowsMessage currentMessage, String obj)
-			throws InvalidParameterException {
-		WindowsMessage varMessage = null;
-		if (obj.equals("this")) {
-			if (currentMessage == null) {
-				throw new InvalidParameterException(
-						"Failure obtaining term value for rule "
-								+ currentRuleName
-								+ ": \"this\" is not a valid name for generating runtime messages.");
-			}
-			varMessage = currentMessage;
-		} else {
-			Object tmp = messageStorage.get(obj);
-			if (tmp instanceof WindowsMessage) {
-				varMessage = (WindowsMessage) tmp;
-			} else {
-				throw new InvalidParameterException(
-						"Failure obtaining term value for rule "
-								+ currentRuleName + ": No message \"" + obj
-								+ "\" stored.");
-			}
-		}
-		return varMessage;
-	}
-
-	/**
-	 * <p>
-	 * Retrieves a stored message sequence from the storage.
-	 * </p>
-	 * 
-	 * @param obj
-	 *            object identifier in the storage
-	 * @return message sequence retrieved from the storage
-	 * @throws InvalidParameterException
-	 *             thrown if no message sequences with the identifier obj is
-	 *             found in the storage
-	 */
-	@SuppressWarnings("unchecked")
-	private List<WindowsMessage> getStoredSeqVariable(String obj)
-			throws InvalidParameterException {
-		List<WindowsMessage> varMsgSeq = null;
-		Object tmp = messageStorage.get(obj);
-		if (tmp instanceof List<?>) {
-			varMsgSeq = (List<WindowsMessage>) tmp;
-		} else {
-			throw new InvalidParameterException(
-					"Failure obtaining term value for rule " + currentRuleName
-							+ ": No sequence \"" + obj + "\" store.");
-		}
-		return varMsgSeq;
-	}
-
-	/**
-	 * <p>
-	 * Handles term-nodes and returns the value of the described term.
-	 * </p>
-	 * 
-	 * @param currentMessage
-	 *            current message during the parsing; required to resolve
-	 *            references to "this" in a term
-	 * @param termElement
-	 *            {@link Element} representing the term node
-	 * @return value of the term or {@code null} of the term node could not be
-	 *         evaluated
-	 */
-	private String getTermValue(WindowsMessage currentMessage,
-			Element termElement) {
-		String value = null;
-		WindowsMessage varMessage = null;
-		if (termElement.getName().equals("constValue")) {
-			value = termElement.getAttributeValue("value");
-		} else if (termElement.getName().equals("paramValue")) {
-			String objectName = termElement.getAttributeValue("obj");
-			varMessage = getStoredMessageVariable(currentMessage, objectName);
-			if (varMessage != null) {
-				String param = termElement.getAttributeValue("param");
-				value = varMessage.getParameter(param);
-			}
-		} else if (termElement.getName().equals("winInfoValue")) {
-			String objectName = termElement.getAttributeValue("obj");
-			varMessage = getStoredMessageVariable(currentMessage, objectName);
-			if (varMessage != null) {
-				String paramString = termElement.getAttributeValue("winParam");
-				if (paramString.equals("class")) {
-					value = varMessage.getWindowClass();
-				} else if (paramString.equals("resourceId")) {
-					value = "" + varMessage.getWindowResourceId();
-				} else if (paramString.equals("hwnd")) {
-					value = "" + varMessage.getHwnd();
-				} else if (paramString.equals("parentTarget")) {
-					String target = varMessage.getXmlWindowDescription();
-					int index = target.lastIndexOf("<");
-					if (index == 0) {
-						Console.traceln("Trying to adress parent of top-level window! Replay probably invalid!");
-					}
-					value = target.substring(0, index);
-				} else if (paramString.equals("parentClass")) {
-					value = varMessage.getParentClass();
-				}
-			}
-		} else if (termElement.getName().equals("msgInfoValue")) {
-			String objectName = termElement.getAttributeValue("obj");
-			varMessage = getStoredMessageVariable(currentMessage, objectName);
-			if (varMessage != null) {
-				String paramString = termElement.getAttributeValue("msgParam");
-				if (paramString.equals("type")) {
-					value = "" + varMessage.getType();
-				} else if (paramString.equals("target")) {
-					value = varMessage.getXmlWindowDescription();
-				}
-			}
-		}
-		return value;
-	}
-
-	/**
-	 * <p>
-	 * Handles term-nodes contained by equalSeq nodes.
-	 * </p>
-	 * 
-	 * @param termElement
-	 *            {@link Element} representing the term-node
-	 * @return list of values of the term
-	 */
-	private List<String> getTermValueSeq(Element termElement) {
-		List<String> values = new LinkedList<String>();
-		if (termElement.getName().equals("seqValue")) {
-			String obj = termElement.getAttributeValue("seqObj");
-			String param = termElement.getAttributeValue("param");
-			List<WindowsMessage> seqVar = getStoredSeqVariable(obj);
-
-			for (WindowsMessage msg : seqVar) {
-				// msg.getParameter returns null, if parameter is not found,
-				// therefore the List can contain null-values
-				values.add(msg.getParameter(param));
-			}
-		}
-		return values;
-	}
-
-	/**
-	 * <p>
-	 * Handles LOWORD and HIWORD child nodes of LPARAM and WPARAM nodes. The
-	 * returned value is the LPARAM/WPARAM value based on the LOWORD and HIWORD.
-	 * </p>
-	 * 
-	 * @param param
-	 *            {@link Element} representing the LPARAM/WPARAM node
-	 * @return value of the LPARAM/WPARAM
-	 */
-	private long loHiWord(Element param) {
-		Element loword = param.getChild("LOWORD", rulesNamespace);
-		Element hiword = param.getChild("HIWORD", rulesNamespace);
-		String lowordStr = getTermValue(null, (Element) loword.getChildren()
-				.get(0));
-		String hiwordStr = getTermValue(null, (Element) hiword.getChildren()
-				.get(0));
-		return MAKEPARAM(Short.parseShort(lowordStr),
-				Short.parseShort(hiwordStr));
-	}
-
-	/**
-	 * <p>
-	 * Takes to short integers and combines them into the high and low order
-	 * bits of an integer.
-	 * </p>
-	 * 
-	 * @param loword
-	 *            low word
-	 * @param hiword
-	 *            high word
-	 * @return combined integer
-	 */
-	private static int MAKEPARAM(short loword, short hiword) {
-		return loword | ((int) hiword) << Short.SIZE;
-	}
+    /**
+     * <p>
+     * the list of all event generation rules available
+     * </p>
+     */
+    private List<EventGenerationRule> generationRules;
+    
+    /**
+     * <p>
+     * Name and path of the XML files containing the rules.
+     * </p>
+     */
+    private String rulesFile;
+
+    /**
+     * <p>
+     * Iterator used for the current sequence.
+     * </p>
+     */
+    private ListIterator<WindowsMessage> sequenceIterator;
+
+    /**
+     * <p>
+     * Token that is currently being generated.
+     * </p>
+     */
+    private MFCEvent currentEvent;
+
+    /**
+     * <p>
+     * Event type of the current token. Stored as a member to be able to update it during the
+     * parsing of the idinfo tag.
+     * </p>
+     */
+    private IEventType currentType;
+
+    /**
+     * <p>
+     * 
+     * </p>
+     */
+    private MFCGUIElement currentTarget;
+
+    /**
+     * <p>
+     * Reference to the ul:rules namespace.
+     * </p>
+     */
+    private static Namespace rulesNamespace;
+
+    /**
+     * <p>
+     * The name of the rule that is currently being evaluated.
+     * </p>
+     */
+    private String currentRuleName;
+
+    /**
+     * <p>
+     * Internal message storage. Used to implement the <code>{@literal <store>}</code> and
+     * <code>{@literal <storeSeq>}</code> tags.
+     * </p>
+     */
+    private Map<String, Object> messageStorage;
+
+    /**
+     * <p>
+     * reference to the window tree created during parsing
+     * </p>
+     */
+    private WindowTree windowTree;
+
+    /**
+     * <p>
+     * Creates a new EventGenerator. Sets "data/rules.xml" as default file for the rules.
+     * </p>
+     */
+    public EventGenerator(WindowTree windowTree) {
+        rulesFile = "data/rules.xml";
+        this.windowTree = windowTree;
+    }
+
+    /**
+     * <p>
+     * Tries to match the rules to the given sequence to generate an {@link WindowsEvent}.
+     * </p>
+     * <p>
+     * The rules are matched the order, in which they are defined in the XML file. Therefore, the
+     * order of the rules in the file defines priorities, when multiple rules could be matched to
+     * the same sequence.
+     * </p>
+     * 
+     * @param sequence
+     *            sequence of message for which an event will be generated
+     * @return event that matches the messages; null, if no rule can be matched
+     */
+    public Event generateEvent(List<WindowsMessage> sequence) {
+        if (generationRules == null) {
+            parseGenerationRules();
+        }
+        
+        
+        /*System.out.println("generating event for ");
+        for (WindowsMessage msg : sequence) {
+            System.out.println("    " + msg + "  " + msg.getParameter("scrollBarHandle") + "  " + msg.getTargetXML());
+        }*/
+
+        boolean isMatch = false;
+
+        for (int ruleIndex = 0; ruleIndex < generationRules.size() && !isMatch; ruleIndex++) {
+            EventGenerationRule currentRule = generationRules.get(ruleIndex);
+            currentRuleName = currentRule.getName();
+            
+            //System.out.println("checking rule " + currentRuleName);
+            
+            messageStorage = new HashMap<String, Object>();
+            sequenceIterator = sequence.listIterator();
+            
+            isMatch = evaluateMessageConditions(currentRule);
+
+            if (isMatch) {
+                currentType = MFCEventTypeFactory.getInstance().getEventType
+                    (currentRuleName, resolveParameters(currentRule.getEventParameters()));
+                
+                currentEvent = new MFCEvent(currentType, currentTarget, windowTree.getGUIModel());
+                
+                for (EventGenerationRule.ReplayMessageSpec replayMessageSpec :
+                      currentRule.getReplayMessageSpecifications())
+                {
+                    if (replayMessageSpec.generateSingleMessage()) {
+                        try {
+                            generateReplayMessage(replayMessageSpec);
+                        }
+                        catch (InvalidParameterException e) {
+                            Console.printerrln(e.getMessage());
+                            // TODO currentToken.invalidateReplay();
+                        }
+                    }
+                    else {
+                        try {
+                            generateReplaySequence(replayMessageSpec);
+                            // TODO currentToken.invalidateReplay();
+                        }
+                        catch (InvalidParameterException e) {
+                            Console.printerrln(e.getMessage());
+                            // TODO currentToken.invalidateReplay();
+                        }
+                    }
+                }
+
+                Console.traceln(currentEvent.getType().toString() + " matched");
+            }
+            else {
+                currentEvent = null;
+            }
+        }
+        if (!isMatch) {
+            Console.traceln("no match found for sequence: " + sequence.toString());
+        }
+        
+        
+        /*if (currentEvent != null && currentEvent.getReplayables() != null) {
+            System.out.println("replay messages are ");
+            for (de.ugoe.cs.quest.eventcore.IReplayable msg : currentEvent.getReplayables()) {
+                System.out.println("    " + msg + "  " + msg.getReplay());
+            }
+        }
+
+        System.out.println();*/
+
+
+        return currentEvent;
+    }
+
+    // ////////////////////////////////////////////////////////////
+    // Helper functions for matching of events, i.e., msg-nodes //
+    // ////////////////////////////////////////////////////////////
+
+    /**
+     * <p>
+     * TODO: comment
+     * </p>
+     *
+     * @param currentRule
+     */
+    private boolean evaluateMessageConditions(EventGenerationRule currentRule) {
+        boolean isMatch = true;
+        List<EventGenerationRule.MessageCondition> messageConditions =
+            currentRule.getMessageConditions();
+
+        int i = 0;
+        while (isMatch && i < messageConditions.size()) {
+            EventGenerationRule.MessageCondition messageCondition = messageConditions.get(i);
+            if (messageCondition.matchMultiple()) {
+                EventGenerationRule.MessageCondition nextMessageCondition = null;
+                if (i + 1 < messageConditions.size()) {
+                    nextMessageCondition = messageConditions.get(i + 1);
+                }
+                try {
+                    isMatch = matchMultipleConditions(messageCondition, nextMessageCondition);
+                }
+                catch (InvalidParameterException e) {
+                    Console.printerrln(e.getMessage());
+                }
+            }
+            else {
+                try {
+                    isMatch = matchSingleMessage(messageCondition);
+                }
+                catch (InvalidParameterException e) {
+                    Console.printerrln(e.getMessage());
+                }
+            }
+            i++;
+        }
+        
+        return isMatch;
+    }
+
+    /**
+     * <p>
+     * Handles msg-nodes where multiple is not true, i.e., not a sequences.
+     * </p>
+     * 
+     * @param messageElement
+     *            {@link Element} representing the msg-node
+     * @return true, if a match is found; false otherwise
+     */
+    private boolean matchSingleMessage(EventGenerationRule.MessageCondition condition) {
+        boolean isMatch = false;
+        WindowsMessage currentMessage = null;
+
+        WindowsMessageType type = condition.getMessageType();
+
+        while (!isMatch && sequenceIterator.hasNext()) {
+            /*
+             * traverses the messages from the current position forward till a message with the
+             * correct type is found
+             */
+            currentMessage = sequenceIterator.next();
+            if (type == currentMessage.getType()) {
+                // message with the correct type found
+                // eval child nodes for further matching/storing
+                isMatch = evaluateMessageCondition(currentMessage, condition);
+
+                // in case the message is a match, eval storage children
+                if (isMatch) {
+                    handleStorage(condition, currentMessage);
+                    currentTarget = currentMessage.getTarget();
+                    // TODO currentToken.setTargetShort(currentMessage.getParentNames());
+                }
+            }
+        }
+
+        return isMatch;
+    }
+
+    /**
+     * <p>
+     * Handles msg-nodes where multiple is true, i.e., sequences. Requires knowledge about the next
+     * msg-node to determine the end of the sequence.
+     * </p>
+     * 
+     * @param messageElement
+     *            {@link Element} representing the msg-node
+     * @param nextMessageElement
+     *            {@link Element} representing the next msg-node; {@code null} if the current node
+     *            is the last one
+     * @return true, if a sequence is matched; false otherwise
+     */
+    private boolean matchMultipleConditions(EventGenerationRule.MessageCondition condition,
+                                            EventGenerationRule.MessageCondition nextCondition)
+    {
+        boolean isMatch = false;
+        boolean isCurrentMatch = false;
+        boolean nextMatchFound = false;
+        WindowsMessage currentMessage = null;
+        WindowsMessage nextMessage = null;
+
+        WindowsMessageType type = condition.getMessageType();
+
+        WindowsMessageType nextType = null;
+        if (nextCondition != null) {
+            nextType = nextCondition.getMessageType();
+        }
+
+        while (!nextMatchFound && sequenceIterator.hasNext()) {
+            currentMessage = sequenceIterator.next();
+            if (type == currentMessage.getType()) {
+                isCurrentMatch = evaluateMessageCondition(currentMessage, condition);
+                isMatch = isMatch || isCurrentMatch;
+
+                if (isCurrentMatch) {
+                    handleStorage(condition, currentMessage);
+                    currentTarget = currentMessage.getTarget();
+                    // TODO currentToken.setTargetShort(currentMessage.getParentNames());
+                }
+            }
+            if (nextCondition != null && isMatch) {
+                // peek next message to check if the sequence ends and the next
+                // match is found
+                if (!sequenceIterator.hasNext()) {
+                    return false; // sequence is over, but not all messages are
+                                  // found
+                }
+                nextMessage = sequenceIterator.next();
+                sequenceIterator.previous();
+
+                if (nextType == nextMessage.getType()) {
+                    nextMatchFound = evaluateMessageCondition(nextMessage, nextCondition);
+                }
+
+            }
+        }
+
+        return isMatch;
+    }
+
+    /**
+     * <p>
+     * Handles equals-nodes.
+     * </p>
+     * 
+     * @param currentMessage
+     *            {@link Element} representing the msg-node the equals-node belongs to
+     * @param messageElement
+     *            {@link Element} representing the equals-node to be evaluated
+     * @return true, if constraint is fulfilled; false otherwise
+     */
+    private boolean evaluateMessageCondition(WindowsMessage                       currentMessage,
+                                             EventGenerationRule.MessageCondition condition)
+    {
+        boolean isMatch = true;
+        for (int i = 0; isMatch && (i < condition.getAttributeConditions().size()); i++)
+        {
+            EventGenerationRule.AttributeCondition attrCond =
+                condition.getAttributeConditions().get(i);
+            
+            // the size 2 of termElements is guaranteed by the XML schema
+            Object value1 = getTermValue(currentMessage, attrCond.getLeftHandSide(), Object.class);
+            Object value2 = getTermValue(currentMessage, attrCond.getRightHandSide(), Object.class);
+            if (value1 == null || value2 == null) {
+                isMatch = false;
+            }
+            else {
+                isMatch = isMatch && value1.equals(value2);
+            }
+        }
+//        for (Element childElement : (List<Element>) messageElement.getChildren("equalsSeq",
+//                                                                               rulesNamespace))
+//        {
+//            List<Element> termElements = childElement.getChildren();
+//            List<String> values1 = getTermValueSeq(termElements.get(0));
+//            List<String> values2 = getTermValueSeq(termElements.get(0));
+//            if (values1 == null || values2 == null) {
+//                isMatch = false;
+//            }
+//            else {
+//                isMatch = isMatch && values1.equals(values2);
+//            }
+//        }
+        return isMatch;
+    }
+
+    /**
+     * <p>
+     * Handles store-nodes and storeSeq-nodes.
+     * </p>
+     * 
+     * @param messageElement
+     *            {@link Element} representing the msg-node that is currently being evaluated
+     * @param currentMessage
+     *            current message in the message sequence that is matched; this is the message that
+     *            is stored
+     */
+    @SuppressWarnings("unchecked")
+    private void handleStorage(EventGenerationRule.MessageCondition messageCondition,
+                               WindowsMessage                       currentMessage)
+    {
+        for (Term valueToStore : messageCondition.getMessagesToStore())
+        {
+            if (valueToStore.getMessageId() != null) {
+              ReplayWindowsMessage replayMessage = new ReplayWindowsMessage(currentMessage);
+              messageStorage.put(valueToStore.getMessageId(), replayMessage);
+              resolveHwnd(replayMessage, valueToStore.getResolveHandles());
+            }
+            else if (valueToStore.getSequenceId() != null) {
+                Object tmp = messageStorage.get(valueToStore.getSequenceId());
+                ReplayWindowsMessage replayMessage = new ReplayWindowsMessage(currentMessage);
+                List<ReplayWindowsMessage> storedSequence;
+                if (tmp == null || tmp instanceof ReplayWindowsMessage) {
+                    storedSequence = new LinkedList<ReplayWindowsMessage>();
+                    storedSequence.add(replayMessage);
+                    messageStorage.put(valueToStore.getSequenceId(), storedSequence);
+                }
+                else if (tmp instanceof List<?>) {
+                    storedSequence = (List<ReplayWindowsMessage>) tmp;
+                    storedSequence.add(replayMessage);
+                    messageStorage.put(valueToStore.getSequenceId(), storedSequence);
+                }
+                resolveHwnd(replayMessage, valueToStore.getResolveHandles());
+            }
+        }
+    }
+
+    /**
+     * <p>
+     * Resolves a parameter that contains a HWND of a message to the target string of the HWND and
+     * stores it.
+     * </p>
+     * 
+     * @param currentMessage
+     *            message whose HWND is resolved
+     * @param list
+     *            child element of the store node that represents the resolve
+     */
+    private void resolveHwnd(ReplayWindowsMessage currentMessage, List<Term> resolveHandles) {
+        if (resolveHandles != null) {
+            for (Term resolveElement : resolveHandles) {
+                String param = resolveElement.getMessageParameterName();
+                String storeParam = resolveElement.getStoreParameterName();
+                long paramHwnd = (Long) currentMessage.getParameter(param);
+                MFCGUIElement guiElement = windowTree.find(paramHwnd);
+                if (guiElement != null) {
+                    currentMessage.addParameter(storeParam, "" + guiElement.toXML());
+                }
+            }
+        }
+    }
+
+    // /////////////////////////////////////////////////////
+    // Helper functions for generating the replay, i.e.,
+    // parsing of genMsg und genMsgSeq-nodes
+    // /////////////////////////////////////////////////////
+
+    /**
+     * <p>
+     * Handles genMsg-nodes and adds the replay to the {@link Event} that is generated.
+     * </p>
+     * 
+     * @param genMsgElement
+     *            {@link Element} representing the genMsg-node
+     */
+    private void generateReplayMessage(EventGenerationRule.ReplayMessageSpec messageSpec) {
+        ReplayWindowsMessage generatedMessage = null;
+        if (messageSpec.getReplayObjectId() != null) { // replay stored message without change
+            generatedMessage = getStoredMessageVariable(null, messageSpec.getReplayObjectId());
+        }
+        else { // generate message according to the rule
+            generatedMessage = new ReplayWindowsMessage
+                (getTermValue(messageSpec.getType(), WindowsMessageType.class));
+            generatedMessage.setTargetXML(getTermValue(messageSpec.getTarget(), String.class));
+
+            if ((messageSpec.getLparamHiWord() != null) ||
+                    (messageSpec.getLparamLoWord() != null))
+            {
+                generatedMessage.setLPARAM
+                    (loHiWord(messageSpec.getLparamLoWord(), messageSpec.getLparamHiWord()));
+            }
+            else if (messageSpec.getLparam() != null) {
+                try {
+                    generatedMessage.setLPARAM(getTermValue(messageSpec.getLparam(), Long.class));
+                }
+                catch (IllegalArgumentException e) {
+                    generatedMessage.setLPARAMasWindowDesc
+                        (getTermValue(messageSpec.getLparam(), String.class));
+                }
+            }
+
+            if ((messageSpec.getWparamHiWord() != null) ||
+                    (messageSpec.getWparamLoWord() != null))
+            {
+                generatedMessage.setWPARAM
+                    (loHiWord(messageSpec.getWparamLoWord(), messageSpec.getWparamHiWord()));
+            }
+            else if (messageSpec.getWparam() != null) {
+                try {
+                    generatedMessage.setWPARAM(getTermValue(messageSpec.getWparam(), Long.class));
+                }
+                catch (IllegalArgumentException e) {
+                    generatedMessage.setWPARAMasWindowDesc
+                        (getTermValue(messageSpec.getWparam(), String.class));
+                }
+            }
+            
+            
+        }
+
+        generatedMessage.setDelay(messageSpec.getDelay());
+
+        currentEvent.addReplayable(generatedMessage);
+    }
+
+    /**
+     * Handles genMsgSeq-nodes and adds the replay to the {@link Event} that is generated.</p>
+     * 
+     * @param genMsgElement
+     *            {@link Element} representing the genMsgSeq-node.
+     */
+    private void generateReplaySequence(EventGenerationRule.ReplayMessageSpec messageSpec)
+    {
+        List<ReplayWindowsMessage> generatedMessageSeq = new LinkedList<ReplayWindowsMessage>();
+        if (messageSpec.getReplayObjectId() != null) { // replay stored sequence without changes
+            generatedMessageSeq = getStoredSeqVariable(messageSpec.getReplayObjectId());
+        }
+        else {
+            List<ReplayWindowsMessage> seqVar =
+                getStoredSeqVariable(messageSpec.getReplayObjectId());
+            
+            Term typeTerm = messageSpec.getType();
+            if (typeTerm.getSequenceId() != null) {
+                seqVar = getStoredSeqVariable(typeTerm.getSequenceId());
+                for (WindowsMessage msg : seqVar) {
+                    ReplayWindowsMessage replayMessage = new ReplayWindowsMessage(msg.getType());
+                    replayMessage.setDelay(messageSpec.getDelay());
+                    generatedMessageSeq.add(replayMessage);
+                }
+            }
+            else { // constValue type
+                WindowsMessageType constMsgType = getTermValue(typeTerm, WindowsMessageType.class);
+                for (int i = 0; i < seqVar.size(); i++) {
+                    ReplayWindowsMessage replayMessage = new ReplayWindowsMessage(constMsgType);
+                    replayMessage.setDelay(messageSpec.getDelay());
+                    generatedMessageSeq.add(replayMessage);
+                }
+            }
+
+            createSequenceTarget(generatedMessageSeq, messageSpec);
+            createSequenceLParam(generatedMessageSeq, messageSpec);
+            createSequenceWParam(generatedMessageSeq, messageSpec);
+        }
+        
+        currentEvent.addReplayableSequence(generatedMessageSeq);
+    }
+
+    /**
+     * <p>
+     * Creates the targets for replay sequences generated with genMsgSeq-nodes.
+     * </p>
+     * 
+     * @param generatedMessageSeq
+     *            list of the messages that is being generated
+     * @param msgsGenerated
+     *            boolean stating if the list of messages is already generated or if the generation
+     *            has to be handles by this method
+     * @param constMsgType
+     *            a constant message type that is used for message generation, in case the list of
+     *            message is generated by this method
+     * @param termElement
+     *            {@link Element} representing the term-node describing the target
+     * @return true, if the list of message is generated after calling this method; false otherwise
+     * @throws NoSuchElementException
+     *             thrown if the seqVar referred to in the termElement contains a different number
+     *             of messages than is contained in messageSeq
+     */
+    private void createSequenceTarget(List<ReplayWindowsMessage>            generatedMessageSeq,
+                                      EventGenerationRule.ReplayMessageSpec messageSpec)
+        throws NoSuchElementException
+    {
+        Iterator<ReplayWindowsMessage> seqIterator = generatedMessageSeq.iterator();
+        if (messageSpec.getTarget().getSequenceId() != null) {
+            List<ReplayWindowsMessage> seqVar =
+                getStoredSeqVariable(messageSpec.getTarget().getSequenceId());
+
+            if (seqVar.size() != generatedMessageSeq.size()) {
+                throw new InvalidParameterException
+                    ("Failure generating replay sequence for rule " + currentRuleName +
+                     ": One or more of the sequence variables used to generate a sequence have " +
+                     "different lenghts.");
+            }
+            
+            for (WindowsMessage msg : seqVar) {
+                seqIterator.next().setTarget(msg.getTarget());
+            }
+        }
+        else { // const value
+            throw new AssertionError("target must be a sequence variable!");
+            /*
+             * If target would not be a variable, the message-elements could not yet be created and
+             * the whole sequence might be broken. If this is to be changed, createSequenceLParam
+             * and createSequenceWParam need to be addepted, too.
+             */
+        }
+    }
+
+    /**
+     * <p>
+     * Creates the LPARAMs for replay sequences generated with genMsgSeq-nodes.
+     * </p>
+     * 
+     * @param generatedMessageSeq
+     *            list of the messages that is being generated
+     * @param msgsGenerated
+     *            boolean stating if the list of messages is already generated or if the generation
+     *            has to be handles by this method
+     * @param constMsgType
+     *            a constant message type that is used for message generation, in case the list of
+     *            message is generated by this method
+     * @param termElement
+     *            {@link Element} representing the term-node describing the LPARAM
+     * @return true, if the list of message is generated after calling this method; false otherwise
+     * @throws NoSuchElementException
+     *             thrown if the seqVar referred to in the termElement contains a different number
+     *             of messages than is contained in messageSeq
+     */
+    private void createSequenceLParam(List<ReplayWindowsMessage>            generatedMessageSeq,
+                                      EventGenerationRule.ReplayMessageSpec messageSpec)
+        throws NoSuchElementException
+    {
+        Iterator<ReplayWindowsMessage> seqIterator = generatedMessageSeq.iterator();
+        if (messageSpec.getLparam().getSequenceId() != null) {
+            List<ReplayWindowsMessage> seqVar =
+                getStoredSeqVariable(messageSpec.getLparam().getSequenceId());
+            
+            if (seqVar.size() != generatedMessageSeq.size()) {
+                throw new InvalidParameterException
+                    ("Failure generating replay sequence for rule " + currentRuleName +
+                     ": One or more of the sequence variables used to generate a sequence have " +
+                     "different lengths.");
+            }
+            for (WindowsMessage msg : seqVar) {
+                ReplayWindowsMessage currentSeqMsg = seqIterator.next();
+                Object paramValue =
+                    msg.getParameter(messageSpec.getLparam().getSequenceParameterName());
+                if (paramValue instanceof Long) {
+                    currentSeqMsg.setLPARAM((Long) paramValue);
+                }
+                else {
+                    currentSeqMsg.setLPARAMasWindowDesc((String) paramValue);
+                }
+            }
+        }
+        else { // const value
+            int paramValue = getTermValue(messageSpec.getLparam(), int.class);
+            while (seqIterator.hasNext()) {
+                seqIterator.next().setLPARAM(paramValue);
+            }
+        }
+
+    }
+
+    /**
+     * <p>
+     * Creates the WPARAMs for replay sequences generated with genMsgSeq-nodes.
+     * </p>
+     * 
+     * @param generatedMessageSeq
+     *            list of the messages that is being generated
+     * @param msgsGenerated
+     *            boolean stating if the list of messages is already generated or if the generation
+     *            has to be handles by this method
+     * @param constMsgType
+     *            a constant message type that is used for message generation, in case the list of
+     *            message is generated by this method
+     * @param termElement
+     *            {@link Element} representing the term-node describing the WPARAM
+     * @return true, if the list of message is generated after calling this method; false otherwise
+     * @throws NoSuchElementException
+     *             thrown if the seqVar referred to in the termElement contains a different number
+     *             of messages than is contained in messageSeq
+     */
+    private void createSequenceWParam(List<ReplayWindowsMessage>            generatedMessageSeq,
+                                      EventGenerationRule.ReplayMessageSpec messageSpec)
+        throws NoSuchElementException
+    {
+        Iterator<ReplayWindowsMessage> seqIterator = generatedMessageSeq.iterator();
+        if (messageSpec.getWparam().getSequenceId() != null) {
+            List<ReplayWindowsMessage> seqVar =
+                getStoredSeqVariable(messageSpec.getWparam().getSequenceId());
+            
+            if (seqVar.size() != generatedMessageSeq.size()) {
+                throw new InvalidParameterException
+                    ("Failure generating replay sequence for rule " + currentRuleName +
+                     ": One or more of the sequence variables used to generate a sequence have " +
+                     "different lengths.");
+            }
+            for (WindowsMessage msg : seqVar) {
+                ReplayWindowsMessage currentSeqMsg = seqIterator.next();
+                Object paramValue =
+                    msg.getParameter(messageSpec.getWparam().getSequenceParameterName());
+                if (paramValue instanceof Long) {
+                    currentSeqMsg.setWPARAM((Long) paramValue);
+                }
+                else {
+                    currentSeqMsg.setWPARAMasWindowDesc((String) paramValue);
+                }
+            }
+        }
+        else { // const value
+            int paramValue = getTermValue(messageSpec.getWparam(), int.class);
+            while (seqIterator.hasNext()) {
+                seqIterator.next().setWPARAM(paramValue);
+            }
+        }
+    }
+
+    // ////////////////////////////
+    // General helper functions //
+    // ////////////////////////////
+
+    /**
+     * <p>
+     * TODO: comment
+     * </p>
+     *
+     * @param eventParameters
+     * @return
+     */
+    private Map<String, String> resolveParameters(List<Term> eventParameters) {
+        Map<String, String> resultParameters = null;
+        
+        if ((eventParameters != null) && (eventParameters.size() > 0)) {
+            resultParameters = new HashMap<String, String>();
+            
+            for (Term term : eventParameters) {
+                if ("seqValue".equals(term.getName())) {
+                    List<String> values = getTermValueAsList(term, String.class);
+                                        
+                    resultParameters.put
+                        (term.getSequenceParameterName(), (String) values.get(values.size() - 1));
+                }
+                else {
+                    resultParameters.put
+                        (term.getMessageParameterName(), getTermValue(term, String.class));
+                }
+            }
+        }
+        
+        return resultParameters;
+    }
+
+    /**
+     * <p>
+     * Retrieves a message from the storage for, e.g., comparison or replay. "this" is used to refer
+     * to the current message.
+     * </p>
+     * 
+     * @param currentMessage
+     *            current message during the parsing; passed to handle "this"
+     * @param obj
+     *            object identifier in the storage
+     * @return message retrieved from the storage
+     * @throws InvalidParameterException
+     *             thrown in case of invalid uses of "this" or if no message with the identifier obj
+     *             is found in the storage
+     */
+    private ReplayWindowsMessage getStoredMessageVariable(WindowsMessage currentMessage, String obj)
+        throws InvalidParameterException
+    {
+        ReplayWindowsMessage varMessage = null;
+        if (obj.equals("this")) {
+            if (currentMessage == null) {
+                throw new InvalidParameterException("Failure obtaining term value for rule " +
+                    currentRuleName +
+                    ": \"this\" is not a valid name for generating runtime messages.");
+            }
+            varMessage = new ReplayWindowsMessage(currentMessage);
+        }
+        else {
+            Object tmp = messageStorage.get(obj);
+            if (tmp instanceof ReplayWindowsMessage) {
+                varMessage = (ReplayWindowsMessage) tmp;
+            }
+            else {
+                throw new InvalidParameterException("Failure obtaining term value for rule " +
+                    currentRuleName + ": No message \"" + obj + "\" stored.");
+            }
+        }
+        return varMessage;
+    }
+
+    /**
+     * <p>
+     * Retrieves a stored message sequence from the storage.
+     * </p>
+     * 
+     * @param obj
+     *            object identifier in the storage
+     * @return message sequence retrieved from the storage
+     * @throws IllegalArgumentException
+     *             thrown if no message sequences with the identifier obj is found in the storage
+     */
+    @SuppressWarnings("unchecked")
+    private List<ReplayWindowsMessage> getStoredSeqVariable(String obj)
+        throws IllegalArgumentException
+    {
+        List<ReplayWindowsMessage> varMsgSeq = null;
+        Object tmp = messageStorage.get(obj);
+        if (tmp instanceof List<?>) {
+            varMsgSeq = (List<ReplayWindowsMessage>) tmp;
+        }
+        else {
+            throw new IllegalArgumentException("Failure obtaining term value for rule " +
+                                               currentRuleName + ": No sequence \"" + obj +
+                                               "\" store.");
+        }
+        return varMsgSeq;
+    }
+
+    /**
+     * <p>
+     * convenience method for {@link #getTermValue(WindowsMessage, Term)} with current message is
+     * null.
+     * </p>
+     * 
+     * @param termElement
+     *            {@link Element} representing the term node
+     * @return value of the term or {@code null} of the term node could not be evaluated
+     */
+    private <T> T getTermValue(EventGenerationRule.Term term, Class<T> expectedType) {
+        return getTermValue(null, term, expectedType);
+    }
+
+    /**
+     * <p>
+     * Handles term-nodes and returns the value of the described term.
+     * </p>
+     * 
+     * @param currentMessage
+     *            current message during the parsing; required to resolve references to "this" in a
+     *            term
+     * @param termElement
+     *            {@link Element} representing the term node
+     * @return value of the term or {@code null} of the term node could not be evaluated
+     */
+    private <T> T getTermValue(WindowsMessage           currentMessage,
+                               EventGenerationRule.Term term,
+                               Class<T>                 expectedType)
+    {
+        T value = null;
+        
+        if ("constValue".equals(term.getName())) {
+            value = getValueAsType(term.getValue(), expectedType);
+        }
+        else if ("paramValue".equals(term.getName())) {
+            String objectName = term.getMessageId();
+            WindowsMessage varMessage = getStoredMessageVariable(currentMessage, objectName);
+            if (varMessage != null) {
+                String param = term.getMessageParameterName();
+                value = getValueAsType(varMessage.getParameter(param), expectedType);
+            }
+        }
+        else if ("winInfoValue".equals(term.getName())) {
+            String objectName = term.getMessageId();
+            WindowsMessage varMessage = getStoredMessageVariable(currentMessage, objectName);
+            if (varMessage != null) {
+                String paramString = term.getWindowParameterName();
+                if (paramString.equals("class")) {
+                    value = getValueAsType
+                        (((MFCGUIElement) varMessage.getTarget()).getType(), expectedType);
+                }
+                else if (paramString.equals("resourceId")) {
+                    value = getValueAsType
+                        (((MFCGUIElement) varMessage.getTarget()).getResourceId(), expectedType);
+                }
+                else if (paramString.equals("hwnd")) {
+                    value = getValueAsType
+                        (((MFCGUIElement) varMessage.getTarget()).getId(), expectedType);
+                }
+                else if (paramString.equals("parentTarget")) {
+                    String target = varMessage.getTargetXML();
+                    int index = target.lastIndexOf("<");
+                    if (index == 0) {
+                        Console.traceln("Trying to adress parent of top-level window! Replay " +
+                        		"probably invalid!");
+                    }
+                    value =  getValueAsType(target.substring(0, index), expectedType);
+                }
+                else if (paramString.equals("parentClass")) {
+                    value =  getValueAsType
+                        (((MFCGUIElement) varMessage.getTarget())
+                        .getParent().getSpecification().getType(), expectedType);
+                }
+            }
+        }
+        else if ("msgInfoValue".equals(term.getName())) {
+            String objectName = term.getMessageId();
+            WindowsMessage varMessage = getStoredMessageVariable(currentMessage, objectName);
+            if (varMessage != null) {
+                String paramString = term.getMessageInfoName();
+                if (paramString.equals("type")) {
+                    value = getValueAsType(varMessage.getType(), expectedType);
+                }
+                else if (paramString.equals("target")) {
+                    value = getValueAsType(varMessage.getTargetXML(), expectedType);
+                }
+            }
+        }
+        else if ("msgInfoValue".equals(term.getName())) {
+            String objectName = term.getMessageId();
+            WindowsMessage varMessage = getStoredMessageVariable(currentMessage, objectName);
+            if (varMessage != null) {
+                String paramString = term.getMessageInfoName();
+                if (paramString.equals("type")) {
+                    value = getValueAsType(varMessage.getType(), expectedType);
+                }
+                else if (paramString.equals("target")) {
+                    value = getValueAsType(varMessage.getTargetXML(), expectedType);
+                }
+            }
+        }
+        
+        return value;
+    }
+    
+    /**
+     * <p>
+     * convenience method for {@link #getTermValueAsList(WindowsMessage, Term)} with current
+     * message is null.
+     * </p>
+     * 
+     * @param termElement
+     *            {@link Element} representing the term node
+     * @return value of the term or {@code null} of the term node could not be evaluated
+     */
+    private <T> List<T> getTermValueAsList(EventGenerationRule.Term term, Class<T> expectedType) {
+        return getTermValueAsList(null, term, expectedType);
+    }
+
+    /**
+     * <p>
+     * Handles term-nodes and returns the value of the described term.
+     * </p>
+     * 
+     * @param currentMessage
+     *            current message during the parsing; required to resolve references to "this" in a
+     *            term
+     * @param termElement
+     *            {@link Element} representing the term node
+     * @return value of the term or {@code null} of the term node could not be evaluated
+     */
+    private <T> List<T> getTermValueAsList(WindowsMessage           currentMessage,
+                                           EventGenerationRule.Term term,
+                                           Class<T>                 expectedElementType)
+    {
+        List<T> values = new ArrayList<T>();
+        if ("seqValue".equals(term.getName())) {
+            List<ReplayWindowsMessage> seqVar = getStoredSeqVariable(term.getSequenceId());
+            Object value;
+            
+            for (ReplayWindowsMessage msg : seqVar) {
+                // msg.getParameter returns null, if parameter is not found,
+                // therefore the List can contain null-values
+                value = msg.getParameter(term.getSequenceParameterName());
+                values.add(getValueAsType(value, expectedElementType));
+            }
+        }
+        else {
+            values.add(getTermValue(currentMessage, term, expectedElementType));
+        }
+        
+        return values;
+    }
+    
+    /**
+     * <p>
+     * TODO: comment
+     * </p>
+     *
+     * @param value
+     * @param expectedType
+     * @return
+     */
+    @SuppressWarnings("unchecked")
+    private <T> T getValueAsType(Object value, Class<T> expectedType) {
+        if (expectedType.isInstance(value)) {
+            return (T) value;
+        }
+        else if (value instanceof String) {
+            try {
+                if (WindowsMessageType.class.equals(expectedType)) {
+                    return (T) WindowsMessageType.parseMessageType((String) value);
+                }
+                else if (Short.class.equals(expectedType)) {
+                    return (T) (Short) Short.parseShort((String) value);
+                }
+            }
+            catch (Exception e) {
+                // in this case, the value can not be transformed to the expected value. So ignore
+                // the exception and fall through to the exception thrown anyway
+            }
+        }
+        else if (value instanceof Long) {
+            try {
+                if (Short.class.equals(expectedType)) {
+                    return (T) (Short) ((Long) value).shortValue();
+                }
+                else if (String.class.equals(expectedType)) {
+                    return (T) ((Long) value).toString();
+                }
+            }
+            catch (Exception e) {
+                // in this case, the value can not be transformed to the expected value. So ignore
+                // the exception and fall through to the exception thrown anyway
+            }
+        }
+        
+        throw new IllegalArgumentException("the term value is not of the expected type " +
+                                           expectedType + " but a " +
+                                           (value != null ? value.getClass() : "null"));
+    }
+
+    /**
+     * <p>
+     * Handles LOWORD and HIWORD child nodes of LPARAM and WPARAM nodes. The returned value is the
+     * LPARAM/WPARAM value based on the LOWORD and HIWORD.
+     * </p>
+     * 
+     * @param param
+     *            {@link Element} representing the LPARAM/WPARAM node
+     * @return value of the LPARAM/WPARAM
+     */
+    private long loHiWord(EventGenerationRule.Term lword, EventGenerationRule.Term hword) {
+        return MAKEPARAM(getTermValue(lword, Short.class), getTermValue(hword, Short.class));
+    }
+
+    /**
+     * <p>
+     * Takes to short integers and combines them into the high and low order bits of an integer.
+     * </p>
+     * 
+     * @param loword
+     *            low word
+     * @param hiword
+     *            high word
+     * @return combined integer
+     */
+    private static int MAKEPARAM(short loword, short hiword) {
+        return loword | ((int) hiword) << Short.SIZE;
+    }
+
+    /**
+     * <p>
+     * TODO: comment
+     * </p>
+     *
+     */
+    @SuppressWarnings("unchecked")
+    private void parseGenerationRules() {
+        SAXBuilder builder = new SAXBuilder();
+        Document doc = null;
+
+        try {
+            doc = builder.build(rulesFile);
+            rulesNamespace = Namespace.getNamespace("ul:rules");
+        }
+        catch (JDOMException e) {
+            Console.printerrln("Invalid rules file.");
+            e.printStackTrace();
+        }
+        catch (IOException e) {
+            Console.printerrln("Invalid rules file.");
+            e.printStackTrace();
+        }
+
+        Element rulesRoot = doc.getRootElement();
+        
+        List<Element> ruleElements = rulesRoot.getChildren("rule", rulesNamespace);
+
+        generationRules = new ArrayList<EventGenerationRule>();
+
+        for (Element ruleElement : ruleElements) {
+            generationRules.add(new EventGenerationRule(ruleElement, rulesNamespace));
+        }
+    }
 
 }
