package paramsim.paramicssimulator.gui;

import java.awt.Dimension;
import java.text.DateFormat;
import java.util.Observable;
import java.util.Observer;
import java.util.logging.Handler;
import java.util.logging.LogRecord;
import java.util.logging.Logger;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JTabbedPane;

import paramsim.paramicssimulator.ParamicsSimulator;
import paramsim.paramicssimulator.ParamicsSimulatorLogMessage;

/**
 * A class which interfaces a ParamicsSimulator.
 * Contains tabs for the controls, logs for all file IO performed by the Simulator, as well
 * as an error log.
 * 
 * @author Greg Eddington
 */
@SuppressWarnings("serial")
public class ParamicsSimulatorGUI extends JFrame implements Observer
{	
	/** The tabs of the GUI **/
	private JTabbedPane tabs;
	
	/** The Paramics Status Panel **/
	private ParamicsLogPanel paramicsStatusPanel;
	
	/** The Camera Status Panel **/
	private ParamicsLogPanel cameraStatusPanel;
	
	/** The Incident Panel **/
	private ParamicsLogPanel incidentPanel;
	
	/** The Error Panel **/
	private ParamicsLogPanel errorPanel;
	
	/** The Paramics Simulator the GUI is interfacing **/
	private ParamicsSimulator simulator;
	
	/**
	 * Logging handler that writes all received log records to the
	 * error text area.
	 * @author Greg Eddington
	 */
	protected class ParamicsSimulatorErrorLoggerHandler extends Handler 
	{
		DateFormat timeFormat = DateFormat.getTimeInstance();
		public void close() throws SecurityException {}
		public void flush() {}
		public void publish(LogRecord record) { errorPanel.write(record.getMessage()); }		
	}

	/**
	 * Creates a new GUI for the Paramics Simulator.
	 * 
	 * @param simulator The Simulator to interface
	 */
	public ParamicsSimulatorGUI(ParamicsSimulator simulator) 
	{		
		super("Paramics Simulator");
	
		// Set the logger handler
		Logger.getLogger("paramsim.paramicssimulator").addHandler(new ParamicsSimulatorErrorLoggerHandler());
		
		this.simulator = simulator;
		
		initializeGUI();
	}	
	
	/**
	 * Updates the GUI when something being observed changes.
	 * 
	 * If the argument is a ParamicSimulatorLogMessage, switch on which log the message
	 * is for and update the appropriate log panel.
	 */
	public void update(Observable o, Object arg) 
	{	
		if(arg instanceof ParamicsSimulatorLogMessage) 
		{
			ParamicsSimulatorLogMessage logMessage = (ParamicsSimulatorLogMessage)arg;
			switch (logMessage.log)
			{
				case PARAMICS_STATUS:
					paramicsStatusPanel.write(logMessage.message);
					break;
				case CAMERA_STATUS:
					cameraStatusPanel.write(logMessage.message);
					break;
				case EXCHANGE:
					incidentPanel.write(logMessage.message);
					break;
			}
		}
	}
	
	/** Initializes the GUI **/
	public void initializeGUI() 
	{	
		// Create tab layout
		tabs = new JTabbedPane();
		tabs.setAlignmentX(Box.CENTER_ALIGNMENT);
		tabs.setMinimumSize(new Dimension(440, 440));
		tabs.setPreferredSize(new Dimension(440, 440));
		tabs.setMaximumSize(new Dimension(440, 440));
		tabs.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
		
		Box guiBox = new Box(BoxLayout.Y_AXIS);
		guiBox.add(tabs);
		add(guiBox);
	
		// Add tabs
		tabs.add("Control", new ParamicsControlPanel(simulator));
		paramicsStatusPanel = new ParamicsLogPanel();
		tabs.add("Paramics Status", paramicsStatusPanel);
		cameraStatusPanel = new ParamicsLogPanel();
		tabs.add("Camera Status", cameraStatusPanel);
		incidentPanel = new ParamicsLogPanel();
		tabs.add("Incidents", incidentPanel);
		errorPanel = new ParamicsLogPanel();
		tabs.add("Errors", errorPanel);
		
		// Set size
		setMinimumSize(new Dimension(450, 450));
		setPreferredSize(new Dimension(450, 450));
		setResizable(false);
		pack();
		setVisible(true);
	}
}
