package framework.scenario;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Set;
import java.util.Map.Entry;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.helpers.DefaultHandler;
public class ScenarioManager {
private IWorld realWorld;
private Hashtable<String, ScenarioFSM> stateMachines = new Hashtable<String, ScenarioFSM>();
private Hashtable<String, ScenarioState> allStates = new Hashtable<String, ScenarioState>();
private Hashtable<String, Event> allEvents = new Hashtable<String, Event>();
public ScenarioManager(String xmlFileName, IWorld realWorld) {
this.realWorld = realWorld;
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(true);
factory.setAttribute(
"http://java.sun.com/xml/jaxp/properties/schemaLanguage",
"http://www.w3.org/2001/XMLSchema");
DocumentBuilder builder = factory.newDocumentBuilder();
builder.setErrorHandler(new DefaultHandler());
Document document = builder.parse(xmlFileName);
// 有限状態マシンの作成、状態の登録、イベントの登録
Hashtable<ScenarioState, NodeList> allTrans = new Hashtable<ScenarioState, NodeList>();
NodeList scenario = document.getChildNodes();
NodeList fsmNodes = scenario.item(0).getChildNodes();
for (int n = 0; n < fsmNodes.getLength(); n++) {
Node fsmNode = fsmNodes.item(n);
if (fsmNode.getNodeName().equals("FSM")) {
Hashtable<String, State> fsmStates = new Hashtable<String, State>();
NodeList stateNodes = fsmNode.getChildNodes();
for (int m = 0; m < stateNodes.getLength(); m++) {
Node stateNode = stateNodes.item(m);
if (stateNode.getNodeName().equals("State")) {
ScenarioState state = new ScenarioState();
String stateName = stateNode.getAttributes().getNamedItem("name").getNodeValue();
fsmStates.put(stateName, state);
allStates.put(stateName, state);
Node stateMessageNode = stateNode.getAttributes().getNamedItem("message");
if (stateMessageNode != null) state.setMessage(stateMessageNode.getNodeValue());
NodeList eventNodes = stateNode.getChildNodes();
allTrans.put(state, eventNodes);
for (int l = 0; l < eventNodes.getLength(); l++) {
Node eventNode = eventNodes.item(l);
if (eventNode.getNodeName().equals("Event")) {
String eventName = eventNode.getAttributes().getNamedItem("name").getNodeValue();
Event e = allEvents.get(eventName);
if (e == null) {
e = new Event(eventName);
allEvents.put(eventName, e);
}
}
}
}
}
String initialStateName = fsmNode.getAttributes().getNamedItem("initial").getNodeValue();
State initialState = fsmStates.get(initialStateName);
ScenarioFSM fsm = new ScenarioFSM(initialState, fsmStates, this);
String fsmName = fsmNode.getAttributes().getNamedItem("name").getNodeValue();
stateMachines.put(fsmName, fsm);
}
}
// 状態遷移を設定する
Set<Entry<ScenarioState, NodeList>> allTransEntries = allTrans.entrySet();
Iterator<Entry<ScenarioState, NodeList>> it = allTransEntries.iterator();
while (it.hasNext()) {
Entry<ScenarioState, NodeList> transEntry = it.next();
ScenarioState state = transEntry.getKey();
NodeList eventNodes = transEntry.getValue();
for (int l = 0; l < eventNodes.getLength(); l++) {
Node eventNode = eventNodes.item(l);
if (eventNode.getNodeName().equals("Event")) {
Node eventNameNode = eventNode.getAttributes().getNamedItem("name");
Event e = null;
if (eventNameNode != null) {
String eventName = eventNameNode.getNodeValue();
e = allEvents.get(eventName);
}
Node nextStateNameNode = eventNode.getAttributes().getNamedItem("trans");
State nextState = null;
if (nextStateNameNode != null) {
String nextStateName = nextStateNameNode.getNodeValue();
nextState = allStates.get(nextStateName);
}
Node syncEventNameNode = eventNode.getAttributes().getNamedItem("sync");
Event syncEvent = null;
if (syncEventNameNode != null) {
String syncEventName = syncEventNameNode.getNodeValue();
syncEvent = allEvents.get(syncEventName);
}
ArrayList<State> guards = new ArrayList<State>();
Node guardStateNameNode = eventNode.getAttributes().getNamedItem("guard");
if (guardStateNameNode != null) {
String guardStateName = guardStateNameNode.getNodeValue();
State guardState = allStates.get(guardStateName);
if (guardState != null) guards.add(guardState);
}
Node guardStateNameNode2 = eventNode.getAttributes().getNamedItem("guard2");
if (guardStateNameNode2 != null) {
String guardStateName2 = guardStateNameNode2.getNodeValue();
State guardState2 = allStates.get(guardStateName2);
if (guardState2 != null) guards.add(guardState2);
}
Node guardStateNameNode3 = eventNode.getAttributes().getNamedItem("guard3");
if (guardStateNameNode3 != null) {
String guardStateName3 = guardStateNameNode3.getNodeValue();
State guardState3 = allStates.get(guardStateName3);
if (guardState3 != null) guards.add(guardState3);
}
Node actionNameNode = eventNode.getAttributes().getNamedItem("action");
ScenarioAction action = null;
if (actionNameNode != null) {
String actionName = actionNameNode.getNodeValue();
action = new ScenarioAction(actionName);
}
state.addTransition(e, nextState, syncEvent, guards, action);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void fire(Event e){
Collection<ScenarioFSM> fsms = stateMachines.values();
Iterator<ScenarioFSM> it = fsms.iterator();
while (it.hasNext()) {
ScenarioFSM fsm = it.next();
fsm.trans(e);
}
}
public void fire(String eventName) {
Event e = allEvents.get(eventName);
if (e == null) return;
fire(e);
}
public void action(ScenarioAction action, Event event, ScenarioState nextState) {
if (action != null) {
String sAction = action.getName();
if (sAction.equals("openDialog")) {
realWorld.dialogOpen();
} else if (sAction.equals("closeDialog")) {
realWorld.dialogClose();
} else if (sAction.equals("print")) {
System.out.println(event.getName());
}
realWorld.action(sAction, event, nextState);
}
if (realWorld.isDialogOpen()) {
String message = nextState.getMessage();
if (message != null) {
realWorld.dialogMessage(message);
Enumeration<Event> events = nextState.getEvents();
int n = 0;
while (events.hasMoreElements()) {
Event ev = events.nextElement();
realWorld.showOption(n, ev.getName());
n++;
}
}
}
}
}