Newer
Older
AlgebraicDataflowArchitectureModel / AlgebraicDataflowArchitectureModel / src / simulator / interfaces / html / HtmlPresenter.java
Sakoda2269 21 days ago 18 KB 検索機能が動くようにした
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);
				}
			}
		}
	}

}