Index: /trunk/src/tmcsim/client/ATMSDriverClient.java
===================================================================
--- /trunk/src/tmcsim/client/ATMSDriverClient.java	(revision 102)
+++ /trunk/src/tmcsim/client/ATMSDriverClient.java	(revision 102)
@@ -0,0 +1,269 @@
+package tmcsim.client;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.FileInputStream;
+import java.rmi.Naming;
+import java.rmi.RemoteException;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.Properties;
+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 tmcsim.common.SimulationException;
+import tmcsim.interfaces.CADClientInterface;
+import tmcsim.interfaces.CoordinatorInterface;
+
+/**
+ * Skeleton for ATMS Driver that reads a "batch" file of highway
+ * status update commands. 
+ * It operates as a client of the
+ * CAD server, using RMI to poll the server every second for the current
+ * simulation clock time.  It uses the simulation clock time
+ * to fire update commands at the desired time.
+ * Note: Sim Mgr must be running before starting this application.
+ *
+ * @author jdalbey
+ */
+public class ATMSDriverClient extends UnicastRemoteObject implements
+        CADClientInterface
+{
+    /**
+     * Error logger.
+     */
+    private static Logger cadClientLogger = Logger.getLogger("tmcsim.client");
+
+    @Override
+    public void refresh() throws RemoteException
+    {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    /**
+     * 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;
+    private static final String CONFIG_FILE_NAME = "cad_client_config.properties";
+    private final static int ONE_SECOND = 1000;
+
+    /**
+     * 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 ATMSDriverClient(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());
+
+        // READ THE BATCH FILE OF COMMANDS and put in a queue
+        // Consider special cases:  1) time to fire first command
+        // has already past when application starts.
+        // 2.  Two commands have same fire time specified.
+        // 3.  How to "override" a command, to clear an incident.
+        
+        // Create a timer that fetches the simulation time every second.
+        Timer timer = new Timer(ONE_SECOND, new ActionListener()
+        {
+            public void actionPerformed(ActionEvent e)
+            {
+                try
+                {
+                    long simtime = theCoorInt.getCurrentSimulationTime();
+                    // Check the queue of commands to see if the first
+                    // item matches the current time.  IF so, 
+                    // issue that command and remove it from queue.
+                    
+                    //theView.updateTime("" + formatInterval(simtime));
+                } catch (RemoteException ex)
+                {
+                    Logger.getLogger(ATMSDriverClient.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();
+                }
+            }
+        });
+    }
+
+    /**
+     * 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 ATMSDriverClient(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);
+        }
+
+    }
+}
