package simulator.interfaces.html;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import models.algebra.Constant;
import models.algebra.Expression;
import models.algebra.InvalidMessage;
import models.algebra.ParameterizedIdentifierIsFutureWork;
import models.algebra.Term;
import models.algebra.UnificationFailed;
import models.algebra.ValueUndefined;
import models.dataConstraintModel.JsonTerm;
import models.dataConstraintModel.ListTerm;
import models.dataConstraintModel.MapTerm;
import models.dataConstraintModel.ResourcePath;
import models.dataFlowModel.DataTransferChannel;
import models.dataFlowModel.ResolvingMultipleDefinitionIsFutureWork;
import parser.Parser;
import parser.Parser.TokenStream;
import parser.exceptions.ExpectedColon;
import parser.exceptions.ExpectedDoubleQuotation;
import parser.exceptions.ExpectedRightBracket;
import parser.exceptions.WrongJsonExpression;
import simulator.Event;
import simulator.Resource;
import simulator.ResourceIdentifier;
import simulator.Simulator;
import simulator.SystemState;
import simulator.interfaces.INativeReceiver;
public class HtmlPresenter implements INativeReceiver{
public final String screenUpdateChannelName = "ScreenUpdate";
public final String screenTemplateUpdateChannelName = "ScreenTemplateUpdate";
public final String setVisibleChannelName = "SetVisible";
public final String setTextChannelName = "SetText";
public final String setTableChannelName = "OnTableChanged";
public final String setTableChannelName2 = "OnTableChanged2";
public final String mouseEventChannelName = "MouseEvent";
public final String textEventChannelName = "TextEvent";
protected Simulator simulator;
protected DataTransferChannel screenUpdateChannel;
protected DataTransferChannel screenTemplateUpdateChannel;
protected DataTransferChannel setVisibleChannel;
protected DataTransferChannel mouseEventChannel;
protected DataTransferChannel textEventChannel;
protected DataTransferChannel setTextChannel;
protected DataTransferChannel setTableChannel;
protected DataTransferChannel setTableChannel2;
protected Map<DataTransferChannel, Map<String, Resource>> channelAndResourcesForReceiving = new HashMap<>();
protected Map<String, HtmlElement> elements;
protected IWebSocketMessageSender ws;
private final String sessionId;
public HtmlPresenter(Simulator simulator, IWebSocketMessageSender ws, Map<String, HtmlElement> elems, String sessionId) {
this.simulator = simulator;
this.ws = ws;
this.sessionId = sessionId;
screenUpdateChannel = (DataTransferChannel) simulator.getModel().getChannel(screenUpdateChannelName);
screenTemplateUpdateChannel = (DataTransferChannel) simulator.getModel().getChannel(screenTemplateUpdateChannelName);
setVisibleChannel = (DataTransferChannel) simulator.getModel().getChannel(setVisibleChannelName);
mouseEventChannel = (DataTransferChannel) simulator.getModel().getInputChannel(mouseEventChannelName);
setTextChannel = (DataTransferChannel) simulator.getModel().getChannel(setTextChannelName);
textEventChannel = (DataTransferChannel) simulator.getModel().getInputChannel(textEventChannelName);
setTableChannel = (DataTransferChannel) simulator.getModel().getChannel(setTableChannelName);
setTableChannel2 = (DataTransferChannel) simulator.getModel().getChannel(setTableChannelName2);
simulator.addNativeReceiver(this, screenUpdateChannel);
elements = elems;
initScreen();
}
private void initScreen() {
Constant curScreenExp = (Constant) (simulator.getCurState().getResource("curScreen").getState().getValue());
DataTransferChannel channel = (DataTransferChannel) simulator.getModel().getInputChannel("ChangeCurScreen");
TokenStream stream = new Parser.TokenStream();
Parser parser = new Parser(stream);
stream.addLine("changeCurScreen(" + curScreenExp.toString() + ")");
try {
Expression eventMessage = parser.parseTerm(stream,simulator.getModel());
ResourcePath resPath = simulator.getModel().getResourcePath("curScreen");
Event event = new Event(channel, eventMessage, resPath, simulator.getCurState().getResource("curScreen"));
simulator.transition(event);
} catch (ExpectedRightBracket | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation | ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork | InvalidMessage | UnificationFailed | ValueUndefined e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
}
}
@Override
public void onReceiveFromModel(Event event, SystemState nextSystemState) {
//画面遷移するときに呼ばれそう
Expression message = event.getMessage();
if (message instanceof Term && ((Term) message).getChildren().size() >= 2) {
Expression curScExp = ((Term) message).getChild(0);
Expression nextScExp = ((Term) message).getChild(1);
if (curScExp instanceof JsonTerm && nextScExp instanceof JsonTerm) {
JsonTerm sendData = new JsonTerm();
sendData.addMember("method", new Constant("\"updateHtml\""));
JsonTerm sendElements = new JsonTerm();
ListTerm addElements = new ListTerm();
ListTerm delElements = new ListTerm();
JsonTerm curSc = (JsonTerm) curScExp;
JsonTerm nextSc = (JsonTerm) nextScExp;
Expression oldWidgets = curSc.get("widgets");
Expression newWidgets = nextSc.get("widgets");
String nextScId = nextSc.get("screenId").toString();
nextScId = nextScId.substring(1, nextScId.length() - 1);
if (oldWidgets instanceof MapTerm && newWidgets instanceof MapTerm) {
Set<String> oldWidSet = new HashSet<>(((MapTerm) oldWidgets).keySet());
Set<String> newWidSet = new HashSet<>(((MapTerm) newWidgets).keySet());
oldWidSet.removeAll(((MapTerm) newWidgets).keySet());
newWidSet.removeAll(((MapTerm)oldWidgets).keySet());
if(!oldWidSet.isEmpty()) {
deleteOldWidgets(oldWidSet, delElements);
}
if (!newWidSet.isEmpty()) {
nextSystemState.getResource("screenTemplates").getChildrenMap().get(nextScId).getResourceIdentifier();
addNewWidgets(newWidSet, nextSystemState, event.getInputResource().getResourceIdentifier(), newWidgets, addElements, nextSystemState.getResource("screenTemplates").getChildrenMap().get(nextScId).getResourceIdentifier());
}
}
sendElements.addMember("add", addElements);
// sendElements.addMember("delete", delElements);
sendData.addMember("data", sendElements);
ws.send(sendData.toString(), sessionId);
}
}
}
private void addNewWidgets(Set<String> newWidSet, Resource screenResource, Expression newWidgets, ListTerm addElements, Resource screenTemplateResource) {
Resource widgetsResource = screenResource.getChildrenMap().get("widgets");
for(String newWid: newWidSet) {
Expression value = ((MapTerm) newWidgets).get(newWid);
if(value instanceof JsonTerm) {
JsonTerm widget = (JsonTerm) value;
Resource widgetResource = widgetsResource.getChildrenMap().get(newWid);
Expression type = widget.get("type");
switch(type.toString()) {
case "\"button\"":
addButton(widget, newWid, addElements, widgetResource);
break;
case "\"label\"":
addLabel(widget, newWid, addElements, widgetResource);
break;
case "\"textInput\"":
addTextInput(widget, newWid, addElements, widgetResource);
break;
case "\"table\"":
addTable(widget, newWid, addElements, screenTemplateResource.getChildrenMap().get("widgets").getChildrenMap().get(newWid), widgetResource);
break;
}
}
}
}
private void addNewWidgets(Set<String> newWidSet, SystemState nextSystemState, ResourceIdentifier ri, Expression newWidgets, ListTerm addElements, ResourceIdentifier screenIdentifier) {
Resource screenResource = nextSystemState.getResource(ri);
Resource screenTemplateResource = nextSystemState.getResource(screenIdentifier);
addNewWidgets(newWidSet, screenResource, newWidgets, addElements, screenTemplateResource);
}
private void addButton(JsonTerm widget, String wid, ListTerm addElements, Resource widgetResource) {
String text = widget.get("text").toString();
HtmlElement button = new HtmlElement("button", wid, text);
Set<String> keySet = widget.keySet();
button.setStyle("position", "absolute");
if(keySet.contains("x")) {
button.setStyle("left", "" + widget.get("x") + "px");
}
if(keySet.contains("y")) {
button.setStyle("top", "" + widget.get("y") + "px");
}
if(keySet.contains("width")) {
button.setStyle("width", "" + widget.get("width") + "px");
}
if(keySet.contains("height")) {
button.setStyle("height", "" + widget.get("height") + "px");
}
//ボタンが押されたり離されたりした時を検知
ResourcePath resPath = mouseEventChannel.getOutputResources().iterator().next();
button.setRestEventListener(new HtmlElementMouseSender(simulator, mouseEventChannel, resPath, widgetResource));
//ボタンが透明になったことを通知
HtmlElementVisibilityReceiver nativeVisibilityReceiver = new HtmlElementVisibilityReceiver(button, ws, sessionId);
simulator.addNativeReceiver(nativeVisibilityReceiver, setVisibleChannel, widgetResource.getChildrenMap().get("visible"));
Map<String, Resource> resources = channelAndResourcesForReceiving.get(setVisibleChannel);
if (resources == null) {
resources = new HashMap<>();
channelAndResourcesForReceiving.put(setVisibleChannel, resources);
}
resources.put(wid, widgetResource);
//ボタンの文字が変わったことを通知
HtmlElementTextReceiver nativeTextReceiver = new HtmlElementTextReceiver(button, ws, sessionId);
simulator.addNativeReceiver(nativeTextReceiver, setTextChannel, widgetResource.getChildrenMap().get("text"));
resources = channelAndResourcesForReceiving.get(setTextChannel);
if (resources == null) {
resources = new HashMap<>();
channelAndResourcesForReceiving.put(setTextChannel, resources);
}
resources.put(wid, widgetResource);
elements.put(wid, button);
addElements.append(button.toMap());
}
private void addLabel(JsonTerm widget, String wid, ListTerm addElements, Resource widgetResource) {
String text = widget.get("text").toString();
HtmlElement label = new HtmlElement("label", wid, text);
Set<String> keySet = widget.keySet();
label.setStyle("position", "absolute");
if(keySet.contains("x")) {
label.setStyle("left", "" + widget.get("x") + "px");
}
if(keySet.contains("y")) {
label.setStyle("top", "" + widget.get("y") + "px");
}
if(keySet.contains("width")) {
label.setStyle("width", "" + widget.get("width") + "px");
}
if(keySet.contains("height")) {
label.setStyle("height", "" + widget.get("height") + "px");
}
//ラベルが透明になったことを通知
HtmlElementVisibilityReceiver nativeVisibilityReceiver = new HtmlElementVisibilityReceiver(label, ws, sessionId);
simulator.addNativeReceiver(nativeVisibilityReceiver, setVisibleChannel, widgetResource);
Map<String, Resource> resources = channelAndResourcesForReceiving.get(setVisibleChannel);
if (resources == null) {
resources = new HashMap<>();
channelAndResourcesForReceiving.put(setVisibleChannel, resources);
}
resources.put(wid, widgetResource);
//ラベルの文字が変わったことを通知
HtmlElementTextReceiver nativeTextReceiver = new HtmlElementTextReceiver(label, ws, sessionId);
simulator.addNativeReceiver(nativeTextReceiver, setTextChannel, widgetResource.getChildrenMap().get("text"));
resources = channelAndResourcesForReceiving.get(setTextChannel);
if (resources == null) {
resources = new HashMap<>();
channelAndResourcesForReceiving.put(setTextChannel, resources);
}
resources.put(wid, widgetResource);
elements.put(wid, label);
addElements.append(label.toMap());
}
private void addTextInput(JsonTerm widget, String wid, ListTerm addElements, Resource widgetResource) {
String text = widget.get("text").toString();
HtmlElement textInput = new HtmlElement("textInput", wid, text);
Set<String> keySet = widget.keySet();
textInput.setStyle("position", "absolute");
if(keySet.contains("x")) {
textInput.setStyle("left", "" + widget.get("x") + "px");
}
if(keySet.contains("y")) {
textInput.setStyle("top", "" + widget.get("y") + "px");
}
if(keySet.contains("width")) {
textInput.setStyle("width", "" + widget.get("width") + "px");
}
if(keySet.contains("height")) {
textInput.setStyle("height", "" + widget.get("height") + "px");
}
//文字の変更を検知
ResourcePath resPath = textEventChannel.getOutputResources().iterator().next();
textInput.setRestEventListener(new HtmlElementTextSender(simulator, textEventChannel, resPath, widgetResource));
//ボタンが透明になったことを通知
HtmlElementVisibilityReceiver nativeVisibilityReceiver = new HtmlElementVisibilityReceiver(textInput, ws, sessionId);
simulator.addNativeReceiver(nativeVisibilityReceiver, setVisibleChannel, widgetResource);
Map<String, Resource> resources = channelAndResourcesForReceiving.get(setVisibleChannel);
if (resources == null) {
resources = new HashMap<>();
channelAndResourcesForReceiving.put(setVisibleChannel, resources);
}
resources.put(wid, widgetResource);
//ボタンの文字が変わったことを通知
HtmlElementTextReceiver nativeTextReceiver = new HtmlElementTextReceiver(textInput, ws, sessionId);
simulator.addNativeReceiver(nativeTextReceiver, setTextChannel, widgetResource);
resources = channelAndResourcesForReceiving.get(setTextChannel);
if (resources == null) {
resources = new HashMap<>();
channelAndResourcesForReceiving.put(setTextChannel, resources);
}
resources.put(wid, widgetResource);
elements.put(wid, textInput);
addElements.append(textInput.toMap());
}
private void addTable(JsonTerm widget, String wid, ListTerm addElements, Resource widgetResource, Resource widgetResource2) {
String text = widget.get("text").toString();
HtmlElement table = new HtmlElement("table", wid, text);
Set<String> keySet = widget.keySet();
table.setStyle("position", "absolute");
if(keySet.contains("x")) {
table.setStyle("left", "" + widget.get("x") + "px");
}
if(keySet.contains("y")) {
table.setStyle("top", "" + widget.get("y") + "px");
}
if(keySet.contains("width")) {
table.setStyle("width", "" + widget.get("width") + "px");
}
if(keySet.contains("height")) {
table.setStyle("height", "" + widget.get("height") + "px");
}
MapTerm data = (MapTerm)widget.get("data");
ListTerm columnsList = (ListTerm)widget.get("columns");
Constant rowNumExp = (Constant)widget.get("rowNum");
Constant rowHeightExp = (Constant)widget.get("rowHeight");
Constant primaryKeyNameExp = (Constant) widget.get("primaryKeyName");
boolean primaryKeyVisible = !primaryKeyNameExp.getValue().equals("");
int colNum = columnsList.size() + (primaryKeyVisible ? 1 : 0);
String[] columns = new String[colNum];
String[][] tableDatas = new String[data.keySet().size()][colNum];
if(primaryKeyVisible) {
columns[0] = (String)primaryKeyNameExp.getValue();
for(int i = 1; i < colNum; i++) {
columns[i] = (String)((Constant)columnsList.get(i - 1)).getValue();
}
} else {
for(int i = 0; i < colNum; i++) {
columns[i] = (String)((Constant)columnsList.get(i)).getValue();
}
}
int dataCount = 0;
for(String dataKey : data.keySet()) {
JsonTerm rowData = (JsonTerm) data.get(dataKey);
if(primaryKeyVisible) {
tableDatas[dataCount][0] = dataKey;
for(int j = 1; j < columns.length; j++) {
Constant cellValue = (Constant) rowData.get(columns[j]);
if(cellValue == null) {
tableDatas[dataCount][j] = "error";
} else {
tableDatas[dataCount][j] = (String)((Constant) rowData.get(columns[j])).getValue();
}
}
} else {
for(int j = 0; j < columns.length; j++) {
Constant cellValue = (Constant) rowData.get(columns[j]);
if(cellValue == null) {
tableDatas[dataCount][j] = "error";
} else {
tableDatas[dataCount][j] = (String)((Constant) rowData.get(columns[j])).getValue();
}
}
}
dataCount++;
}
JsonTerm tableDataJson = new JsonTerm();
ListTerm columnsList2 = new ListTerm();
for(String col: columns) {
columnsList2.addChild(new Constant("\""+ col + "\""));
}
tableDataJson.addMember("columns", columnsList2);
ListTerm tableRows = new ListTerm();
for(String[] row: tableDatas) {
ListTerm rowList = new ListTerm();
for(String cell: row) {
rowList.addChild(new Constant("\"" + cell + "\""));
}
tableRows.addChild(rowList);
}
tableDataJson.addMember("rows", tableRows);
table.setData(tableDataJson);
//ボタンが押されたり離されたりした時を検知
ResourcePath resPath = mouseEventChannel.getOutputResources().iterator().next();
table.setRestEventListener(new HtmlElementMouseSender(simulator, mouseEventChannel, resPath, widgetResource));
//ボタンが透明になったことを通知
HtmlElementVisibilityReceiver nativeVisibilityReceiver = new HtmlElementVisibilityReceiver(table, ws, sessionId);
simulator.addNativeReceiver(nativeVisibilityReceiver, setVisibleChannel, widgetResource.getChildrenMap().get("visible"));
Map<String, Resource> resources = channelAndResourcesForReceiving.get(setVisibleChannel);
if (resources == null) {
resources = new HashMap<>();
channelAndResourcesForReceiving.put(setVisibleChannel, resources);
}
resources.put(wid, widgetResource);
//ボタンの文字が変わったことを通知
HtmlElementTextReceiver nativeTextReceiver = new HtmlElementTextReceiver(table, ws, sessionId);
simulator.addNativeReceiver(nativeTextReceiver, setTextChannel, widgetResource.getChildrenMap().get("text"));
resources = channelAndResourcesForReceiving.get(setTextChannel);
if (resources == null) {
resources = new HashMap<>();
channelAndResourcesForReceiving.put(setTextChannel, resources);
}
resources.put(wid, widgetResource);
//テーブルのデータが変更されたことを通知
HtmlElementTableReceiver nativeTableReceiver = new HtmlElementTableReceiver(table, ws, sessionId);
simulator.addNativeReceiver(nativeTableReceiver, setTableChannel, widgetResource.getChildrenMap().get("data"));
simulator.addNativeReceiver(nativeTableReceiver, setTableChannel2, widgetResource2.getChildrenMap().get("data"));
resources = channelAndResourcesForReceiving.get(setTableChannel);
if (resources == null) {
resources = new HashMap<>();
channelAndResourcesForReceiving.put(setTableChannel, resources);
}
resources.put(wid, widgetResource);
elements.put(wid, table);
addElements.append(table.toMap());
}
private void deleteOldWidgets(Set<String> oldWidSet, ListTerm delElements) {
for (String oldWid : oldWidSet) {
elements.remove(oldWid);
//TODO
// del widgets
delElements.append(new Constant(oldWid));
}
for (DataTransferChannel channel : channelAndResourcesForReceiving.keySet()) {
Map<String, Resource> widToResource = channelAndResourcesForReceiving.get(channel);
for (String oldWid: oldWidSet) {
Resource resource = widToResource.remove(oldWid);
if (resource != null) {
simulator.removeNativeReceiver(channel, resource);
}
}
}
}
}