package com.example.test.dtram;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.HashMap;
import java.util.Map;

import org.springframework.stereotype.Component;

import com.example.test.pojo.Layout;

import algorithms.TypeInference;
import models.algebra.Expression;
import models.algebra.Variable;
import models.dataConstraintModel.ChannelMember;
import models.dataConstraintModel.JsonTerm;
import models.dataConstraintModel.ResourcePath;
import models.dataFlowModel.DataTransferChannel;
import models.dataFlowModel.DataTransferModel;
import parser.Parser;
import parser.Parser.TokenStream;
import parser.exceptions.ExpectedColon;
import parser.exceptions.ExpectedRightBracket;
import parser.exceptions.WrongJsonExpression;
import simulator.Simulator;
import simulator.interfaces.html.HtmlElement;
import simulator.interfaces.html.HtmlPresenter;
import simulator.interfaces.html.IWebSocketMessageSender;

@Component
public class Dtram {
	
	File file;
	DataTransferModel model;
	Simulator simulator;
	
	private final IWebSocketMessageSender ws;
	
	private Map<String, HtmlElement> elements;
	
	HtmlPresenter presenter;
	
	Dtram(IWebSocketMessageSender ws){
		this.ws = ws;
		elements = new HashMap<>();
	}
	
	public void initModel(String path) {
		file = new File(path);
		System.out.println(path);
		try {
			Parser parser = new Parser(new BufferedReader(new FileReader(file)));
			model  = parser.doParse();
			model.getInputChannel("Init");
		}catch(Exception e) {
			
		}
	}
	
	public void constructModel(Layout l) {
		try {

			TokenStream stream = new Parser.TokenStream();
			Parser parser = new Parser(stream);
			
			model = new DataTransferModel();
			ResourcePath screen = new ResourcePath("screen");
			ResourcePath widgets = new ResourcePath(screen, "widgets");
			ResourcePath widget = new ResourcePath(widgets, new Variable("wid"));
			ResourcePath type = new ResourcePath(widget, "type");
			ResourcePath text = new ResourcePath(widget, "text");
			ResourcePath id = new ResourcePath(widget, "id");
			ResourcePath state = new ResourcePath(widget, "state");
			ResourcePath visible = new ResourcePath(widget, "visible");
			ResourcePath x = new ResourcePath(widget, "x");
			ResourcePath y = new ResourcePath(widget, "y");
			ResourcePath w = new ResourcePath(widget, "w");
			ResourcePath h = new ResourcePath(widget, "h");
			
			model.addResourcePath(screen);
			model.addResourcePath(widgets);
			model.addResourcePath(widget);
			model.addResourcePath(type);
			model.addResourcePath(id);
			model.addResourcePath(text);
			model.addResourcePath(state);
			model.addResourcePath(visible);
			model.addResourcePath(x);
			model.addResourcePath(y);
			model.addResourcePath(w);
			model.addResourcePath(h);
//			JsonTerm elements = new JsonTerm();
//			for(Element element : l.getElements()) {
//				JsonTerm elem = new JsonTerm();
//				elem.addMember("type", new Constant(element.getType()));
//				elem.addMember("id", new Constant(element.getId()));
//				elem.addMember("text", new Constant(element.getText()));
//				elements.addMember(element.getId(), elem);
//			}
//			widgets.getResourceHierarchy().setInitialValue(elements);
			
			addNativeOutputChannel(stream, parser, screen, "ScreenUpdate", "curSc: Json", "update(curSc, nextSc)", "nextSc");
			addNativeOutputChannel(stream, parser, visible, "SetVisible", "curVisible: Bool", "setVisible(nextVisible)", "nextVisible");
			addNativeOutputChannel(stream, parser, text, "SetText", "curText: Str", "setText(nextText)", "nextText");
			addNativeInputChannel(stream, parser, state, "MouseEvent", "curState: Int", "mouseEvent(nextState)", "nextState");
			addNativeInputChannel(stream, parser, text, "MouseEvent", "curText: Str", "textEvent(nextText)", "nextText");
			
			TypeInference.infer(model);
			
			
			
		} catch (Exception e) {
			// TODO 自動生成された catch ブロック
			e.printStackTrace();
		}
		
	}
	
	private void addNativeOutputChannel(TokenStream stream, Parser parser, ResourcePath path, 
			String channelName, String curStateName, String messageName, String nextStateName) throws ExpectedRightBracket, WrongJsonExpression, ExpectedColon {
		DataTransferChannel outputChannel = new DataTransferChannel(channelName);
		outputChannel.setNative(true);
		ChannelMember out = new ChannelMember(path);
		stream.addLine(curStateName);
		Expression curState = parser.parseTerm(stream, model);
		stream.addLine(messageName);
		Expression message = parser.parseTerm(stream, model);
		stream.addLine(nextStateName);
		Expression nextState = parser.parseTerm(stream, model);
		out.getStateTransition().setCurStateExpression(curState);
		out.getStateTransition().setMessageExpression(message);
		out.getStateTransition().setNextStateExpression(nextState);
		outputChannel.addChannelMemberAsInput(out);
		model.addChannel(outputChannel);
	}
	
	private void addNativeInputChannel(TokenStream stream, Parser parser, ResourcePath path, 
			String channelName, String curStateName, String messageName, String nextStateName) throws ExpectedRightBracket, WrongJsonExpression, ExpectedColon {
		DataTransferChannel inputChannel = new DataTransferChannel(channelName);
		inputChannel.setNative(true);
		ChannelMember in = new ChannelMember(path);
		stream.addLine(curStateName);
		Expression curState = parser.parseTerm(stream, model);
		stream.addLine(messageName);
		Expression message = parser.parseTerm(stream, model);
		stream.addLine(nextStateName);
		Expression nextState = parser.parseTerm(stream, model);
		in.getStateTransition().setCurStateExpression(curState);
		in.getStateTransition().setMessageExpression(message);
		in.getStateTransition().setNextStateExpression(nextState);
		inputChannel.addChannelMemberAsOutput(in);
		model.addInputChannel(inputChannel);
	}
	
	public void startSimulator() {
		simulator = new Simulator(model);
		simulator.init();
		presenter = new HtmlPresenter(simulator, ws, elements);
		System.out.println(simulator.getCurState().getResource("screen.widgets"));
	}
	
	public void onRestEvent(String id, String method, JsonTerm message) {
		elements.get("\"" + id + "\"").onRestEvent(method, message);
	}
	
	
	
	
}
