/*
 * 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.vnserver;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

class UML4SOAVerificationServer implements Runnable {

	private ServerSocket server;

	private BufferedReader in;

	private PrintWriter out;

	public void listen() {
		new Thread(this).run();
	}

	class ClientWorker implements Runnable {

		private Socket fClient;

		public ClientWorker(Socket client) {
			fClient= client;
		}

		public void run() {
			String line;
			BufferedReader in= null;
			PrintWriter out= null;
			try {
				in= new BufferedReader(new InputStreamReader(fClient.getInputStream()));
				out= new PrintWriter(fClient.getOutputStream(), true);
			} catch (IOException e) {
				VerificationServerPlugin.logError(e);
				return;
			}

			try {
				line= in.readLine();
				// Lenghty calculation
				System.out.println("GOT LINE: " + line);

				String[] split= line.split("\\Q" + ServerClientConstants.SEPARATOR + "\\E");
				if (split.length != 4) {
					out.println(ServerClientConstants.SERVER_ERROR + "Need four segments for check: " + line);
					return;
				}

				String left= split[1];
				String right= split[2];
				String fileName= split[3];

				String result= null;

				if (line.startsWith(ServerClientConstants.CHECKTYPE_COMPATIBILITY)) {

					String theory= getTheory(line);

					// Check compatiblity
					result= checkCompatibility(theory, left, right, fileName);

				} else if (line.startsWith(ServerClientConstants.CHECKTYPE_REFINEMENT)) {

					String theory= getTheory(line);

					// Check refinement
					result= checkRefinement(theory, left, right, fileName);

				} else {
					out.println(ServerClientConstants.SERVER_ERROR + "Unknown command.");
					return;
				}

				if (result == null)
					out.println(ServerClientConstants.SERVER_CHECK_POSITIVE);
				else
					out.println(ServerClientConstants.SERVER_CHECK_NEGATIVE + result);



			} catch (IOException e) {
				VerificationServerPlugin.logError(e);
				if (!out.checkError()) {
					out.println(ServerClientConstants.SERVER_ERROR + e.getMessage());
				}
				return;
			} finally {
				try {
					fClient.close();
				} catch (IOException e) {
					VerificationServerPlugin.logError(e);
				}
			}
		}
	}

	public void run() {

		System.out.println("Listening on 4444.");

		try {
			server= new ServerSocket(4444);
		} catch (IOException e) {
			VerificationServerPlugin.logError(e);
			System.out.println("Could not listen on port 4444");
		}

		while (true) {
			ClientWorker w;
			try {
				// server.accept returns a client connection
				w= new ClientWorker(server.accept());
				Thread t= new Thread(w);
				t.start();
			} catch (IOException e) {
				System.out.println("Accept failed: 4444");
				VerificationServerPlugin.logError(e);
				return;
			}
		}
	}

	public String getTheory(String line) {

		if (line.contains(ServerClientConstants.THEORY_SO))
			return ServerClientConstants.THEORY_SO;

		if (line.contains(ServerClientConstants.THEORY_WEAK))
			return ServerClientConstants.THEORY_WEAK;

		if (line.contains(ServerClientConstants.THEORY_STRONG))
			return ServerClientConstants.THEORY_STRONG;


		return null;
	}

	public String checkCompatibility(String theory, String left, String right, String fileName) {

		ServerCompatibilityChecker checker= new ServerCompatibilityChecker(theory, fileName);
		checker.setLeft(left);
		checker.setRight(right);

		if (checker.check())
			return null;
		else
			return checker.getResult();
	}

	public String checkRefinement(String theory, String left, String right, String fileName) {

		ServerRefinementChecker checker= new ServerRefinementChecker(theory, fileName);
		checker.setLeft(left);
		checker.setRight(right);

		if (checker.check())
			return null;
		else
			return checker.getResult();

	}

	protected void finalize() {
		try {
			in.close();
			out.close();
			server.close();
		} catch (IOException e) {
			VerificationServerPlugin.logError(e);
		}
	}

	public void stop() {
		finalize();
	}

}
