package classes;

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

public class Servidor {

	private ServerSocket servidor;
	private Socket conexao;
	private ObjectInputStream input;
	private ObjectOutputStream output;
	private Processa objProcessar;
	
	public void run(){
		
		/*
		 * Inicialização do Socket de conexão com o servidor
		 * Vincula-se o Socket a uma porta TCP e define-se o tamanho da fila de conexões
		 * Após executar o método, a dupla "IP servidor"."Porta 56789" poderão ser utilizados
		 * para a comunicação TCP com o servidor
		 */
		try{
			
			servidor = new ServerSocket(56789, 100);
			
		}catch(IOException e){
			System.out.println("Exceção ao inicializar Socket no Servidor");
			e.printStackTrace();
		}
		
		while(true){
			/*
			 * O servidor aguarda uma conexão de cliente através do método accept()
			 * quando executado, retorna um Socket que define a conexão entre cliente e servidor
			 * Após isto são definidos os objetos para gerenciar o fluxo no canal de comunicação
			 * ObjectInputStream e ObjectOutputStream tornam transparente o envio/recebimento de 
			 * objetos por este canal de comunicação (desde que sejam serializáveis) 
			 */
			try{
				
				conexao = servidor.accept();
				output = new ObjectOutputStream(conexao.getOutputStream());
				output.flush();
				input = new ObjectInputStream(conexao.getInputStream());
				
				System.out.println("Conexão iniciada com cliente " + conexao.getInetAddress().getHostName());			
				
			}catch(IOException e){
				System.out.println("Exceção ao estabelecer conexão com cliente");
				e.printStackTrace();
			}
			
			/*
			 * O servidor então aguarda o cliente enviar o objeto para ser processado
			 * Neste caso o objeto a ser enviado implementa a interface Processa, e o servidor
			 * Sequer sabe que objeto é este, apenas que ele tem um método processaObjeto
			 * Como o objeto é transferido pelo canal de comunicação, este método apresentará 
			 * diferentes comportamentos para objetos distintos que forem enviados para o servidor
			 */
			try{
				
				objProcessar = (Processa) input.readObject();
				objProcessar.processaObjeto();
				output.writeObject(objProcessar);
				output.flush();
				
			}catch(IOException e1){
				e1.printStackTrace();
			}catch(ClassNotFoundException e2){
				e2.printStackTrace();
			}
			
			/*
			 * Após realizado o processamento desejado no servidor, a conexão com o cliente é finalizada
			 * E o servidor volta a aguardar novas conexões para processar outros objetos
			 */
			try{
				input.close();
				output.close();
				conexao.close();
			}catch(IOException e){
				System.out.println("Exceção ao fechar conexão com cliente!");
				e.printStackTrace();
			}
		}
	}
	
	/*
	 * Metodo para inicializar programa servidor
	 */
	public static void main(String[] args) {
		Servidor server = new Servidor();
		server.run();
	}

}
