package fr.upem.tcp;


import java.io.Closeable;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class SqueletteTCPPProxy {

	private class PThread extends Thread {

		private final Object lock = new Object();
		private boolean shutdown = false;
		private Socket sin;

		public PThread() {
		}

		public void shutdown(){
			synchronized (lock) {
				if (!shutdown) {
					shutdown=true;
					this.interrupt();
					silentlyClose(sin);
				}
			}
		}

		private void process() throws IOException, InterruptedException {
		
			// TODO Treat the socket sin

		}


		public void run() {
			while(!Thread.currentThread().isInterrupted()) {
				try{
					final Socket s;
					synchronized (ss) {
						s = ss.accept();
					}

					synchronized (lock) {
						if (!shutdown)  { 
							sin = s;
						}
						else { 
							silentlyClose(sin);
							return;
						}
					}
				} catch (IOException e) {
					shutdown();
					shutdownServer();
					return;
				}

				try{
					process();
				} catch (Exception e) {
					// Ignore all exceptions 
				} finally {
					silentlyClose(sin);
				}
			}
		}
	}



	final private int maxThreads;
	final private ServerSocket ss;
	final private PThread threadArray[];
	final private Object serverLock = new Object();
	private boolean shutdownServer; 



	public SqueletteTCPPProxy(int listeningPort, int maxThreads) throws IOException {
		this.maxThreads=maxThreads;
		ss = new ServerSocket(listeningPort);
		threadArray = new PThread[maxThreads];
	}


	private static void usage() {
		System.out.println("listeningPort maxThreads");
	}

	public static void main(String[] args) throws NumberFormatException, IOException {
		if (args.length!=2) {
			usage();
			return;
		}
		final SqueletteTCPPProxy server = new SqueletteTCPPProxy(Integer.parseInt(args[0]),  Integer.parseInt(args[1]));
		Thread monitor = new Thread (new Runnable() {
			public void run() {
				Scanner sc=null;
				try{
					sc = new Scanner(System.in);
					while (sc.hasNextLine()) {
						String s=sc.nextLine();
						if (s.equals("Shutdown")) break;
					}
				} finally {
					if (sc!=null) sc.close();
					server.shutdownServer();
				}
			}
		});
		monitor.setDaemon(true);
		monitor.start();
		server.launch();

	}

	public void launch() {
		synchronized (serverLock) {
			for (int i = 0; i < maxThreads; i++) {
				threadArray[i] = new PThread();
				threadArray[i].start();
			}
		}
	}

	private void silentlyClose(Closeable s) {
		try {
			if (s!=null) s.close();
		} catch (IOException e) {
			// Ignore
		}
	}

	public void shutdownServer() {
		synchronized (serverLock) {
			if (shutdownServer) return;
			shutdownServer=true;
		}
		silentlyClose(ss);
		for (int i = 0; i < maxThreads; i++) {
			threadArray[i].shutdown();
		}
	}

}



