//   Course Number: COSC 650 Data Comm/Networks
//    Program Name: ChatLoginPanel
//  Project Number: 2
//         Authors: Brian Hoffman
//                  Mike McKinney
//                  Javier Carrasco
//     Description: This class displays a login panel complete with server address,
//                  server port, username, and status fields. The panel also holds 
//                  connect and cancel buttons. Upon filling in the appropriate 
//                  information and hitting the connect button, the client will 
//                  attempt to create a socket to the server and send an addClient
//                  message. If unsuccessful, an error message will be diplayed in 
//                  the status field and the connected boolean variable will remain 
//                  false. If successful, the login panel will wait for the success
//                  message, i.e. acceptClient, and save it for future use. It will
//                  also set connected to true. The program making use of the login
//                  panel should loop and keep checking the connected status using
//                  the success() method. Once this method returns true, that 
//                  program should get the connection and the first message using 
//                  the getConnection() and getConnectMsg() methods.
//                 

// Java Core Packages
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;

// Jave Extension Packages 
import javax.swing.*;
import javax.swing.border.*;

public class ChatLoginPanel extends GriddedPanel
{
    // private data
    private ClientConnection connection;
    private boolean connected = false;
    private ChatMessage connectMsg;
    public static final int DEFAULT_PORT = 6789;
    
    // GUI Components
    private GriddedPanel topPanel;
    private JLabel serverAddLabel; 
    private JTextField serverAddField;          
    private JLabel nicknameLabel;
    private JTextField nicknameField; 
    private JLabel portLabel;
    private JTextField portField;
    private JButton connectButton;       
    private JButton cancelButton;       
    private JPanel statusPanel;     
    private JTextField statusField;
    
    /**
     * ------------------------------------------------------------------------
     * constructor - sets up the GUI
     * ------------------------------------------------------------------------
     */  
    public ChatLoginPanel()
    {
        super();
        
        // add label and field for getting server IP address
        topPanel = new GriddedPanel();
        topPanel.setBorder(BorderFactory.createTitledBorder(
                       BorderFactory.createEtchedBorder(), 
                       "Login / Connect",
                       TitledBorder.LEFT, TitledBorder.TOP )); 
        serverAddLabel = new JLabel("Enter Server Name or IP Address");
        serverAddField = new JTextField(20);
        portLabel = new JLabel("Enter Port Number");
        portField = new JTextField(Integer.toString(DEFAULT_PORT), 20);        
        nicknameLabel = new JLabel("Enter Nickname or Chat Handle");
        nicknameField = new JTextField(20);
        connectButton = new JButton("Connect");
        connectButton.addActionListener(new connectButtonHandler());
        cancelButton = new JButton("Cancel");
        cancelButton.addActionListener(new cancelButtonHandler()); 
        topPanel.addComponent(serverAddLabel, 1, 1, 2, 1);
        topPanel.addComponent(serverAddField, 2, 1, 2, 1);
        topPanel.addComponent(portLabel, 3, 1, 2, 1);
        topPanel.addComponent(portField, 4, 1, 2, 1);
        topPanel.addComponent(nicknameLabel, 5, 1, 2, 1);
        topPanel.addComponent(nicknameField, 6, 1, 2, 1);
        topPanel.addComponent(connectButton, 7, 1, 1, 1);
        topPanel.addAnchoredComponent(cancelButton, 7, 2, 1, 1,
                                      GridBagConstraints.EAST);
        addComponent(topPanel, 1, 1);
                
        //create status panel
        statusPanel = new JPanel();
        statusPanel.setLayout(new BorderLayout());
        statusPanel.setBorder(BorderFactory.createTitledBorder(
                       BorderFactory.createEtchedBorder(), "Status",
                       TitledBorder.LEFT, TitledBorder.TOP )); 
        statusField = new JTextField(20);
        statusField.setEditable(false);
        statusPanel.add(statusField, BorderLayout.CENTER);
        addComponent(statusPanel, 2,1);
       
        // make the panel visible
        setVisible(true);
    }

    /**
     * ------------------------------------------------------------------------
     * connectButtonHandler - handles presses of the connect button
     * ------------------------------------------------------------------------
     */
    private class connectButtonHandler implements ActionListener
    {
        public void actionPerformed(ActionEvent event)
        {
            if(!connected)
            {
                // read information from the GUI and create a connection 
                String server = serverAddField.getText();
                String name = nicknameField.getText();
                int portNum = Integer.parseInt(portField.getText());
                if ((name.length()==0) || (server.length()==0))
                {
                    JOptionPane.showMessageDialog(null, 
                       "Must enter nickname and server address.", "Login Error",
                       JOptionPane.ERROR_MESSAGE);
                    return;
                }
                statusField.setText("Connecting...");
                connection = new ClientConnection(server, portNum, name);
                
                // check if the connection was successful
                if (!connection.connect())
                {
                    statusField.setText("Connection Failed");
                }
                else
                {
                    statusField.setText("Connection Succeeded");
                }
                
                // send an addClient message to the server to see if it will  
                // accept me with the given login name 
                try 
                {
                    connection.sendMessage(new ChatMessage("addClient", name, "", ""));
                    statusField.setText("Requesting Login ...");
                    
                    // wait for the server to acknowledge and act appropriately based
                    // upon the type of message returned. If it is anything other than
                    // an accept message, the connection should be closed and the 
                    // status printed out
                    connectMsg = connection.readMessage();
                    if (!connectMsg.getType().equals("acceptClient"))
                    {
                        statusField.setText("Server Refused Login");
                        connection.close();
                        connected = false;
                    }
                    else 
                    {
                        statusField.setText("Server Accepted Login");
                        connected = true;
                    }
                }
                // any exceptions at this point should abort the connection 
                catch(Exception e) 
                {
                    connection.close();
                    connected = false;
                    connectMsg = null;
                    statusField.setText("Connection Lost: IO Error");
                } // end catch
            } // end if 
        } // end actionPerformed 
    } // end class 
   
    /**
     * ------------------------------------------------------------------------
     * clearButtonHandler - handles presses of the clear button
     * ------------------------------------------------------------------------
     */
    private class cancelButtonHandler implements ActionListener
    {
        public void actionPerformed(ActionEvent event)
        {
            if (!connected)
            {
               serverAddField.setText("");
               nicknameField.setText("");
               statusField.setText("Disconnected");
            } // end if 
        } // end actionPerformed
    } // end class
    
    
    /**
     * ------------------------------------------------------------------------
     * getConnection - accessor method that returns the connection
     * ------------------------------------------------------------------------
     */  
    public ClientConnection getConnection()
    {
        return connection;
    }
    
    /**
     * ------------------------------------------------------------------------
     * success - returns true if the panel has successfully created a connection
     *           and false otherwise
     * ------------------------------------------------------------------------
     */ 
    public boolean success()
    {
        return connected;
    }
    
    /**
     * ------------------------------------------------------------------------
     * getConnectMessage - accessor method that returns the server's connection
     *                     message that includes a list of the chatrooms that 
     *                     are currently available
     * ------------------------------------------------------------------------
     */  
    public ChatMessage getConnectMsg()
    {
        return connectMsg;
    }
    
    
    /**
     * ------------------------------------------------------------------------
     * reset - resets the login panel so that it may be used again. This method 
     *         assumes that the connection has been read by some other program 
     *         that is responsible for maintaining it and any references to it 
     *         from here onward
     * ------------------------------------------------------------------------
     */  
    public void reset()
    { 
        // reset variables
        connected = false;
        connection = null;
        connectMsg = null;
        
        //reset GUI fields
        serverAddField.setText("");
        nicknameField.setText(""); 
        portField.setText(Integer.toString(DEFAULT_PORT));    
        statusField.setText("");
    }
}