package org.academiadecodigo.enuminatti.chat;

import com.sun.security.ntlm.Server;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

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

public class ChatServer {
    private ServerSocket socket;
    private Socket clientSocket;
    private PrintWriter out;
    private BufferedReader in;

    public static void main(String[] args) {

        ChatServer server = new ChatServer();

        try {
            while (true) {
                server.listen();
                server.chat();
            }
        } catch (ServerGracefulQuit e) {
            server.closeServer();
        }

    }

    private ChatServer() {
        int portNumber = getPort();

        try {
            socket = new ServerSocket(portNumber);
        } catch (IOException e) {
            System.out.println("Couldn't bind to that port number.");
            e.printStackTrace();
            System.exit(1);
        }

        System.out.println("Listening...");
    }

    private void chat() throws ServerGracefulQuit {
        String message = "";

        printMotd();
        out.println("ACK");

        try {
            while (message != null) {
                switch (message) {
                    case "/info":
                        info();
                        break;
                    case "/motd":
                        printMotd();
                        break;
                    case "/quit":
                        closeConnection();
                        throw new ServerGracefulQuit();
                    case "/disconnect":
                        closeConnection();
                        return;
                    default:
                }
                out.println("ACK");

                message = in.readLine();
                System.out.println(clientSocket.toString() +
                        " < " + (message != null ? message : "<null>"));
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

        // if client closed unexpectedly
        closeConnection();
    }

    private void closeConnection() {

        if (clientSocket == null || clientSocket.isClosed()) {
            return;
        }

        System.out.println("closing connection to client " + clientSocket.getInetAddress().getHostAddress());

        if (in != null) {
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        if (out != null)
            out.close();

        if (clientSocket != null) {
            try {
                clientSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    private void closeServer() {
        if (socket != null) {
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void listen() {
        try {
            clientSocket = socket.accept();
            System.out.println("opened connection with client " +
                    clientSocket.getInetAddress().getHostAddress());
            out = new PrintWriter(clientSocket.getOutputStream(), true);
            in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void printMotd() {
        String motd = "Welcome to ACNet.\n";
        motd += "Available commands: /info, /motd, /disconnect, /quit\n";
        motd += " /info: send client list\n";
        motd += " /motd: sends this message\n";
        motd += " /disconnect: disconnect client from server\n";
        motd += " /quit: close server\n";

        out.println(motd);
        System.out.println(clientSocket.getInetAddress() + " > /motd");
    }

    private void info() {
        String info = "client(s) connected: \n";
        info += " - " + clientSocket.getInetAddress().getHostAddress();

        out.println(info);
        System.out.println(clientSocket.getInetAddress() + " > /info");
    }

    private static int getPort() {
        Scanner scanner = new Scanner(System.in);
        System.out.println("Listening port: ");
        return scanner.nextInt();
    }

    private class ServerGracefulQuit extends Exception {
    }
}
