/*
 * This file has been developed at the University of Munich, Chair for Programming & Software Engineering.
 * 
 * This file is licensed under the Eclipse Public License (EPL) 1.0
 * 
 */
package eu.uml4soa.utbm.ui.md;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

import com.nomagic.magicdraw.core.Application;
import com.nomagic.task.ProgressStatus;
import com.nomagic.task.RunnableWithProgress;

import eu.uml4soa.utbm.ui.md.api.ServerClientConstants;

public class UML4SOAServerSemanticsWorker implements RunnableWithProgress {

	public enum ResultType {
		NOT_CHECKED, ERROR, CHECK_OKAY, CHECK_WRONG
	};

	public enum Side {
		LEFT, RIGHT
	}

	public static class Result {

		private ResultType fResultType;

		private String fMessage;

		private Side fProblematicAutomaton;

		private String fProblematicTransition;

		private String fStateLeft;

		private String fStateRight;

		public Result(ResultType type, String message) {
			fResultType= type;
			fMessage= message;
		}

		public ResultType getResultType() {
			return fResultType;
		}

		public String getMessage() {
			return fMessage;
		}

		public void setProblematicAutomaton(Side left) {
			fProblematicAutomaton= left;
		}


		public void setProblematicTransition(String transition) {
			fProblematicTransition= transition;
		}

		public Side getProblematicAutomaton() {
			return fProblematicAutomaton;
		}


		public String getProblematicTransition() {
			return fProblematicTransition;
		}

		public void setProblematicStateLeft(String state1) {
			fStateLeft= state1;
		}

		public String getStateLeft() {
			return fStateLeft;
		}

		public void setProblematicStateRight(String state2) {
			fStateRight= state2;
		}

		public String getStateRight() {
			return fStateRight;
		}

	}

	// INPUT:

	private String fMessage;

	private String fLeftID;

	private String fRightID;

	// OUTPUT:

	private Result fResult;

	public UML4SOAServerSemanticsWorker() {
		fResult= null;
	}

	public void setMessage(String message) {
		fMessage= message;
	}

	public void setLeft(String leftId) {
		fLeftID= leftId;
	}

	public void setRight(String rightId) {
		fRightID= rightId;
	}

	@Override
	public void run(ProgressStatus progressStatus) {
		File tempFile= null;
		progressStatus.setIndeterminate(true);

		try {
			tempFile= MDUtil.exportEMFUML(Application.getInstance().getProject());
		} catch (Exception ex) {
			fResult= new Result(ResultType.ERROR, ex.getMessage());
			return;
		}

		String msg= fMessage + ServerClientConstants.SEPARATOR + fLeftID + ServerClientConstants.SEPARATOR + fRightID
				+ ServerClientConstants.SEPARATOR + tempFile.getAbsolutePath();
		Socket socket= null;

		String messageFromServer= null;

		try {
			socket= new Socket("localhost", 4444);
			PrintWriter out= new PrintWriter(socket.getOutputStream(), true);
			out.println(msg);
			BufferedReader in= new BufferedReader(new InputStreamReader(socket.getInputStream()));
			messageFromServer= in.readLine();

		} catch (UnknownHostException e) {
			fResult= new Result(ResultType.ERROR, e.getMessage());
			return;
		} catch (IOException e) {
			fResult= new Result(ResultType.ERROR, e.getMessage());
			return;
		} finally {
			if (socket != null) {
				try {
					socket.close();
				} catch (IOException e) {
					fResult= new Result(ResultType.ERROR, e.getMessage());
					return;
				}
			}
		}

		// When we get here, we should have a message.
		if (messageFromServer == null || messageFromServer.isEmpty()) {
			fResult= new Result(ResultType.ERROR, "Message from server null or empty - unknown problem!");
			return;
		}

		if (messageFromServer.startsWith(ServerClientConstants.SERVER_ERROR)) {
			// Server has a severe problem.
			fResult= new Result(ResultType.ERROR, "Server problem: " + messageFromServer.substring(ServerClientConstants.SERVER_ERROR.length()));
			return;
		}

		if (messageFromServer.startsWith(ServerClientConstants.SERVER_CHECK_POSITIVE)) {
			fResult= new Result(ResultType.CHECK_OKAY, "Check reports success.");
			return;
		}

		if (messageFromServer.startsWith(ServerClientConstants.SERVER_CHECK_NEGATIVE)) {

			// get information from the target
			String theInformation= messageFromServer.substring(ServerClientConstants.SERVER_CHECK_NEGATIVE.length());

			if (theInformation.startsWith(ServerClientConstants.ERROR_COMPATIBILITY_SIGNATURE)) {
				// Compatibility Signature problem.
				String message= theInformation.substring(ServerClientConstants.ERROR_COMPATIBILITY_SIGNATURE.length());
				fResult= new Result(ResultType.CHECK_WRONG, message);
				return;
			} else if (theInformation.startsWith(ServerClientConstants.ERROR_COMPATIBILITY_TRANSITION)) {
				// Compatibility Transition problem
				String message= theInformation.substring(ServerClientConstants.ERROR_COMPATIBILITY_TRANSITION.length());
				String[] split= message.split("\\Q" + ServerClientConstants.SEPARATOR + "\\E");
				if (split.length != 5) {
					fResult= new Result(ResultType.ERROR, "Unknown compatibility result from server: " + theInformation);
					return;
				} else {
					String automaton= split[1];
					String state1= split[2];
					String state2= split[3];
					String transition= split[4];

					fResult= new Result(ResultType.CHECK_WRONG, "There is a transition on the " + automaton
							+ " which has no match on the other side: " + transition + "().");

					if (automaton.equals("LEFT"))
						fResult.setProblematicAutomaton(Side.LEFT);
					if (automaton.equals("RIGHT"))
						fResult.setProblematicAutomaton(Side.RIGHT);

					fResult.setProblematicStateLeft(state1);
					fResult.setProblematicStateRight(state2);
					fResult.setProblematicTransition(transition);
					return;
				}

			} else if (theInformation.startsWith(ServerClientConstants.ERROR_REFINEMENT)) {
				// Refinement problem
				fResult= new Result(ResultType.CHECK_WRONG, "Not right: " + theInformation);


				String message= theInformation.substring(ServerClientConstants.ERROR_REFINEMENT.length());
				String[] split= message.split("\\Q" + ServerClientConstants.SEPARATOR + "\\E");
				if (split.length != 5) {
					fResult= new Result(ResultType.ERROR, "Unknown refinement result from server: " + theInformation);
					return;
				} else {
					String automaton= split[1];
					String state1= split[2];
					String state2= split[3];
					String transition= split[4];

					fResult= new Result(ResultType.CHECK_WRONG, "There is a transition on the " + automaton
							+ " which has no match on the other side: " + transition + "().");

					if (automaton.equals("LEFT"))
						fResult.setProblematicAutomaton(Side.LEFT);
					if (automaton.equals("RIGHT"))
						fResult.setProblematicAutomaton(Side.RIGHT);

					fResult.setProblematicStateLeft(state1);
					fResult.setProblematicStateRight(state2);
					fResult.setProblematicTransition(transition);
					return;
				}

			} else {
				fResult= new Result(ResultType.ERROR, "Unkonwn result from server: " + theInformation);
				return;
			}
		}

	}

	public Result getResult() {
		return fResult;
	}

}
