package tmcsim.client;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.Properties;
import java.util.Vector;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;
import javax.swing.JWindow;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.table.DefaultTableModel;
import tmcsim.client.cadclientgui.data.Incident;
import tmcsim.client.cadclientgui.enums.CADDataEnums.INC_TABLE;
import tmcsim.common.SimulationException;
import tmcsim.interfaces.CADClientInterface;
import tmcsim.interfaces.CoordinatorInterface;

/**
 * CADlogDisplays shows the current CAD log for all incidents. It operates as a client of the
 * CAD server, using RMI to poll the server every second for the current
 * list of incidents and associated comments/notes table. 
 *
 * @author jdalbey
 */
public class CADlogDisplay extends UnicastRemoteObject implements
        CADClientInterface
{
    /**
     * Error logger.
     */
    private static Logger cadClientLogger = Logger.getLogger("tmcsim.client");

    private static final String CONFIG_FILE_NAME = "cad_client_config.properties";
    private static final String LOG_FILE_NAME = "CADcomments.log";
    private final static int TEN_SECONDS = 10000;

    /**
     * Enumeration containing properties name values. See CADClient class
     * description for more information.
     *
     * @author Matthew Cechini
     * @see CADClient
     */
    private static enum PROPERTIES
    {
        CAD_SIM_HOST("CADSimulatorHost"), CAD_SIM_PORT("CADSimulatorSocketPort"), CAD_RMI_PORT(
        "CADRmiPort"), CLIENT_CAD_POS("CADPosition"), CLIENT_USER_ID(
        "CADUserID"), KEYBOARD_TYPE("KeyboardType"), DISPLAY_TYPE(
        "DisplayType");
        public String name;

        private PROPERTIES(String n)
        {
            name = n;
        }
    }
    /**
     * CADClientSocket Object to handle socket communication between the Client
     * and CAD Simulator.
     */
    private CADClientSocket theClientSocket;

    /**
     * Properties object for the CADClient class.
     */
    private Properties cadClientProp;
    /**
     * RMI interface for communication with the remote Coordinator.
     */
    private static CoordinatorInterface theCoorInt;
    /**
     * reference to itself to be used for disconnecting from CADSimulator
     */
    private CADClientInterface client = this;
    /*
     * PrintWriter handle for sending log to a file 
     */
    private PrintWriter writer;

    /**
     * Constructor. Initialize data from parsed properties file. Create a socket
     * connection to the CADSimulator.
     *
     * @param propertiesFile File path (absolute or relative) to the properties
     * file containing configuration data.
     */
    public CADlogDisplay(String propertiesFile) throws SimulationException,
            RemoteException
    {
        if (!verifyProperties(propertiesFile))
        {
            System.exit(0);
        }

        connect(cadClientProp.getProperty(PROPERTIES.CAD_SIM_HOST.name).trim(),
                cadClientProp.getProperty(PROPERTIES.CAD_RMI_PORT.name).trim());

        // Create a timer that fetches the simulation time every second.
        Timer timer = new Timer(TEN_SECONDS, new ActionListener()
        {
            public void actionPerformed(ActionEvent evt)
            {
                try
                {
                    Vector<Incident> incList = theCoorInt.getIncidentList(); 
                    StringBuffer output = new StringBuffer();

                    for (Incident incident: incList)
                    {
                    // DefaultTableModel noteTable = (DefaultTableModel) theCoorInt.getCadDataIncidentTable(INC_TABLE.COMMENTS_NOTES, incident.getLogNum());
                     // Output noteTable
                        // Retrieve the table of comments/notes the users created
                        DefaultTableModel notesTable = incident.getCommentsNotesTable();
                        // Retrieve the notes chronologically (Most recent is in first row)
                        for (int row=notesTable.getRowCount()-1; row >=0; row--)
                        {
                            // Combine the fields into one export entry
                            //sb.append(notesTable.getValueAt(row,1) + " "); // time
                            String initials = (String) notesTable.getValueAt(row,2); // user initials
                            // If there are user intials, include this item.
                            // Zero length initials mean it's a scripted item, ignore it.
                            if (initials.length() > 0)
                            {//CAD Log Entry, Incident #187, Sharon: REQUEST EXTRA ANCHOVIES
                                output.append("CAD log entry, ");
                                output.append("Incident #" + incident.logNum + ", ");
                                output.append(initials + ": ");
                                output.append(notesTable.getValueAt(row,4) + "\n"); // notes
                            }
                        }
                    }
                    System.out.print(output);
                    // Write output to a file
                    try 
                    {
                        writer = new PrintWriter(new FileWriter(LOG_FILE_NAME));
                        writer.print(output);
                        writer.close();
                    } catch (Exception exc) {
                        exc.printStackTrace();
                        } 
        
                    //long simtime = theCoorInt.getCurrentSimulationTime();
                    //theView.updateTime("" + formatInterval(simtime));
                } catch (RemoteException ex)
                {
                    Logger.getLogger(CADlogDisplay.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        });
        timer.start();

        ensureProperShutdown();
    }

    /**
     * Connect to the Coordinator's RMI object, and register this object for
     * callback with the Coordinator.
     *
     * @param hostname Host name of the CAD Simulator.
     * @param portNumber Port number of the CAD Simulator RMI communication.
     * @throws SimulationException if there is an error creating the RMI
     * connection.
     */
    protected void connect(String hostname, String portNumber)
            throws SimulationException
    {

        String coorIntURL = "";

        try
        {
            coorIntURL = "rmi://" + hostname + ":" + portNumber
                    + "/coordinator";
            theCoorInt = (CoordinatorInterface) Naming.lookup(coorIntURL);
            theCoorInt.registerForCallback(this);
        } catch (Exception e)
        {
            throw new SimulationException(SimulationException.CAD_SIM_CONNECT,
                    e);
        }
    }

    /**
     * This method verifies that the CAD Simulator Host and Port values are not
     * null. Also, if a CAD Position or User ID do not exist in the properties
     * file, the user is prompted to enter values. These values are written to
     * the properties file. If the user cancels the process of entering these
     * values, the verification fails.
     *
     * @param propertiesFile File path (absolute or relative) to the properties
     * file containing configuration data.
     * @return True if the properties file is valid, false if not.
     * @throws SimulationException if there is an exception in verifying the
     * properties file, or if the user cancels input.
     */
    private boolean verifyProperties(String propertiesFile)
            throws SimulationException
    {

        // Load the properties file.
        try
        {
            cadClientProp = new Properties();
            cadClientProp.load(new FileInputStream(propertiesFile));
        } catch (Exception e)
        {
            cadClientLogger.logp(Level.SEVERE, "SimulationManager",
                    "Constructor", "Exception in reading properties file.", e);

            throw new SimulationException(SimulationException.INITIALIZE_ERROR,
                    e);
        }


        // Ensure that the properties file does not have null values for the
        // CAD Simulator's connection information.
        if (cadClientProp.getProperty(PROPERTIES.CAD_SIM_HOST.name) == null
                || cadClientProp.getProperty(PROPERTIES.CAD_SIM_PORT.name) == null)
        {
            cadClientLogger.logp(Level.SEVERE, "SimulationManager",
                    "Constructor", "Null value in properties file.");
            throw new SimulationException(SimulationException.INITIALIZE_ERROR);
        }

        return true;
    }

    /**
     * Format a time in seconds as HH:MM:SS
     *
     * @param l
     * @return
     */
    private String formatInterval(final long l)
    {
        final long hr = TimeUnit.SECONDS.toHours(l);
        final long min = TimeUnit.SECONDS.toMinutes(l - TimeUnit.HOURS.toSeconds(hr));
        final long sec = TimeUnit.SECONDS.toSeconds(l - TimeUnit.HOURS.toSeconds(hr) - TimeUnit.MINUTES.toSeconds(min));
        return String.format("%02d:%02d:%02d", hr, min, sec);
    }

    public void ensureProperShutdown()
    {
        Runtime.getRuntime().addShutdownHook(new Thread()
        {
            public void run()
            {
                try
                {
                    theCoorInt.unregisterForCallback(client);
                } catch (RemoteException e)
                {
                    e.printStackTrace();
                }
            }
        });
    }

    @Override
    public void refresh() throws RemoteException
    {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    /**
     * Construct the CADClient with the properties file path, either from the
     * command line arguments or default.
     *
     * @param args Command line arguments.
     */
    public static void main(String[] args)
    {
        if (System.getProperty("CONFIG_DIR") == null)
        {
            System.setProperty("CONFIG_DIR", "config");
        }

        try
        {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            new CADlogDisplay(System.getProperty("CONFIG_DIR") + System.getProperty("file.separator") + CONFIG_FILE_NAME);

        } catch (Exception e)
        {
            cadClientLogger.logp(Level.SEVERE, "SimulationManager", "Main",
                    "Error initializing application.");

            JOptionPane.showMessageDialog(new JWindow(), e.getMessage(),
                    "Error - Program Exiting", JOptionPane.ERROR_MESSAGE);

            System.exit(-1);
        }

    }
}
