package tmcsim.cadsimulator.viewer.model;

import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import tmcsim.common.CADEnums;
import tmcsim.common.CADEnums.PARAMICS_STATUS;

/**
 * SimulatorStatus represents the status of the current simulation. This
 * information includes:
 *
 * <ul>
 * <li>Current simulation time.</li>
 * <li>Current simulation status.</li>
 * <li>Number of remote CAD Clients connected.</li>
 * <li>Status of Simulation Manager connection.</li>
 * <li>Status of Paramics connection.</li>
 * <li>Paramics Network Loaded</li>
 * <li>Information log messages.</li>
 * <li>Error log messages</li>
 * </ul>
 *
 * @author jdalbey
 * @version 0.1
 */
@SuppressWarnings("serial")
public class CADSimulatorStatus extends java.util.Observable
{

    /**
     * Count of how many CAD clients have connected.
     */
    private int numClientsConnected;
    /**
     * Is the Simulation Manager connected?
     */
    private boolean simMgrStatus;
    /**
     * The current state of the script this simulation has loaded.
     */
    private CADEnums.SCRIPT_STATUS scriptState;
    /**
     * The current simulation elapsed time.
     */
    private long currentTime;
    /**
     * The current state of the connectio to paramics
     */
    private PARAMICS_STATUS paramicsConnectionStatus;
    /**
     * ID of currently loaded paramics network
     */
    private String networkID;
    /**
     * Logging ErrorHandler.
     */
    private SimulatorErrorHandler errorHandler;
    private StringBuffer infoMessages;
    private StringBuffer errorMessages;

    /**
     * Constructor. Initialize GUI Objects. Register the logging handler to
     * listen for log records from all loggers that exist in the
     * "tmcsim.cadsimulator" package structure.
     */
    public CADSimulatorStatus()
    {
        errorHandler = new SimulatorErrorHandler();
        Logger.getLogger("tmcsim.cadsimulator").addHandler(errorHandler);
        scriptState = CADEnums.SCRIPT_STATUS.NO_SCRIPT;
        paramicsConnectionStatus = PARAMICS_STATUS.DISCONNECTED;
        networkID = "";
        numClientsConnected = 0;
        infoMessages = new StringBuffer();
        errorMessages = new StringBuffer();
    }

    public String getInfoMessages()
    {
        return infoMessages.toString();
    }

    public String getErrorMessages()
    {
        return errorMessages.toString();
    }

    /**
     * Method is called when a CAD Client connects to the Server.
     * The displayed number of connected clients is incremented by one.
     */
    public void connectClient()
    {
        numClientsConnected += 1;
        setChanged();
        notifyObservers();

        //termConnectedTF.setText(String.valueOf(numClientsConnected));
    }

    /**
     * Method is called when a CAD Client disconnects from the CAD Simulator.
     * The displayed number of connected clients is decremented by one.
     */
    public void disconnectClient()
    {
        if (numClientsConnected > 0)
        {
            numClientsConnected--;
        }
        setChanged();
        notifyObservers();

        //termConnectedTF.setText(String.valueOf(numClientsConnected));
    }

    /**
     * Accessor to current number of clients.
     *
     * @return number of connected clients
     */
    public int getNumClients()
    {
        return numClientsConnected;
    }

    /**
     * Method is called when Simulation Manager connects or disconnects.
     *
     * @param connection True if simulation manager is connected, false if not.
     */
    public void setSimManagerStatus(boolean connection)
    {
        simMgrStatus = connection;
        setChanged();
        notifyObservers();

        //managerConnectedTF.setText("Yes");
    }

    /**
     * Accessor to Sim Mgr connection status
     *
     * @return number of connected clients
     */
    public boolean isSimManagerConnected()
    {
        return simMgrStatus;
    }

    /**
     * Method called to convert current simulation time (parameter long value)
     * to a string of format H:MM:SS. Time is then updated on GUI.
     *
     * @param seconds Long value of current time
     */
    public void setTime(long seconds)
    {
        currentTime = seconds;
        setChanged();
        notifyObservers();
    }

    public String getCurrentTime()
    {
        String time = new String();
        long timeSegment;
        long seconds = currentTime;
        timeSegment = seconds / 3600;
        time += String.valueOf(timeSegment) + ":";

        seconds = seconds % 3600;

        timeSegment = seconds / 60;
        if (timeSegment < 10)
        {
            time += "0";
        }

        time += String.valueOf(timeSegment) + ":";
        seconds = seconds % 60;

        timeSegment = seconds;
        if (timeSegment < 10)
        {
            time += "0";
        }

        time += String.valueOf(timeSegment);
        return time;
        //simulationClockLabel.setText(time);

    }

    /**
     * Method is called to display the current status of the simulation.
     *
     * @param newStatus Current status of simulation. The following table
     * describes each possible status and what is displayed. Each status code is
     * found as a public static int in the Coordinator Class.
     *
     * <table cellpadding="2" cellspacing="2" border="1" style="text-align:
     * left; width: 250px;">
     * <tbody>
     * <tr>
     * <th>Status<br></th>
     * <th>Actions Taken<br></th>
     * </tr>
     * <tr>
     * <td>NO_SCRIPT<br></td>
     * <td>Set the simulation status text to a black "No Script". <br></td>
     * </tr>
     * <tr>
     * <td>SCRIPT_STOPPED_NOT_STARTED<br></td>
     * <td>Set the simulation status text to a red "Ready". <br></td>
     * </tr>
     * <tr>
     * <td>SCRIPT_PAUSED_STARTED<br></td>
     * <td>Set the simulation status text to a red "Paused". <br></td>
     * </tr>
     * <tr>
     * <td>SCRIPT_RUNNING<br></td>
     * <td>Set the simulation status text to a green "Running". <br></td>
     * </tr>
     * <tr>
     * <td>ATMS_SYNCHRONIZATION<br></td>
     * <td>Set the simulation status text to an orange "Synchronizing".
     * <br></td>
     * </tr>
     * </tbody>
     * </table>
     */
    public void setScriptStatus(CADEnums.SCRIPT_STATUS newStatus)
    {
        scriptState = newStatus;
        setChanged();
        notifyObservers();
    }

    public CADEnums.SCRIPT_STATUS getScriptStatus()
    {
        return scriptState;
    }

    /**
     * Method is called when a connection to paramics is made or dropped.
     *
     * @param newStatus The status denoting whether a connection has been made
     * or dropped.
     */
    public void setParamicsStatus(CADEnums.PARAMICS_STATUS newStatus)
    {
        paramicsConnectionStatus = newStatus;
        setChanged();
        notifyObservers();
    }

    public CADEnums.PARAMICS_STATUS getParamicsStatus()
    {
        return paramicsConnectionStatus;
    }

    /**
     * Method is called when a paramics network is loaded.
     *
     * @param networkID Unique ID for Paramics network that has been loaded.
     */
    public void setParamicsNetworkLoaded(String networkID)
    {
        this.networkID = networkID;
        setChanged();
        notifyObservers();
    }

    public String getParmicsNetworkID()
    {
        return networkID;
    }

    /**
     * Logging Handler to listen for Information and Error messages logged for
     * the CAD Simulator. Received LogRecords are displayed in the info or error
     * message Text Area.
     *
     * @author Matthew Cechini
     */
    private class SimulatorErrorHandler extends Handler
    {

        public void close() throws SecurityException
        {
        }

        public void flush()
        {
        }

        public void publish(LogRecord rec)
        {
            StringBuffer msgBuffer = new StringBuffer();

            msgBuffer.append(rec.getSourceClassName() + "."
                    + rec.getSourceMethodName() + " = "
                    + rec.getMessage());
            // which panel to display in
            if (rec.getLevel() == Level.INFO)
            {
                infoMessages.append(msgBuffer);
            }
            else
            {
                errorMessages.append(msgBuffer);
            }
            setChanged();
            notifyObservers();
        }
    }
}
