package org.academiadecodigo.enuminatti.webserver;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * MIT License
 * (c) 2017 Ricardo Constantino
 */

public class WebServer {
    private static final boolean DEBUG = true;
    private static final boolean THREADED = true;

    private ServerSocket server;
    private ExecutorService threadPool;


    public static void main(String[] args) {

        int portNumber = 0;
        if (args.length > 0) {
            portNumber = Integer.parseInt(args[0]);
        }
        if (portNumber == 0) {
            portNumber = Integer.parseInt(getString());
        }

        WebServer server = new WebServer(portNumber);

        server.listen();

    }

    private WebServer(int portNumber) {
        try {
            server = new ServerSocket(portNumber);
            printDebug("* Listening in port " + portNumber);
            if (THREADED) {
                threadPool = Executors.newFixedThreadPool(50);
                printDebug("Starting thread pool with 50 threads.") ;
            }
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(1);
        }
    }

    private void listen() {
        try {
            while (true) {
                if (THREADED) {
                    threadPool.submit(new ConnectionHandler(serve()));
                } else {
                    ConnectionHandler handler = new ConnectionHandler(serve());
                    handler.run();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
            System.err.println("* Failed to connect to client socket.");
        } finally {
            exit();
        }
    }

    private Socket serve() throws IOException {
        Socket clientSocket = server.accept();
        printDebug("* Accepted connection from " +
                clientSocket.getInetAddress().getHostAddress());
        return clientSocket;
    }

    private void exit() {
        if (threadPool != null) {
            threadPool.shutdown();
        }
        if (server != null) {
            try {
                server.close();
            } catch (IOException e) {
                System.err.println("* Couldn't close gracefully.");
                e.printStackTrace();
            }
        }
    }

    private static String getString() {
        Scanner scanner = new Scanner(System.in);
        System.out.printf("Port to listen: ");
        return scanner.nextLine();
    }

    public static void printDebug(String message) {
        if (DEBUG)
            System.out.println(message);
    }
}
