package paramsim.paramicssimulator.gui;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.JPanel;
import javax.swing.JRadioButton;

import paramsim.paramicssimulator.ParamicsSimulator;
import paramsim.paramicssimulator.SimulationCamera;
import paramsim.paramicssimulator.ParamicsSimulator.NETWORK_STATUS;

/**
 * A JPanel which provides an interface to control the Paramics Simulator.
 * Contains a Paramics Status interface using radio buttons, and multiple
 * Camera Status interfaces using radio buttons.
 * 
 * @author Greg Eddington
 */
@SuppressWarnings("serial")
public class ParamicsControlPanel extends JPanel implements ActionListener
{
	/** The simulator **/
	private ParamicsSimulator simulator;
	
	/** Loading Status **/
	private final static String LOADING = "Loading";
	
	/** Warming Status **/
	private final static String WARMING = "Warming";
	
	/** Loaded Status **/
	private final static String LOADED = "Loaded";
	
	/** Free Flow Speed Label **/
	private final static String FREE_FLOW = "Free Flow";
	
	/** Slow Speed Label **/
	private final static String SLOW = "Slow";
	
	/** Stopped Speed Label **/
	private final static String STOPPED = "Stopped";
	
	/** Fast Camera Status Character ID **/
	private final static Character FAST_CHARACTER = 'F';
	
	/** Medium Camera Status Character ID **/
	private final static Character MEDIUM_CHARACTER = 'M';
	
	/** Slow Camera Status Character ID **/
	private final static Character SLOW_CHARACTER = 'S';
	
	/** Constructor **/
	public ParamicsControlPanel(ParamicsSimulator simulator)
	{
		this.simulator = simulator;
		
		Box controlsBox = new Box(BoxLayout.Y_AXIS);
		controlsBox.setAlignmentY(Box.CENTER_ALIGNMENT);

		controlsBox.add(Box.createVerticalStrut(20));
		controlsBox.add(CreateStatusBox());
		controlsBox.add(Box.createVerticalStrut(20));
		controlsBox.add(CreateCameraBox());
		
		add(controlsBox);
	}
	
	/** Create a Paramics Status GUI box **/
	private Box CreateStatusBox()
	{
		Box radioBox = new Box(BoxLayout.X_AXIS);
		
		ButtonGroup radioButtons = new ButtonGroup();	
		
		JRadioButton loadingButton = new JRadioButton(LOADING);
		loadingButton.setActionCommand(LOADING);
		JRadioButton warmingButton = new JRadioButton(WARMING);
		warmingButton.setActionCommand(WARMING);
		JRadioButton loadedButton = new JRadioButton(LOADED);
		loadedButton.setActionCommand(LOADED);
		
		loadingButton.addActionListener(this);
		warmingButton.addActionListener(this);
		loadedButton.addActionListener(this);
		
		loadingButton.setSelected(true);
		
		radioButtons.add(loadingButton);
		radioButtons.add(warmingButton);
		radioButtons.add(loadedButton);
		
		radioBox.add(loadingButton);
		radioBox.add(Box.createHorizontalStrut(25));
		radioBox.add(warmingButton);
		radioBox.add(Box.createHorizontalStrut(25));
		radioBox.add(loadedButton);
		
		Box statusBox = new Box(BoxLayout.Y_AXIS);
		statusBox.setBorder( BorderFactory.createCompoundBorder(
								BorderFactory.createTitledBorder("Paramics Status"), 
								BorderFactory.createEmptyBorder(0, 40, 10, 40) ) );
		statusBox.add(radioBox);
		
		return statusBox;
	}
	
	/** Creates a Camera Status GUI box **/
	private Box CreateCameraBox()
	{
		Box camerasBox = new Box(BoxLayout.Y_AXIS);
		Box cameraLineBox = new Box(BoxLayout.X_AXIS);
		
		for (int i = 1; i <= simulator.getCameras().size(); i++)
		{
			Box cameraBox = new Box(BoxLayout.Y_AXIS);
			cameraBox.setBorder( BorderFactory.createCompoundBorder(
				BorderFactory.createTitledBorder("Camera " + simulator.getCameras().get(i-1).id), 
				BorderFactory.createEmptyBorder(0, 5, 10, 5) ) );
			ButtonGroup radioButtons = new ButtonGroup();
			
			JRadioButton fastButton = new JRadioButton(FREE_FLOW);
			JRadioButton mediumButton = new JRadioButton(SLOW);
			JRadioButton slowButton = new JRadioButton(STOPPED);
			slowButton.setSelected(true);
	
			fastButton.setActionCommand(FAST_CHARACTER + Integer.toString(i-1));
			mediumButton.setActionCommand(MEDIUM_CHARACTER + Integer.toString(i-1));
			slowButton.setActionCommand(SLOW_CHARACTER + Integer.toString(i-1));
			
			fastButton.addActionListener(this);
			mediumButton.addActionListener(this);
			slowButton.addActionListener(this);
			
			radioButtons.add(fastButton);
			radioButtons.add(mediumButton);
			radioButtons.add(slowButton);
			cameraBox.add(fastButton);
			cameraBox.add(mediumButton);
			cameraBox.add(slowButton);
			
			cameraLineBox.add(cameraBox);
			cameraLineBox.add(Box.createHorizontalStrut(20));
			
			if (i % 3 == 0 && i != simulator.getCameras().size())
			{
				camerasBox.add(cameraLineBox);
				camerasBox.add(Box.createVerticalStrut(15));
				cameraLineBox = new Box(BoxLayout.X_AXIS);
			}
		}
		camerasBox.add(cameraLineBox);
		camerasBox.add(Box.createVerticalStrut(15));
		cameraLineBox = new Box(BoxLayout.X_AXIS);
		
		return camerasBox;
	}

	/** 
	 * Listens for actions performed in the GUI.
	 * 
	 * A Paramics Status action will be either LOADING, WARMING, or LOADED.  If
	 * recieved, the writeParamicsStatus function will be called from the simulator
	 * with the appropriate message.
	 * 
	 * Any other action is considered a Camera Status Action.  The first character
	 * of the action command is either FAST_CHARACTER, MEDIUM_CHARACTER, or SLOW_CHARACTER,
	 * with the remainder of the command being the ID# of the camera.  The writeCameraStatus
	 * function of the simulator will be called with the appropriate information.
	 */
	public void actionPerformed(ActionEvent e) 
	{
		String command = e.getActionCommand();
		if (command == LOADING)
		{
			simulator.writeParamicsStatus(NETWORK_STATUS.LOADING);
		}
		else if (command == WARMING)
		{
			simulator.writeParamicsStatus(NETWORK_STATUS.WARMING);
		}
		else if (command == LOADED)
		{
			simulator.writeParamicsStatus(NETWORK_STATUS.LOADED);
		}
		else // Camera Speed Status
		{
			List<SimulationCamera> cameras = simulator.getCameras();
			SimulationCamera camera = cameras.get(Integer.parseInt(command.substring(1)));
			
			if (e.getActionCommand().charAt(0) == FAST_CHARACTER)
			{
				camera.averageSpeedNE = camera.averageSpeedSW =
					((camera.minFreeFlowSpeed + camera.maxFreeFlowSpeed) / 2);
			}
			else if (e.getActionCommand().charAt(0) == MEDIUM_CHARACTER)
			{
				camera.averageSpeedNE = camera.averageSpeedSW =
					((camera.minSlowSpeed + camera.maxSlowSpeed) / 2);
			}
			else if (e.getActionCommand().charAt(0) == SLOW_CHARACTER)
			{
				camera.averageSpeedNE = camera.averageSpeedSW =
					((camera.minStoppedSpeed + camera.maxStoppedSpeed) / 2);
			}
			
			simulator.writeCameraStatus(cameras);
		}
	}
}
