public class DOMElementValueTrace extends TraceObject/* implements EpisodeSource */{
	private String elementId;
	private String elementType;
	private String nodeType;
	private String nodeName;
	private String oldValue;
	private String newValue;
	private String parentNodeValue;

	public DOMElementValueTrace() {
		super();
		setEpisodeSource(true);
	}

	public String getElementId() {
		return elementId;
	}

	public void setElementId(String elementId) {
		this.elementId = elementId;
	}

	public String getElementType() {
		return elementType;
	}

	public void setElementType(String elementType) {
		this.elementType = elementType;
	}

	public String getNodeType() {
		return nodeType;
	}

	public void setNodeType(String nodeType) {
		this.nodeType = nodeType;
	}

	public String getNodeName() {
		return nodeName;
	}

	public void setNodeName(String nodeName) {
		this.nodeName = nodeName;
	}

	public String getOldValue() {
		return oldValue;
	}

	public void setOldValue(String oldValue) {
		this.oldValue = oldValue;
	}

	public String getNewValue() {
		return newValue;
	}

	public void setNewValue(String newValue) {
		this.newValue = newValue;
	}

	public String getParentNodeValue() {
		return parentNodeValue;
	}

	public void setParentNodeValue(String parentNodeValue) {
		this.parentNodeValue = parentNodeValue;
	}

	public JSONObject getValueChangeAsJSON() {
		JSONObject returnObject = new JSONObject();

		try {
			returnObject.put("elementId", this.elementId);
			// returnObject.put("elementType", this.elementType);
			// returnObject.put("nodeType", this.nodeType);
			// returnObject.put("nodeName", this.nodeName);
			returnObject.put("oldValue", this.oldValue);
			returnObject.put("newValue", this.newValue);
			returnObject.put("parentNodeValue", this.parentNodeValue);
		} catch (JSONException e) {
			e.printStackTrace();
		}
		return returnObject;
	}

} public class DOMEventTrace extends TraceObject/* implements EpisodeSource */{
	private String eventType;
	private String eventHandler;
	private JSONObject targetElement;

	public DOMEventTrace() {
		super();
		setEpisodeSource(true);
	}

	public String getEventType() {
		return eventType;
	}

	public void setEventType(String eventType) {
		this.eventType = eventType;
	}

	public String getEventHandler() {
		if (eventHandler == "") {
			return "anonymous";
		} else {
			return eventHandler;
		}
	}

	public void setEventHandler(String eventHandler) {
		this.eventHandler = eventHandler;
	}

	@JsonSetter("targetElement")
	public void setTargetElement(String targetElement_string) {
		try {
			this.targetElement = new JSONObject(targetElement_string);
		} catch (JSONException e) {
			System.out.println("Exception constructing JSONObject from string "
			        + targetElement_string);
			e.printStackTrace();
		}
	}

	public String getTargetElement() {
		// return targetElement.getString("attributes").replaceAll("\"", "");
		// return targetElement.getString("attributes").replaceAll("\"", "\\\"");
		// return targetElement;
		return targetElement == null ? null : targetElement.toString();
	}

	public String getTargetElementAttributes() {
		try {
			if (targetElement.get("attributes").toString().replaceAll("\"", "").length() > 22) {
				// If there are too many attributes for the target element, print a shorter version
				// This is specific to the pic2plot sequence diagram as the comment box is not very
				// big
				return targetElement.get("attributes").toString().replaceAll("\"", "")
				        .substring(0, 19)
				        + "...";
			} else {
				return targetElement.get("attributes").toString().replaceAll("\"", "");
			}
		} catch (JSONException e) {
			e.printStackTrace();
			return "";
		}
	}
} public class DOMMutationTrace extends TraceObject/* implements EpisodeSource */{
	private String mutationType;
	private String data;
	private String nodeName;
	private String nodeValue;
	private String nodeType;
	private String parentNodeValue;

	public DOMMutationTrace() {
		super();
		setEpisodeSource(false);
	}

	public String getMutationType() {
		return mutationType;
	}

	public String getData() {
		return data;
	}

	public void setData(String data) {
		this.data = data;
	}

	public void setMutationType(String mutationType) {
		this.mutationType = mutationType;
	}

	public String getNodeName() {
		return nodeName;
	}

	public void setNodeName(String nodeName) {
		this.nodeName = nodeName;
	}

	public String getNodeValue() {
		return nodeValue;
	}

	public void setNodeValue(String nodeValue) {
		this.nodeValue = nodeValue;
	}

	public String getNodeType() {
		return nodeType;
	}

	public void setNodeType(String nodeType) {
		this.nodeType = nodeType;
	}

	public String getParentNodeValue() {
		return parentNodeValue;
	}

	public void setParentNodeValue(String parentNodeValue) {
		this.parentNodeValue = parentNodeValue;
	}

	public JSONObject getMutationAsJSON() {
		JSONObject returnObject = new JSONObject();
		try {
			returnObject.put("Mutation type", this.mutationType);
			returnObject.put("Node ID", this.parentNodeValue); // returnObject.put("nodeType",
															   // this.nodeType);
			returnObject.put("Type of value changed", this.nodeName.replace("#", ""));
			returnObject.put("Content changed", this.nodeValue);
		} catch (JSONException e) {
			e.printStackTrace();
		}
		return returnObject;
	}

	/*
	 * public String getMutationAsJSON() { // JSONObject returnObject = new JSONObject(); JSONArray
	 * args = new JSONArray(); // Variable[] args.put(this.mutationType);
	 * args.put(this.parentNodeValue); args.put(this.nodeName.replace("#", ""));
	 * args.put(this.nodeValue); return args == null ? null : args.toString(); /* try {
	 * returnObject.put("Mutation type", this.mutationType); returnObject.put("Node ID",
	 * this.parentNodeValue); // returnObject.put("nodeType", this.nodeType);
	 * returnObject.put("Type of value changed", this.nodeName.replace("#", ""));
	 * returnObject.put("Content changed", this.nodeValue); } catch (JSONException e) {
	 * e.printStackTrace(); } return returnObject; }
	 */
} public class TimeoutCallback extends TimingTrace/* implements EpisodeSource*/ {
	public TimeoutCallback() {
		super();
		setEpisodeSource(true);
	}
} public class TimeoutSet extends TimingTrace {
	private int delay;
	private JSONArray args = new JSONArray(); // Variable[]

	public int getDelay() {
		return delay;
	}

	public void setDelay(int delay) {
		this.delay = delay;
	}

	public String getArgs() {
		// return args;
		return args == null ? null : args.toString();
	}

	@JsonSetter("args")
	public void setArgs(String args_string) {
		try {
			this.args = new JSONArray("[" + args_string + "]");
		} catch (JSONException e) {
			System.out.println("Exception constructing JSONObject from string " + args_string);
			e.printStackTrace();
		}
	}
} public class TimingTrace extends TraceObject {
	private int timeoutId;
	private String callbackFunction;

	public int getTimeoutId() {
		return timeoutId;
	}
	public void setTimeoutId(int timeoutId) {
		this.timeoutId = timeoutId;
	}
	public String getCallbackFunction() {
		if (callbackFunction == "") {
			return "anonymous";
		} else {
			return callbackFunction;
		}
	}
	public void setCallbackFunction(String callbackFunction) {
		this.callbackFunction = callbackFunction;
	}	
} @JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="@class")
public class TraceObject implements Comparable<TraceObject> {
	private int id;
	private int counter;
	private String messageType;
	private long timeStamp;
	private boolean isEpisodeSource;
//	private boolean isBookmarked;
	
	public TraceObject() {
		isEpisodeSource = false;
//		isBookmarked = false;
	}
	
	public int getCounter() {
		return counter;
	}
	public void setCounter(int counter) {
		this.counter = counter;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getMessageType() {
		return messageType;
	}
	public void setMessageType(String messageType) {
		this.messageType = messageType;
	}
	public long getTimeStamp() {
		return timeStamp;
	}
	public void setTimeStamp(long timeStamp) {
		this.timeStamp = timeStamp;
	}
	public int compareTo(TraceObject o) {
		if (counter < o.getCounter())
			return -1;
		else if (counter > o.getCounter())
			return 1;
		return 0;
	}
	
	public boolean isEpisodeSource() {
		return isEpisodeSource;
	}
	
	public void setEpisodeSource(boolean isEpisodeSource) {
		this.isEpisodeSource = isEpisodeSource;
	}
/*
	public boolean getIsBookmarked() {
		return isBookmarked;
	}

	public void setIsBookmarked(boolean isBookmarked) {
		this.isBookmarked = isBookmarked;
	}
	*/
} public class XMLHttpRequestOpen extends XMLHttpRequestTrace {
	private String methodType;
	private String url;
	private boolean async;

	public String getUrl() {
		return url;
	}
	public void setUrl(String url) {
		this.url = url;
	}
	public String getMethodType() {
		return methodType;
	}
	public void setMethodType(String methodType) {
		this.methodType = methodType;
	}
	public boolean isAsync() {
		return async;
	}
	public void setAsync(boolean async) {
		this.async = async;
	}	
} public class XMLHttpRequestResponse extends XMLHttpRequestTrace/* implements EpisodeSource */{
	private String callbackFunction; // Function type ?
	private String response;

	public XMLHttpRequestResponse() {
		super();
		setEpisodeSource(true);
	}
	public String getCallbackFunction() {
		return callbackFunction;
	}
	public void setCallbackFunction(String callbackFunction) {
		this.callbackFunction = callbackFunction;
	}
	public String getResponse() {
		return response;
	}
	public void setResponse(String response) {
		this.response = response.replace("\n", "").replace("\r", "");
	}	
} public class XMLHttpRequestSend extends XMLHttpRequestTrace {
	private String message;

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}
} public class XMLHttpRequestTrace extends TraceObject {
	private int xhrId;
	
	public int getXhrId() {
		return xhrId;
	}

	public void setXhrId(int xhrId) {
		this.xhrId = xhrId;
	}	
}
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import javax.xml.bind.annotation.XmlRootElement;
import org.codehaus.jackson.annotate.JsonAutoDetect;
import org.codehaus.jackson.annotate.JsonSetter;
import com.clematis.core.trace.DOMElementValueTrace;
import com.clematis.core.trace.DOMEventTrace;
import com.clematis.core.trace.DOMMutationTrace;
import com.clematis.core.trace.TimeoutCallback;
import com.clematis.core.trace.TimeoutSet;
import com.clematis.core.trace.TimingTrace;
import com.clematis.core.trace.TraceObject;
import com.clematis.core.trace.XMLHttpRequestOpen;
import com.clematis.core.trace.XMLHttpRequestResponse;
import com.clematis.core.trace.XMLHttpRequestSend;
import com.clematis.core.trace.XMLHttpRequestTrace;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.annotation.JsonRootName;
package com.clematis.core.episode;





@JsonAutoDetect
@JsonRootName("Story")
@JsonPropertyOrder({ "domEventTraces", "functionTraces", "timingTraces", "xhrTraces",
        "orderedTraceList", "episodes",
        "timeoutSets", "timeoutCallbacks", "xhrOpens", "xhrSends", "xhrResponses", "domEvents",
        "domMutations", "domElementValues" })
@XmlRootElement
public class Story {
	private ArrayList<TraceObject> domEventTraces;
	private ArrayList<TraceObject> functionTraces;
	private ArrayList<TraceObject> timingTraces;
	private ArrayList<TraceObject> xhrTraces;
	private ArrayList<TraceObject> orderedTraceList;
	private ArrayList<Episode> episodes;

	private HashMap<Integer, TimeoutSet> timeoutSets; // by to_id
	private HashMap<Integer, TimeoutCallback> timeoutCallbacks;
	private HashMap<Integer, XMLHttpRequestOpen> xhrOpens;