/**********************************************************************************
* TCP client that allows communication with TCP server
* Provides the ability to execute SQL commands against mysql or oracle databases
* When a TCP socket is created you are assigned a local port number by the O/S.
* This client a a swing UI 
*
* Usage: TCPclientUI [with optional] <hostname> <serverPort>
* 
* @version 3.0
* @author Sam Sultan
**********************************************************************************/
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.net.*;

public class TCPclientUI extends JFrame 
                         implements ActionListener, KeyListener 
{
    JLabel            userLabel  = new JLabel("User: ");
    JTextField        user       = new JTextField(12);
    JLabel            pswdLabel  = new JLabel("Password: ");
    JPasswordField    pswd       = new JPasswordField(12);
    String[]          dbArray    = {"oracle","mysql"};
    JComboBox<String> dbList     = new JComboBox<>(dbArray);
    String            dbSelected = "";

    JLabel      sqlLabel    = new JLabel("SQL:  ");
    JTextArea   sql         = new JTextArea(5, 70);           //height, width
    JScrollPane sql2        = new JScrollPane(sql);           //make it scrollable
    JTextArea   result      = new JTextArea(12,70);           //height, width
    JScrollPane result2     = new JScrollPane(result);        //make it scrollable

    JLabel      hostLabel   = new JLabel("Host: ");
    JTextField  host        = new JTextField(25);
    JLabel      portLabel   = new JLabel("Port: ");
    JTextField  port        = new JTextField(6);
    ImageIcon   image       = new ImageIcon("go.png");
    JButton     execute     = new JButton(image);

    String sendString;                  //string to send server
    String recvString = null;           //string received from server

    InetAddress serverIP;               //IP address object for server
    InetAddress clientIP;               //IP address object for client
    
    int serverPort;                     //port number for server
    int clientPort;                     //port number for client

    Socket TCPSocket;                   //TCP socket object

    public static void main(String[] args) 
    {
        String hostName = (args.length>0) ? args[0] : ""; 
        String portNum  = (args.length>1) ? args[1] : ""; 

        TCPclientUI ui = new TCPclientUI(hostName, portNum);   
    }

    public TCPclientUI(String hostName, String portNum)         //constructor 
    {
        setTitle("Enter SQL Command");                          //set title               
        setDefaultCloseOperation(EXIT_ON_CLOSE);                //action when click on X

        Container panel = getContentPane();                     //get reference to the content pane

        FlowLayout layout = new FlowLayout(FlowLayout.LEFT);    //create a FlowLayout manager set to left
        panel.setLayout(layout);                                //Flow the window using layout

        JToolBar toolBox1 = new JToolBar();                     //create a tool bar
        toolBox1.add(userLabel);                                //add components to tool bar
        toolBox1.add(user);
        toolBox1.add(new JLabel("     "));
        toolBox1.add(pswdLabel);
        toolBox1.add(pswd);
        toolBox1.add(new JLabel("      "));
        toolBox1.add(dbList);

        JToolBar toolBox2 = new JToolBar();              //create a tool bar
        toolBox2.add(hostLabel);                         //add components to tool bar
        toolBox2.add(host);
        toolBox2.add(new JLabel("    "));
        toolBox2.add(portLabel);
        toolBox2.add(port);
        toolBox2.add(new JLabel("              "));
        toolBox2.add(execute);

        host.setText(hostName);                         //if provided, display on screen
        port.setText(portNum);                          //if provided, display on screen

        host.setEditable(false);                        //cannot edit results
        port.setEditable(false);
        result.setEditable(false);                      

        panel.add(toolBox1);                            //add components to the panel                    
        panel.add(sql2);                                
        panel.add(result2);                            
        panel.add(toolBox2);                    

        setSize(800, 400);                              //set width/height of window 
        setResizable(false);                            //no resize 
        setVisible(true);                               //make window visible

        dbList.addActionListener(this);                 //add an event handler on dropdownlist
        execute.addActionListener(this);                //add an event handler on button
        sql.addKeyListener(this);                       //add a key handler on SQLCommand
    }

    public void actionPerformed(ActionEvent evt) 
    {
        Object source = evt.getSource();                //get a reference to the object 

        if (source == dbList)
            dbSelected = (String) dbList.getSelectedItem();    
             
        if (source == execute)
            callServer();                               //call the server
    }

    public void keyTyped(KeyEvent evt)    { }           //must implement
    public void keyPressed(KeyEvent evt)  { }           //even if empty
    public void keyReleased(KeyEvent evt) { }


//---------------------------------------------------------------------------

    private void callServer()
    {
        try                                          
        {
            String hostName   = host.getText();             //get text from window
            String portNumber = port.getText();             //get text from window

            serverIP   = InetAddress.getByName(hostName);   //get server hostname -> address
            serverPort = Integer.parseInt(portNumber);      //get server port number        

            TCPSocket = new Socket(serverIP,serverPort);    //establish new client socket


            serverIP   = TCPSocket.getInetAddress();        //get server IP address
            serverPort = TCPSocket.getPort();               //get server port number        
            clientIP   = TCPSocket.getLocalAddress();       //get local IP address
            clientPort = TCPSocket.getLocalPort();          //get local port number 

            InputStream       socketIn1  = TCPSocket.getInputStream();          //ref to socket input 
            InputStreamReader socketIn2  = new InputStreamReader(socketIn1);    //convert to 16 bit
            BufferedReader    socketIn   = new BufferedReader(socketIn2);       //to use readLine()

            OutputStream       socketOut1 = TCPSocket.getOutputStream();        //ref to socket output 
            OutputStreamWriter socketOut2 = new OutputStreamWriter(socketOut1); //convert to 16 bit
            PrintWriter        socketOut  = new PrintWriter(socketOut2);        //buffered and can use println()    

            //------------------ read data from screen -------------------

            String userId     =  user.getText();                        //get user from window
            char[] pswdArray  =  pswd.getPassword();                    //get password as char[] 
            String password   =  String.valueOf(pswdArray);             //convert to String                     
            String dbType     = (String) dbList.getSelectedItem();      //get dropdown list 
            String sqlCommand =  sql.getText(); 
            
            if (userId.equals(""))   throw new Exception("Please enter User id");
            if (password.equals("")) throw new Exception("Please enter Password");                  
            
            //------------------ send data -------------------------------
    
            String sendString  = dbType +":"+ userId +":"+ password + "\n";   //populate credentials
                   sendString += sqlCommand;                                  //append the SQL commands
                   
            sendString = sendString.replace('\n','\t');         //newline is used as delimeter in socket   
            socketOut.println(sendString);                      //send data thru the socket     
            socketOut.flush();                                  //flush buffer

            //------------------ receive data -----------------------------
    
            String sqlResult = "";

            while(true)                               //use for multiple lines 
            {                    
                recvString = socketIn.readLine();
                if (recvString.length() == 0) break;  //empty line?
                sqlResult += recvString + "\n";                                  
            }                               
            recvString = socketIn.readLine();         //flush whatever is in socket. 

            result.setText(sqlResult);                //display the result
            result.setCaretPosition(0);               //scroll back to top


//          System.out.println("Closing connection to "+ serverIP +":"+ serverPort);
//          socketIn.close();
//          socketOut.close();
//          TCPSocket.close();
        }
        catch(UnknownHostException e)
        {
            result.setText("Unknown host: " + e.toString());
        }
        catch(IOException e)
        {   
            result.setText("I/O or Network error: " + e.toString());
        }
        catch(Exception e)
        {   
            result.setText(e.toString());
        }
    }
}
//---------------------------------------------------------------------------