import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Scanner;

public class Client {
    
    private Socket socket;
    private BufferedReader bufferedReader;
    private BufferedWriter bufferedWriter;
    private String username;

    //Uses threads
    //Constructor
    public Client(Socket socket, String username) { 
        try {
            this.socket = socket;
            this.bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); //Message that can be sent under the client username
            this.bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); //What client is sending to other clients in the server.
            this.username = username;
        } catch (IOException e) {
            shutdownApplication(socket, bufferedReader, bufferedWriter);
        }
    }

    public void sendMessage() {
        try {
            bufferedWriter.write(username); //identifier for clienthandler
            bufferedWriter.newLine(); 
            bufferedWriter.flush();

            Scanner scanner = new Scanner(System.in); //for the console for messages to send
            while (socket.isConnected()) { //get user messages and send to console
                String messageToSend = scanner.nextLine(); 
                bufferedWriter.write(username + ": " + messageToSend);
                bufferedWriter.newLine();
                bufferedWriter.flush();
            }
        } catch (IOException e) {
            shutdownApplication(socket, bufferedReader, bufferedWriter);
        }
    } 
    //Every client has a seperate thread that will await a new message
    public void listeningForMSG() {
        new Thread(new Runnable() { //Creating and object with Thread. Runnable is used to run a separate thread
           @Override //when the same method from this class has the same as the Clienthandler class
           public void run() {
            String msgFromGC;

            while (socket.isConnected()) { //seperate thread from client to wait for a message
                try { //try block to read the broadcasted messaged for the chat
                    msgFromGC = bufferedReader.readLine();
                    System.out.println(msgFromGC); 
                } catch (IOException e) {
                    shutdownApplication(socket, bufferedReader, bufferedWriter);
                }
            }
           }
        }).start();
    }

     public void shutdownApplication(Socket socket, BufferedReader bufferedReader, BufferedWriter bufferedWriter) { //close
        try { //try catch block to shutdown client interaction
            if (bufferedReader != null) {
                bufferedReader.close();
            }
            if (bufferedWriter != null) {
                bufferedWriter.close();
            }
            if (socket != null) {
                socket.close();
            }
        } catch(IOException e) {
            e.printStackTrace();
        }
    }

    //main method
    public static void main(String[] args) throws IOException {
        //To enter a username before being transferred to the GC
        Scanner scanner = new Scanner(System.in);
        System.out.println("Enter your username: ");
        String username = scanner.nextLine();
        Socket socket = new Socket("localhost", 9999); //Client socket matching port number with server
        Client client = new Client(socket, username);
        client.listeningForMSG();
        client.sendMessage();
    }
}
