package no.hal.scxml.generator;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import no.hal.scxml.emf.javascript.EmfJavascriptEvaluator;
import no.hal.scxml.scxmlxt.State;
import no.hal.scxml.scxmlxt.StateMachine;
import org.apache.commons.scxml.Context;
import org.apache.commons.scxml.Evaluator;
import org.apache.commons.scxml.TriggerEvent;
import org.apache.commons.scxml.env.SimpleErrorReporter;
import org.apache.commons.scxml.env.SimpleScheduler;
import org.apache.commons.scxml.io.SCXMLParser;
import org.apache.commons.scxml.io.SCXMLSerializer;
import org.apache.commons.scxml.model.ModelException;
import org.apache.commons.scxml.model.SCXML;
import org.apache.commons.scxml.model.TransitionTarget;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.js4emf.ecore.JavascriptSupport;
import org.eclipse.emf.js4emf.ecore.JavascriptSupportFactory;
public class ScxmlRunner {
private ScriptEventManager scriptEventManager;
private ResourceSet resourceSet;
public ScxmlRunner(ResourceSet resourceSet) {
this.resourceSet = resourceSet;
}
private ScxmlxtGenerator scxmlxtGenerator;
private ScxmlGenerator scxmlGenerator;
private StateMachine stateMachine;
private SCXML scxml;
public void init(EObject model, URI scxmlBaseUri) throws ModelException {
scxmlxtGenerator = new ScxmlxtGenerator(model, scxmlBaseUri);
stateMachine = scxmlxtGenerator.generateScxmlxt();
scxmlGenerator = new ScxmlGenerator();
scxmlGenerator.getRootVariables().putAll(scxmlxtGenerator.getRootVariables());
scxml = scxmlGenerator.generateScxml(stateMachine);
TransitionTarget startState = (TransitionTarget)scxml.getTargets().get(scxml.getInitial());
scriptEventManager = new ScriptEventManager(scxmlGenerator.getScriptEventHandlers());
scxmlGenerator.getOnEntry(startState).addAction(scriptEventManager.getInitAction());
System.out.println(SCXMLSerializer.serialize(scxml));
SCXMLParser.updateSCXML(scxml);
}
public StateMachine getStateMachine() {
return stateMachine;
}
public SCXML getSCXML() {
return scxml;
}
private JavascriptSupport javascriptSupport;
public void setJavascriptSupport(JavascriptSupport javascriptSupport) {
this.javascriptSupport = javascriptSupport;
}
private ScxmlEventQueueExecutor executor = null;
public void start() {
try {
if (javascriptSupport == null) {
javascriptSupport = JavascriptSupportFactory.getInstance().createJavascriptSupport();
}
Evaluator evaluator = new EmfJavascriptEvaluator(resourceSet, javascriptSupport);
executor = new ScxmlEventQueueExecutor(evaluator, new SimpleErrorReporter()) {
@Override
public synchronized void triggerEvents(TriggerEvent[] events) throws ModelException {
EList<State> currentStates = ScxmlRunner.this.getStateMachine().getCurrentStates();
currentStates.clear();
try {
super.triggerEvents(events);
} finally {
Iterator<?> states = getCurrentStatus().getStates().iterator();
while (states.hasNext()) {
org.apache.commons.scxml.model.State state = (org.apache.commons.scxml.model.State)states.next();
Object scxmlxtObject = scxmlGenerator.getScxmlxtObject(state);
if (scxmlxtObject instanceof State) {
currentStates.add((State)scxmlxtObject);
}
}
}
}
};
executor.setEventdispatcher(new SimpleScheduler(executor));
for (Map.Entry<String, Object> entry: scxmlGenerator.getRootVariables().entrySet()) {
executor.getRootContext().setLocal(entry.getKey(), entry.getValue());
}
executor.setStateMachine(scxml);
executor.addListener(scxml, scriptEventManager);
executor.go();
} catch (Exception e) {
System.err.println("Exception when starting state machine: " + e);
}
}
public void pause() {
executor.pause();
}
public void resume() {
try {
executor.resume();
} catch (Exception e) {
System.err.println("Exception when resuming state machine: " + e);
}
}
public boolean stateCheck(String stateId, boolean expected, boolean def) {
for (TransitionTarget state: ((Set<TransitionTarget>)executor.getCurrentStatus().getStates())) {
while (state!= null) {
if (stateId.equals(state.getId())) {
if (expected) {
return true;
}
}
state = state.getParent();
}
}
return def;
}
public TransitionTarget getState(String stateId) {
return scxmlGenerator.getState(stateId);
}
public EObject getEObject(TransitionTarget state) {
Context scope = scriptEventManager.getScInstance().getContext(state);
while (scope != null) {
for (Map.Entry<String, Object> varEntry: ((Map<String, Object>)scope.getVars()).entrySet()) {
String name = varEntry.getKey();
if (name.startsWith("this")) {
Object value = varEntry.getValue();
if (value instanceof EObject) {
EObject eObject = (EObject)value;
if (scxmlxtGenerator.isEObjectVariableName(name, eObject)) {
return eObject;
}
}
}
}
scope = scope.getParent();
}
return null;
}
}