// ServidorPrimos.java
// 
// Este programa tem como objetivo ilustrar como escrever um
// servidor (isto e', um programa) capaz de escutar em uma
// porta (isto e', ler de um socket) e executar servicos de
// forma multi-threaded (ou seja, para cada pedido recebido,
// um thread e' criado para atender ao pedido. Com isso, varios
// pedidos (oriundos de clientes diversos) podem ser processados
// concorrentemente.
//
// O programa pode ser executando fornecendo-se na linha de comando
// o numero da porta a ser utilizada pelo servidor. Se nenhuma porta
// for fornecida, o proprio servidor arruma uma e a imprime para
// que clientes possam utiliza-la.
//
//               dilma@ime.usp.br
//               Versao 0.1 - MAC 448 Segundo Semestre 2000
//

import java.net.*;
import java.io.*;

public class ServidorPrimos {
    ServerSocket socket_;
    int porta_;
    
    public ServidorPrimos(int porta) {
        try {
            socket_ = new ServerSocket(porta);
        }
        catch (IOException e) {
            System.out.println("Erro na criacao do socket:\n" + e);
            System.exit(1);
        }
        if (porta == 0) {  // alguma livre foi usada 
            porta_ = socket_.getLocalPort();
        }
        else {
            porta_ = porta;
        }
        System.out.println("Socket criado na porta " + porta_);
    }
    
    public ServerSocket getSocket() {
        return socket_;
    }
    
    public static void main(String args[]) {
        int porta = 0;
        // checa se porta foi fornecida como argumento
        if (args.length > 0) {
            try {
                porta = Integer.parseInt(args[0]);
            }
            catch (NumberFormatException e) {
                System.out.println("Valor invalido p/ porta: " + args[0]);
                System.exit(1);
            }
        }
        
        // abre socket
        ServidorPrimos serv = new ServidorPrimos(porta);
        
        // Faz trabalho como servidor
        for ( ; ; ) {
            Socket chegando = null;
            try {
                chegando = serv.getSocket().accept();
            }
            catch (IOException e) {
                System.out.println("Problema com getSocket().accept()\n" + e);
                System.exit(1);
            }
            
            // cria thread para processar entrada (que tambem
            // devolve resultados ao cliente)
            Processamento p = new Processamento(chegando);
            Thread t = new Thread(p);
            t.start(); /* esta linha poderia ser combinada
                        * com a anterior em:
                        *       new Thread(p).start() */
        }
        
    }
}

class Processamento implements Runnable {
    Socket socket_;
    BufferedReader in_;
    PrintWriter out_;
    public Processamento(Socket chegando) {
        socket_ = chegando;
        try {
            in_ = new BufferedReader(
                    new InputStreamReader(chegando.getInputStream())
                );
            out_ = new PrintWriter(chegando.getOutputStream(), true);
        }
        catch (IOException e) {
            System.out.println("Problema input/output streams\n" + e);
            System.exit(1);
        }
    }
    boolean primo(long num) {
        // solucao preguicosa
        for (long div=2; div < num/2; div++)
            if (num % div == 0)
                return false;
        return true;
    }
    public void run() {
        System.out.println("Conexao aceita");
        String line = null;
        String resposta = null;
        long num;
        do {
            try {
                line = in_.readLine();
            }
            catch (IOException e) {
                System.out.println("Em thread " + Thread.currentThread() + e);
                return;
            }
            if (line == null || line.compareTo("") == 0) 
                break;
            // processa a linha: neste exemplo significa
            // ver se e' primo
            try {
                num = Long.parseLong(line);
                if (primo(num))
                    resposta = new String(num + " e primo");
                else
                    resposta = new String(num + " nao e primo");
                
            }
            catch (NumberFormatException e) {
                resposta = new String("Entrada " + line + " invalida");
            }
            System.out.println(resposta);
            out_.println(resposta);
            Thread.currentThread().yield(); 
        } while (true);
        try {
            in_.close();
            out_.close();
            socket_.close();
        } catch (IOException e) {
            System.out.println("Problema fechando I/O ou socket\n" + e);
        }
    }
}
