import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.net.*;

/** A GUI client for the chat server. */
public class ChatClientGUI {

  /**
   * Displays a GUI that both displays message from the chat room and allows
   * new messages to be sent to the room.
   */
  public static void main(String[] args) {
    JTextArea messageArea = new JTextArea();     // shows messages from the room
    JTextField newMessage = new JTextField(30);  // new message from user
    JButton sendButton = new JButton("Send");    // click to send new message

    // When the user hits Send, send the new message to the server. It will
    // then show up in the message area when the server passes it back.
    sendButton.addActionListener(e -> {
          speak(newMessage.getText());
          newMessage.setText("");
        });

    // Display the UI with the parts above.
    showChatUI(messageArea, newMessage, sendButton);

    // Create a thread to listen for new messages in the room and display them.
    new ChatListenerThread(messageArea).start();
  }

  /**
   * Displays a text area in the center of a window with a text field and
   * button along the bottom.
   */
  private static void showChatUI(
      JTextArea messageArea, JTextField messageField, JButton messageButton) {
    JFrame frame = new JFrame("Chat Client");
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

    messageArea.setColumns(40);
    messageArea.setRows(15);

    JScrollPane messageScroll = new JScrollPane(messageArea);
    frame.add(messageScroll, BorderLayout.CENTER);

    JPanel panel = new JPanel();
    panel.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
    panel.add(messageField);
    panel.add(messageButton);
    
    frame.add(panel, BorderLayout.SOUTH);
    frame.pack();
    frame.setVisible(true);
  }

  /** Sends the given message to the chat room. */
  private static void speak(String msg) {
    try {
      Socket socket = new Socket(ChatClient.HOST, ChatServer.PORT);
      Writer writer = new OutputStreamWriter(socket.getOutputStream());
      writer.write("speak " + msg + "\n");
      writer.flush();
      socket.close();
    } catch (IOException ex) {
      ex.printStackTrace(System.err);
      // Keep running in this case. Maybe it will get better?
    }
  }

  /** Listens for messages and display them in this text area. */
  private static class ChatListenerThread extends Thread {

    /** The text area in which room messages are displayed. */
    private JTextArea messageArea;

    /** Creates a thread to show new chat message in the given area. */
    public ChatListenerThread(JTextArea messageArea) {
      this.messageArea = messageArea;
    }

    /** Listens for new messages in an infinite loop. */
    public void run() {
      try {
        Socket socket = new Socket(ChatClient.HOST, ChatServer.PORT);

        Writer writer = new OutputStreamWriter(socket.getOutputStream());
        writer.write("listen\n");
        writer.flush();

        BufferedReader reader = new BufferedReader(
            new InputStreamReader(socket.getInputStream()));
        String msg;
        while ((msg = reader.readLine()) != null) {
          // Most UI APIs cannot be called from outside the UI thread.
          // invokeLater will call us back on the UI thread.
          final String newLine = msg + "\n";
          SwingUtilities.invokeLater(() -> messageArea.append(newLine));
        }
      } catch (IOException ex) {
       ex.printStackTrace(System.err);
       System.exit(1);
      }
    }
  }
}