//   Course Number: COSC 645 Applied Cryptography
//    Program Name: SendSharesClient
//         Authors: Brian Hoffman
//                  Derek Waby
//                  Kypros Ioannou
//                  Harsha V. Reddy
//     Description: This class implements a network client whose job is to 
//                  submit a single secret share to a ShamirServer and wait
//                  for subsequent responses. In particular, the server will
//                  keep the client apraised of how many shares are required 
//                  to complete the key and will display the key when finished.
//                  The program begins with a simple GUI that allows the user 
//                  to specify the server and port along with fields for the
//                  X, Y, and prime number parts of the share. The GUI has 
//                  three buttons on the botton. The first submits the share
//                  displayed, the second clars all the fields, and the third
//                  allows the user to read the share from a file. When the 
//                  send shares button is pressed, the client clears the GUI 
//                  and displays an output window showing results from the 
//                  server.

// Java Core Packages
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.util.ArrayList;
import java.math.BigInteger;

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

public class SendSharesClient extends JFrame
{ 
    // private class variables
    public final static int DEFAULT_PORT = 4567;
    private Container container;
    
    // sendPanel Components 
    private JPanel sendPanel;
    private GriddedPanel serverPanel;
    private JLabel serverAddLabel;
    private JTextField serverAddField;
    private JLabel serverPortLabel;
    private JTextField serverPortField;
    private GriddedPanel sharePanel;
    private JLabel shareXLabel;
    private JTextField shareXField;
    private JLabel shareYLabel;
    private JTextArea shareYArea;
    private JLabel primeLabel;
    private JTextArea primeArea;    
    private JPanel buttonPanel;
    private JButton requestButton;
    private JButton clearButton;
    private JButton saveButton;

    // waitPanel Components
    private JPanel waitPanel;
    private JLabel waitLabel;
    private JTextArea msgArea;
    
    // ------------------------------------------------------------------------
    // constructor - sets up the GUI
    //-------------------------------------------------------------------------
    public SendSharesClient()
    {
        // title the window 
        super("Transmit Shamir Secret Share");
        
        // get content pane and set layout
        container = getContentPane();
        container.setLayout(new BorderLayout());
        
        // create components for the share panel
        shareXLabel = new JLabel("X:");
        shareXField = new JTextField(20);
        shareYLabel = new JLabel("Y:");
        shareYArea = new JTextArea(5,20);
        primeLabel = new JLabel("Prime:");
        primeArea = new JTextArea(5,20);
        
        // add components to share panel
        sharePanel = new GriddedPanel();
        sharePanel.setBorder(BorderFactory.createTitledBorder(
                               BorderFactory.createEtchedBorder(), "The Share",
                               TitledBorder.CENTER, TitledBorder.TOP ));           
        sharePanel.addComponent(shareXLabel, 1, 1);
        sharePanel.addFilledComponent(shareXField, 1, 2, 2, 1,
                                       GridBagConstraints.HORIZONTAL);
        sharePanel.addComponent(shareYLabel, 2, 1);
        sharePanel.addFilledComponent(new JScrollPane(shareYArea), 2, 2, 2, 2,
                                       GridBagConstraints.BOTH);
        sharePanel.addComponent(primeLabel, 4, 1);
        sharePanel.addFilledComponent(new JScrollPane(primeArea), 4, 2, 2, 2,
                                       GridBagConstraints.BOTH);        
         
        // create components for the server panel
        serverPanel = new GriddedPanel();
        serverAddLabel = new JLabel("Enter Server's Address");
        serverAddField = new JTextField(20);
        serverPortLabel = new JLabel("Enter Port Number");
        serverPortField = new JTextField(5);
        serverPortField.setText(Integer.toString(DEFAULT_PORT));
        
        // add components to server panel
        serverPanel.addComponent(serverAddLabel, 1, 1, 3, 1);
        serverPanel.addFilledComponent(serverAddField, 2, 2, 2, 1,
                                       GridBagConstraints.HORIZONTAL);
        serverPanel.addComponent(serverPortLabel, 3, 1, 3, 1);
        serverPanel.addFilledComponent(serverPortField, 4, 2, 2, 1,
                                       GridBagConstraints.HORIZONTAL);
        serverPanel.addFilledComponent(sharePanel, 5, 2, 2, 1,
                                       GridBagConstraints.BOTH);
        
        //create components for button panel
        requestButton = new JButton("Send Share");
        requestButton.addActionListener(new SendButtonHandler());
        clearButton = new JButton("Clear");
        clearButton.addActionListener(new ClearButtonHandler());
        saveButton = new JButton ("Read from File");
        saveButton.addActionListener(new ReadButtonHandler(this));
        
        // add components to the buttonPanel
        buttonPanel = new JPanel(new GridLayout(1,3));
        buttonPanel.add(requestButton);
        buttonPanel.add(clearButton);
        buttonPanel.add(saveButton);
        
        // add everthing to sendPanel
        sendPanel = new JPanel( new BorderLayout());
        sendPanel.add(serverPanel, BorderLayout.CENTER);
        sendPanel.add(buttonPanel, BorderLayout.SOUTH);
        container.add(sendPanel, BorderLayout.CENTER);
        
        // display the initial GUI
        pack();
        setVisible(true);   
    }
    
    // ------------------------------------------------------------------------
    // SendButtonHandler
    //-------------------------------------------------------------------------
    private class SendButtonHandler implements ActionListener
    {
        public void actionPerformed(ActionEvent event)
        {
            // build the waitPanel
            buildWaitPanel();
            
            // send processing of results into another thread
            Thread process = new Thread () {
                public void run()
                {
                    // create the connection and send the share
                    ClientConnection connection = new ClientConnection(serverAddField.getText(),
                                                  Integer.parseInt(serverPortField.getText()));
            
                    // check if the connection was successful
                    if (!connection.connect())
                    {
                        msgArea.append("Error connecting to server! \n"); 
                        msgArea.setCaretPosition(msgArea.getText().length());
                       return;
                    }
            
                    // send the share to the server and wait for responses 
                    try
                    {
                        connection.sendObject( new ShamirMsg("share",
                               new BigInteger(shareXField.getText()),
                               new BigInteger(shareYArea.getText()), 
                               new BigInteger(primeArea.getText()) ) );
                        
                        ShamirMsg currentMsg = (ShamirMsg) connection.readObject();
                        String currentType = currentMsg.getType();
                        while( !(currentType.equals("key")) && !(currentType.equals("invalidShare")) )
                        {
                            if (currentType.equals("numRemain"))
                            {
                                msgArea.append("Server is waiting for " + currentMsg.getX() +
                                               " shares.\n"); 
                                msgArea.setCaretPosition(msgArea.getText().length());
                            }
                            currentMsg = (ShamirMsg) connection.readObject();
                            currentType = currentMsg.getType();
                        }
                        
                        if(currentType.equals("key"))
                        {
                            msgArea.append("The key is " + currentMsg.getX() + ".\n" ); 
                            msgArea.setCaretPosition(msgArea.getText().length());
                            connection.sendObject( new ShamirMsg("terminate"));
                        }
                        else
                        { 
                            msgArea.append("You sent an invalid share to the server.\n" ); 
                            msgArea.setCaretPosition(msgArea.getText().length());
                            connection.sendObject( new ShamirMsg("terminate"));
                        }
                    }
                    catch(Exception e)
                    {
                        JOptionPane.showMessageDialog(null, "Error requesting share!", 
                                   "Share Request Error", JOptionPane.ERROR_MESSAGE);
                        e.printStackTrace();
                    }
                    finally
                    {
                       connection.close();
                    } // end finally                
                } // end run
            }; // end thread
            process.start();
        } // end actionPerformed
    } // end SendButtonHandler
    
    // ------------------------------------------------------------------------
    // ClearButtonHandler
    //-------------------------------------------------------------------------
    private class ClearButtonHandler implements ActionListener
    {
        public void actionPerformed(ActionEvent event)
        {
            serverAddField.setText("");
            serverPortField.setText(Integer.toString(DEFAULT_PORT));
            shareXField.setText("");
            shareYArea.setText("");
            primeArea.setText("");
        }
    }
    // ------------------------------------------------------------------------
    // ReadButtonHandler
    //-------------------------------------------------------------------------
    private class ReadButtonHandler implements ActionListener
    {
        private JFrame parent;
        
        public ReadButtonHandler(JFrame inFrame)
        {
            parent = inFrame;
        }
        
        public void actionPerformed(ActionEvent event)
        {
            boolean error = false;
            
            // open a file chooser dialog and get the input file
            JFileChooser chooser = new JFileChooser();
            chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
            chooser.setCurrentDirectory(new File("."));
            if(chooser.showOpenDialog(parent) != JFileChooser.APPROVE_OPTION)
                return;
            File fileName = chooser.getSelectedFile();  
            
            // setup a buffered reader for the file
            FileReader theFile;
            BufferedReader inFile = null;
            try
            {
                 theFile = new FileReader(fileName);
                 inFile = new BufferedReader(theFile);
            
                // read in X component from the first line 
                String temp = inFile.readLine();           
                if (temp == null)
                {
                    JOptionPane.showMessageDialog(null, "File is empty!", 
                                       "File Read Error", JOptionPane.ERROR_MESSAGE);
                    error = true;
                }
                else
                {
                    shareXField.setText(temp);
                }
                
                // read in Y component from the next line
                if (!error)
                {
                    temp = inFile.readLine();           
                    if (temp == null)
                    {
                        JOptionPane.showMessageDialog(null, "File has no Y component!", 
                                       "File Read Error", JOptionPane.ERROR_MESSAGE);
                        error = true;
                    }
                    else
                    {
                        shareYArea.setText(temp);
                    }
                }
          
                // read in prime from the last line 
                if (!error)
                {
                    temp = inFile.readLine();           
                    if (temp == null)
                    {
                        JOptionPane.showMessageDialog(null, "File has no prime number!", 
                                       "File Read Error", JOptionPane.ERROR_MESSAGE);
                        error = true;
                    }
                    else
                    {
                        primeArea.setText(temp);
                    }
                }                  
            }            
            catch(IOException ioException)
            {
                JOptionPane.showMessageDialog(null, "Error reading from file!", 
                                  "File Read Error", JOptionPane.ERROR_MESSAGE);
            }
            finally  // close the file stream
            {
                try
                { if (inFile != null) inFile.close(); }
                catch(IOException e)
                {} // do nothing                     
            }   
        } // end ActionPerformed        
    } // end ReadButtonHandler

    // ------------------------------------------------------------------------
    // buildWaitPanel
    //-------------------------------------------------------------------------
    public void buildWaitPanel()
    {
        waitPanel = new JPanel(new BorderLayout());
        waitLabel = new JLabel("Waiting for server to accumulate enough shares...");
        msgArea = new JTextArea(10, 20);
        waitPanel.add(waitLabel, BorderLayout.NORTH);
        waitPanel.add(new JScrollPane(msgArea), BorderLayout.CENTER);
        
        container.remove(sendPanel);
        container.add(waitPanel);
        container.validate();
        container.repaint();
    }
    
    // ------------------------------------------------------------------------
    // main - executes application
    //------------------------------------------------------------------------- 
    public static void main (String args[])
    {
        SendSharesClient application = new SendSharesClient();
        application.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }       
}
