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();
    messageArea.setColumns(40);
    messageArea.setRows(15);

    JTextField newMessage = new JTextField(30);

    JButton sendButton = new JButton("Send");
    sendButton.addActionListener(e -> {
          speak(newMessage.getText());
          newMessage.setText("");
        });

    showChatMessages(messageArea);
    showChatUI(messageArea, newMessage, sendButton);
  }

  /**
   * 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);

    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);
  }

  /** Listens for messages and display them in this text area. */
  private static void showChatMessages(final JTextArea messageArea) {
    Thread listenThread = new Thread(() -> {
          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);
          }
        });
    listenThread.start();
  }

  /** 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?
    }
  }
}