package net;

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

/**
 * \class TCPServer
 * this class provides a TCPServer. There are two modes of running. 
 * In the first mode, the server handles the connection of the clients. 
 * For each connection, it clones itself and the clone will be one the second mode. 
 * In the second mode, the server handles the communication with the client. 
 * (With that system, there is a TCPServer which handles the connections, 
 * and a TCPServer for each client, handling the communication part)
 */
public abstract class TCPServer implements MessageConnection, Runnable, Cloneable {
	private enum Mode {treatClient, treatConnections}
	private Socket commonSocket;
	private ServerSocket waitSocket;
	private Mode mode = Mode.treatConnections;
	
	/**
	 * the server listen on the port given
	 * \param port port on which the server is going to listen
	 */
	public void startServer(int port) throws IOException {
		waitSocket = new ServerSocket(port);
		//System.out.println("got socket");
		new Thread(this).start();
		//System.out.println("thread started");
	}
	
	/**
	 * the server stop to listen on the port
	 */
	public void stopServer() throws IOException {
		waitSocket.close();
	}
	
	/**
	 * main method of the thread
	 */
	public void run() {
		if (mode == Mode.treatConnections) {
			while (true) {
				try {
					commonSocket = waitSocket.accept();
					TCPServer myClone = (TCPServer) this.clone();
					myClone.mode = Mode.treatClient;
					new Thread(myClone).start();
				} catch (IOException e) {
					System.out.println(e);
					e.printStackTrace();
				} catch (CloneNotSupportedException e) {
					System.out.println(e);
					e.printStackTrace();
				}
			}
		} else {
			//System.out.println("dealing with client");
			manageClient(commonSocket);
		}
	}
	
	/**
	 * return the port on which the server is listening
	 */
	public int getPort() {
		return waitSocket.getLocalPort();
	}
	
	/**
	 * handles the communication with the client associated to this (TCPServer)
	 */
	public abstract void manageClient(Socket comm);
	
	@Override
	public Message getMessage() throws IOException, ClassNotFoundException {
		try {
			ObjectInputStream in = new ObjectInputStream(commonSocket.getInputStream());
			return (Message) in.readObject();
		} catch (Exception e) {
			return null;
		}
		
	}
	
	@Override
	public  void sendMessage(Message m) throws IOException {
		ObjectOutputStream out = new ObjectOutputStream(commonSocket.getOutputStream());
		out.writeObject(m);
	}
}
