package fr.insa.clavardator.lib.network;

import fr.insa.clavardator.lib.util.ErrorCallback;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class TcpListener {
	Acceptor acceptor = null;

	public TcpListener() {
	}

	public void acceptConnection(int port, NewConnectionCallback callback, ErrorCallback errorCallback) {
		if (acceptor != null) {
			acceptor.stopAccepting();
		}
		acceptor = new Acceptor(port, callback, errorCallback);
		acceptor.start();
	}

	/**
	 * Stop accepting incoming connexions.
	 * Must be called before exiting the app.
	 */
	public void stopAccepting() {
		if (acceptor != null)
			acceptor.stopAccepting();
	}


	public interface NewConnectionCallback {
		void onNewConnection(Socket clientSocket);
	}

	private static class Acceptor extends Thread {
		private final NewConnectionCallback callback;
		private final ErrorCallback errorCallback;
		private final int port;
		private boolean shouldStop = false;
		private ServerSocket server;

		public Acceptor(int port, NewConnectionCallback callback, ErrorCallback errorCallback) {
			this.port = port;
			this.callback = callback;
			this.errorCallback = errorCallback;
		}

		@Override
		public void run() {
			try {
				server = new ServerSocket(port);
				while (!shouldStop) {
					Socket clientSocket = server.accept();
					callback.onNewConnection(clientSocket);
				}
			} catch (IOException e) {
				if (!shouldStop)
					errorCallback.onError(e);
			}
		}

		public void stopAccepting() {
			shouldStop = true;
//			TODO: call interrupt() with ChannelServerSocket instead of closing the socket?
			try {
				server.close();
			} catch (IOException ignored) {
			}
		}
	}
}
