Index: trunk/autoquest-ui-core/src/main/java/de/ugoe/cs/autoquest/commands/sequences/CMDgenerateReplayfile.java
===================================================================
--- trunk/autoquest-ui-core/src/main/java/de/ugoe/cs/autoquest/commands/sequences/CMDgenerateReplayfile.java	(revision 1270)
+++ trunk/autoquest-ui-core/src/main/java/de/ugoe/cs/autoquest/commands/sequences/CMDgenerateReplayfile.java	(revision 1663)
@@ -15,4 +15,5 @@
 package de.ugoe.cs.autoquest.commands.sequences;
 
+import java.io.BufferedWriter;
 import java.io.File;
 import java.io.FileOutputStream;
@@ -20,4 +21,5 @@
 import java.io.OutputStreamWriter;
 import java.util.Collection;
+import java.util.Iterator;
 import java.util.List;
 import java.util.logging.Level;
@@ -45,169 +47,246 @@
 public class CMDgenerateReplayfile implements Command {
 
-	/*
-	 * (non-Javadoc)
-	 * 
-	 * @see de.ugoe.cs.util.console.Command#help()
-	 */
-	@Override
-	public String help() {
-		return "generateReplayfile <filename> <sequences>";
-	}
-
-	/*
-	 * (non-Javadoc)
-	 * 
-	 * @see de.ugoe.cs.util.console.Command#run(java.util.List)
-	 */
-	@SuppressWarnings("unchecked")
-	@Override
-	public void run(List<Object> parameters) {
-		String filename;
-		String sequencesName;
-		try {
-			filename = (String) parameters.get(0);
-			sequencesName = (String) parameters.get(1);
-		} catch (Exception e) {
-			throw new IllegalArgumentException();
-		}
-
-		Collection<List<Event>> sequences = null;
-		Object dataObject = GlobalDataContainer.getInstance().getData(
-				sequencesName);
-		if (dataObject == null) {
-			CommandHelpers.objectNotFoundMessage(sequencesName);
-			return;
-		}
-		if (!SequenceInstanceOf.isCollectionOfSequences(dataObject)) {
-			CommandHelpers.objectNotType(sequencesName,
-					"Collection<List<Event<?>>>");
-			return;
-		}
-
-		sequences = (Collection<List<Event>>) dataObject;
-		createLogfileMultipleSessions(sequences, filename);
-	}
-	
-	    /**
-	     * <p>
-	     * {@link IReplayDecorator} to be used. If this field is {@code null}, no decorator is used.
-	     * Default: {@code null}
-	     * </p>
-	     */
-	    private IReplayDecorator decorator = null;
-
-	    /**
-	     * <p>
-	     * Id of the current session. The starting id is 1.
-	     * </p>
-	     */
-	    int sessionId = 1;
-
-	    /**
-	     * <p>
-	     * Creates a replay file that contains multiple event sequences.
-	     * </p>
-	     * 
-	     * @param sequences
-	     *            collection of event sequences from which the sessions are generated
-	     * @param filename
-	     *            name and path of the replay file
-	     */
-	    private void createLogfileMultipleSessions(Collection<List<Event>> sequences, String filename) {
-	        OutputStreamWriter writer = openReplayFile(filename);
-	        if (writer != null) {
-	            try {
-	                try {
-	                    decorator =
-	                        sequences.iterator().next().get(0).getReplayables().get(0).getDecorator();
-	                }
-	                catch (Exception e) {
-	                    // in the above line, many things can go wrong: emtpy sequences, null
-	                    // references, etc. However, all failures just indicate that no replay decorator
-	                    // should be used, hence, we ignore the exception
-                            Console.traceln(Level.FINEST, "no decorator used for " + filename);
-	                }
-	                if (decorator != null) {
-	                    writer.write(decorator.getHeader());
-	                }
-	                for (List<Event> actions : sequences) {
-	                    writeSession(actions, writer);
-	                }
-	                if (decorator != null) {
-	                    writer.write(decorator.getFooter());
-	                }
-	                decorator = null;
-	                writer.close();
-	            }
-	            catch (IOException e) {
-	                Console.printerrln("Unable to write replay file " + filename);
-	            }
-	        }
-	    }
-
-	    /**
-	     * <p>
-	     * Helper function that opens the replay file for writing.
-	     * </p>
-	     * 
-	     * @param filename
-	     *            name and path of the replay file
-	     * @return {@link OutputStreamWriter} that writes to the replay file
-	     */
-	    private OutputStreamWriter openReplayFile(String filename) {
-	        File file = new File(filename);
-	        boolean fileCreated;
-	        try {
-	            fileCreated = file.createNewFile();
-	            if (!fileCreated) {
-	                Console.traceln(Level.INFO, "Created logfile " + filename);
-	            }
-	            else {
-	                Console.traceln(Level.INFO, "Overwrote existing logfile " + filename);
-	            }
-	        }
-	        catch (IOException e) {
-	            Console.printerrln("Unable to create file " + filename);
-	            Console.logException(e);
-	        }
-	        OutputStreamWriter writer = null;
-	        try {
-	            writer = new OutputStreamWriter(new FileOutputStream(file), "UTF-16");
-	        }
-	        catch (IOException e) {
-	            Console.printerrln("Unable to open file for writing (read-only file):" + filename);
-	            Console.logException(e);
-	        }
-	        return writer;
-	    }
-
-	    /**
-	     * <p>
-	     * Helper function that adds an event sequence to the replay.
-	     * </p>
-	     * 
-	     * @param actions
-	     *            event sequences to be added
-	     * @param writer
-	     *            {@link OutputStreamWriter} to which the replay is added
-	     * @throws IOException
-	     *             thrown if there is a problem writing to writer
-	     */
-	    private void writeSession(List<Event> actions, OutputStreamWriter writer) throws IOException {
-	        if (decorator != null) {
-	            writer.write(decorator.getSessionHeader(sessionId));
-	        }
-	        for (Event currentAction : actions) {
-
-	            List<? extends IReplayable> replayables = currentAction.getReplayables();
-	            for (IReplayable replayble : replayables) {
-	                writer.write(replayble.getReplay() + StringTools.ENDLINE);
-	                writer.flush();
-	            }
-	        }
-	        if (decorator != null) {
-	            writer.write(decorator.getSessionFooter(sessionId));
-	        }
-	        sessionId++;
-	    }
+    /*
+     * (non-Javadoc)
+     * 
+     * @see de.ugoe.cs.util.console.Command#help()
+     */
+    @Override
+    public String help() {
+        return "generateReplayfile <filename> <sequences>";
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see de.ugoe.cs.util.console.Command#run(java.util.List)
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public void run(List<Object> parameters) {
+        String filename;
+        String sequencesName;
+        try {
+            filename = (String) parameters.get(0);
+            sequencesName = (String) parameters.get(1);
+        }
+        catch (Exception e) {
+            throw new IllegalArgumentException();
+        }
+
+        Collection<List<Event>> sequences = null;
+        Object dataObject = GlobalDataContainer.getInstance().getData(sequencesName);
+        if (dataObject == null) {
+            CommandHelpers.objectNotFoundMessage(sequencesName);
+            return;
+        }
+        if (!SequenceInstanceOf.isCollectionOfSequences(dataObject)) {
+            CommandHelpers.objectNotType(sequencesName, "Collection<List<Event<?>>>");
+            return;
+        }
+
+        sequences = (Collection<List<Event>>) dataObject;
+        createLogfileMultipleSessions(sequences, filename);
+
+        writeJacaretoXML(sequences, filename);
+    }
+
+    private void writeLine(BufferedWriter writer, String line) throws IOException {
+        writer.write(line);
+        writer.newLine();
+    }
+
+    private void writeJacaretoHead(BufferedWriter writer) throws IOException {
+        writeLine(writer, "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>");
+        writeLine(writer, "<JacaretoStructure>");
+        writeLine(writer, "<Record>");
+
+        // TODO: This header content is basically copy+paste from a
+        // specific jacareto replay file right now.
+        // Some things such as screen resolution and especially the
+        // application starter details need to be changed for general cases.
+        writeLine(writer,
+                  "<Calendar procTime=\"0\" duration=\"0\" year=\"2014\" month=\"8\" date=\"11\" hour=\"14\" min=\"43\" sec=\"41\" uuid=\"06831ba1-f28a-4e05-b46e-ce9d8f9ffa0f\" />");
+        writeLine(writer,
+                  "<SystemInfo procTime=\"0\" duration=\"0\" screenWidth=\"2646\" screenHeight=\"1024\" javaVersion=\"1.7.0_65\" lookAndFeel=\"javax.swing.plaf.metal.MetalLookAndFeel\" uuid=\"720f430f-52cf-4d8b-9fbe-58434f766efe\" />");
+        writeLine(writer,
+                  "<KeyboardState procTime=\"0\" duration=\"0\" isNumLockOn=\"false\" isScrollLockOn=\"false\" isCapsLockOn=\"false\" applyIsNumLockOn=\"true\" applyIsScrollLockOn=\"true\" applyIsCapsLockOn=\"true\" uuid=\"28146f79-9fc7-49f9-b4a8-5866a7625683\" />");
+        writeLine(writer, "ComponentMode numberPopupMenues=\"true\" />");
+        writeLine(writer,
+                  "<ApplicationStarter procTime=\"5\" duration=\"5\" name=\"HelloWorldSwing\" class=\"HelloWorldSwing\" initclass=\"\" basepath=\"/home/daniel/project/autoquest-jfcmonitor\" classpathext=\"${basepath}/helloswing.jar;${basepath}/.;\" detectDuration=\"false\" captureparams=\"\" replayparams=\"\" uuid=\"a7b7d7b9-caa9-4d6d-b052-cf74d353275e\" />");
+    }
+
+    private void writeJacaretoEvents(BufferedWriter writer, Collection<List<Event>> sequences)
+        throws IOException
+    {
+        for (List<Event> sequence : sequences) {
+            for (Iterator<Event> eventIter = sequence.iterator(); eventIter.hasNext();) {
+                Event event = eventIter.next();
+
+                // TODO
+            }
+        }
+    }
+
+    private void writeJacaretoTail(BufferedWriter writer) throws IOException {
+        writeLine(writer, "</Record>");
+
+        // TODO: There is a really big <structure> part in jacareto's replay
+        // files but they make no sense to me right now - skip this until later
+        // or until jacareto complains. =)
+        writeLine(writer, "<Structure>");
+        writeLine(writer, "</Structure>");
+
+        writeLine(writer, "<JacaretoStructure>");
+    }
+
+    private void writeJacaretoXML(Collection<List<Event>> sequences, String filename) {
+        BufferedWriter writer = new BufferedWriter(openReplayFile(filename + ".xml"));
+
+        try {
+            writeJacaretoHead(writer);
+            writeJacaretoEvents(writer, sequences);
+            writeJacaretoTail(writer);
+
+            writer.flush();
+            writer.close();
+        }
+        catch (IOException e) {
+            Console.printerrln("Unable to write Jacareto replay file " + filename);
+        }
+    }
+
+    /**
+     * <p>
+     * {@link IReplayDecorator} to be used. If this field is {@code null}, no decorator is used.
+     * Default: {@code null}
+     * </p>
+     */
+    private IReplayDecorator decorator = null;
+
+    /**
+     * <p>
+     * Id of the current session. The starting id is 1.
+     * </p>
+     */
+    int sessionId = 1;
+
+    /**
+     * <p>
+     * Creates a replay file that contains multiple event sequences.
+     * </p>
+     * 
+     * @param sequences
+     *            collection of event sequences from which the sessions are generated
+     * @param filename
+     *            name and path of the replay file
+     */
+    private void createLogfileMultipleSessions(Collection<List<Event>> sequences, String filename) {
+        OutputStreamWriter writer = openReplayFile(filename);
+        if (writer != null) {
+            try {
+                try {
+                    decorator =
+                        sequences.iterator().next().get(0).getReplayables().get(0).getDecorator();
+                }
+                catch (Exception e) {
+                    // in the above line, many things can go wrong: emtpy sequences, null
+                    // references, etc. However, all failures just indicate that no replay decorator
+                    // should be used, hence, we ignore the exception
+                    Console.traceln(Level.FINEST, "no decorator used for " + filename);
+                }
+                if (decorator != null) {
+                    writer.write(decorator.getHeader());
+                }
+                for (List<Event> actions : sequences) {
+                    writeSession(actions, writer);
+                }
+                if (decorator != null) {
+                    writer.write(decorator.getFooter());
+                }
+                decorator = null;
+                writer.close();
+            }
+            catch (IOException e) {
+                Console.printerrln("Unable to write replay file " + filename);
+            }
+        }
+    }
+
+    /**
+     * <p>
+     * Helper function that opens the replay file for writing.
+     * </p>
+     * 
+     * @param filename
+     *            name and path of the replay file
+     * @param encoding
+     *            file encoding, empty string for platform default
+     * @return {@link OutputStreamWriter} that writes to the replay file
+     */
+    private OutputStreamWriter openReplayFile(String filename, String encoding) {
+        File file = new File(filename);
+        boolean fileCreated;
+        try {
+            fileCreated = file.createNewFile();
+            if (!fileCreated) {
+                Console.traceln(Level.INFO, "Created logfile " + filename);
+            }
+            else {
+                Console.traceln(Level.INFO, "Overwrote existing logfile " + filename);
+            }
+        }
+        catch (IOException e) {
+            Console.printerrln("Unable to create file " + filename);
+            Console.logException(e);
+        }
+        OutputStreamWriter writer = null;
+        try {
+            if (encoding.isEmpty()) {
+                writer = new OutputStreamWriter(new FileOutputStream(file));
+            }
+            else {
+                writer = new OutputStreamWriter(new FileOutputStream(file), encoding);
+            }
+        }
+        catch (IOException e) {
+            Console.printerrln("Unable to open file for writing (read-only file):" + filename);
+            Console.logException(e);
+        }
+        return writer;
+    }
+
+    private OutputStreamWriter openReplayFile(String filename) {
+        return openReplayFile(filename, "");
+    }
+
+    /**
+     * <p>
+     * Helper function that adds an event sequence to the replay.
+     * </p>
+     * 
+     * @param actions
+     *            event sequences to be added
+     * @param writer
+     *            {@link OutputStreamWriter} to which the replay is added
+     * @throws IOException
+     *             thrown if there is a problem writing to writer
+     */
+    private void writeSession(List<Event> actions, OutputStreamWriter writer) throws IOException {
+        if (decorator != null) {
+            writer.write(decorator.getSessionHeader(sessionId));
+        }
+        for (Event currentAction : actions) {
+
+            List<? extends IReplayable> replayables = currentAction.getReplayables();
+            for (IReplayable replayble : replayables) {
+                writer.write(replayble.getReplay() + StringTools.ENDLINE);
+                writer.flush();
+            }
+        }
+        if (decorator != null) {
+            writer.write(decorator.getSessionFooter(sessionId));
+        }
+        sessionId++;
+    }
 }
