package sim;

import java.awt.*;
import java.awt.event.*;

import sim.util.DialogButton;
import sim.util.SimSeparator;
import sim.util.ImagePanel;

public class SimulationProperties extends Dialog implements ActionListener
{
	public static final long SLOWEST_SPEED = 2000;
	
	public static long SPEED = SimulationProperties.SLOWEST_SPEED / 2;
	public static double STEP_SIZE = 0.5;
	public static boolean SHOW_FLOW = true;
	public static Color ONE_COLOR = Color.red;
	public static Color ZERO_COLOR = Color.green;
	
	private static Image ICON;
	
	public static String getColorName(Color c)
	{
		String result = "black";
		
		if(c.getRGB() == Color.red.getRGB())
			result = "red";
		else if(c.getRGB() == Color.green.getRGB())
			result = "green";
		else if(c.getRGB() == Color.blue.getRGB())
			result = "blue";
		else if(c.getRGB() == Color.yellow.getRGB())
			result = "yellow";
		else if(c.getRGB() == Color.cyan.getRGB())
			result = "cyan";
		else if(c.getRGB() == Color.magenta.getRGB())
			result = "magenta";
		else if(c.getRGB() == Color.orange.getRGB())
			result = "orange";
		else if(c.getRGB() == Color.pink.getRGB())
			result = "pink";
		else if(c.getRGB() == Color.white.getRGB())
			result = "white";
		else if(c.getRGB() == Color.gray.getRGB())
			result = "gray";
		else if(c.getRGB() == Color.lightGray.getRGB())
			result = "light gray";
		
		return result;
		
	}
	
	public static Color getColor(String name)
	{
		Color result = Color.black;
		
		if(name.equals("red"))
			result = Color.red;
		else if(name.equals("green"))
			result = Color.green;
		else if(name.equals("blue"))
			result = Color.blue;
		else if(name.equals("yellow"))
			result = Color.yellow;
		else if(name.equals("cyan"))
			result = Color.cyan;
		else if(name.equals("magenta"))
			result = Color.magenta;
		else if(name.equals("orange"))
			result = Color.orange;
		else if(name.equals("pink"))
			result = Color.pink;
		else if(name.equals("white"))
			result = Color.white;
		else if(name.equals("gray"))
			result = Color.gray;
		else if(name.equals("light gray"))
			result = Color.lightGray;
		
		return result;
	}
	
	
	private ActualProperties properties;
	private ImagePanel iconHolder;
	
	public SimulationProperties()
	{
		super(MainWindow.MAIN_WINDOW, "Properties");
		
		if(SimulationProperties.ICON == null)
			SimulationProperties.ICON = GuiFileLink.getImage("sim/images/Simulation.gif");
		
		this.setLayout(new GridBagLayout());
		this.setModal(true);
		this.setResizable(false);
		
		Panel p = new Panel(new FlowLayout(FlowLayout.RIGHT, 10, 10));
		
		DialogButton b = new DialogButton("OK");
		b.addActionListener(this);
		p.add(b);
		b = new DialogButton("Cancel");
		b.addActionListener(this);
		p.add(b);
		
		GridBagConstraints c = new GridBagConstraints();
		c.gridx = 0;
		c.gridy = 2;
		c.gridwidth = 1;
		c.gridheight = 1;
		c.anchor = GridBagConstraints.EAST;
		c.fill = GridBagConstraints.NONE;
		
		this.add(p, c);
		
		this.properties = new ActualProperties();
		
		c.gridy = 1;
		c.insets = new Insets(10, 20, 40, 20);
		c.anchor = GridBagConstraints.CENTER;
		this.add(this.properties, c);
		
		p = new Panel(new FlowLayout(FlowLayout.LEFT, 10, 0));
		this.iconHolder = new ImagePanel(SimulationProperties.ICON);
		p.add(this.iconHolder);
		p.add(new Label("Simulation Properties", Label.LEFT));
		
		c.anchor = GridBagConstraints.WEST;
		c.insets = new Insets(0, 0, 0, 0);
		c.gridy = 0;
		
		this.add(p, c);
		
		this.addWindowListener(new WindowAdapter()
		{
			public void windowClosing(WindowEvent e)
			{
				hide();
			}
		});
	}
	
	public void show()
	{
		this.properties.initialise();
		
		super.show();
	}
	
	public void addNotify()
	{
		super.addNotify();
		
		int width = 40 + this.properties.getSize().width + this.getInsets().left + this.getInsets().right;
		int height = 70 + this.iconHolder.getPreferredSize().height + this.properties.getSize().height + DialogButton.HEIGHT + this.getInsets().top + this.getInsets().bottom;
		this.setSize(width, height);
		doLayout();
		
		this.setLocation(MainWindow.getMiddleOfScreen(this));
	}
	
	public void actionPerformed(ActionEvent e)
	{
		this.hide();
		
		if(((DialogButton)e.getSource()).getLabel().equals("OK"))
			this.properties.ok();
	}
	
	public void paint(Graphics g)
	{	
		super.paint(g);
	
		Rectangle r = this.properties.getBounds();
		
		r.x = r.x - 10;
		r.y = r.y - 5;
		
		r.width = r.width + 20;
		r.height = r.height + 40;
			
		g.setColor(Color.white);
		g.drawLine(r.x, r.y, r.x + r.width - 2, r.y);
		g.drawLine(r.x, r.y, r.x, r.y + r.height - 2);
		
		g.setColor(Color.black);
		g.drawLine(r.x + r.width - 1, r.y, r.x + r.width - 1, r.y + r.height - 1);
		g.drawLine(r.x, r.y + r.height - 1, r.x + r.width - 1, r.y + r.height - 1);
		
		g.setColor(this.getBackground().darker());
		g.drawLine(r.x + r.width - 2, r.y + 1, r.x + r.width - 2, r.y + r.height - 2);
		g.drawLine(r.x + 1, r.y + r.height - 2, r.x + r.width - 2, r.y + r.height - 2);
	}
	
	private class ActualProperties extends Container implements ActionListener, FocusListener, ItemListener, AdjustmentListener
	{
		private TextField editStep = new TextField(10);
		private Checkbox editFlow = new Checkbox("Show data flow", SimulationProperties.SHOW_FLOW);
		private Scrollbar editSpeed = new Scrollbar(Scrollbar.HORIZONTAL, 50, 0, 0, 101);
		
		private Choice editZero = new Choice();
		private Choice editOne = new Choice();
		private Label flow = new Label("Data Flow");
		private Label speed = new Label("Speed");
		
		private double oldStep;
		private Color oldOne;
		private Color oldZero;
		
		public ActualProperties()
		{
			super();
			this.setLayout(new BorderLayout(0, 15));
			
			this.oldStep = SimulationProperties.STEP_SIZE;
			
			this.editStep.addActionListener(this);
			this.editStep.addFocusListener(this);
			this.editStep.setText(Double.toString(this.oldStep));
			
			this.editSpeed.setBlockIncrement(20);
			this.editSpeed.setUnitIncrement(1);
			this.editSpeed.addAdjustmentListener(this);
			
			this.editOne.add("red");
			this.editOne.add("green");
			this.editOne.add("blue");
			this.editOne.add("yellow");
			this.editOne.add("cyan");
			this.editOne.add("magenta");
			this.editOne.add("orange");
			this.editOne.add("pink");
			this.editOne.addItemListener(this);
			this.editOne.addFocusListener(this);
			
			this.editZero.add("red");
			this.editZero.add("green");
			this.editZero.add("blue");
			this.editZero.add("yellow");
			this.editZero.add("cyan");
			this.editZero.add("magenta");
			this.editZero.add("orange");
			this.editZero.add("pink");
			this.editZero.addItemListener(this);
			this.editZero.addFocusListener(this);
			
			// data flow
			Panel big = new Panel(new BorderLayout(0, 15));
			Panel p = new Panel(new BorderLayout());
			p.add(this.flow, BorderLayout.WEST);
			p.add(new SimSeparator(), BorderLayout.CENTER);
			big.add(p, BorderLayout.NORTH);
			
			Panel p2 = new Panel(new GridBagLayout());
			GridBagConstraints c = new GridBagConstraints();
			
			c.weightx = 1;
			c.weighty = 0;
			c.gridheight = 1;
			c.fill = GridBagConstraints.NONE;
			
			c.insets = new Insets(0, 0, 15, 0);
			c.gridwidth = 4;
			c.gridy = 0;
			c.gridx = 0;
			c.anchor = GridBagConstraints.WEST;
			p2.add(this.editFlow, c);
			
			c.insets = new Insets(0, 0, 0, 0);
			c.gridwidth = 1;
			c.gridy = 1;
			c.anchor = GridBagConstraints.EAST;
			p2.add(new Label("Zero"), c);
			
			c.gridx = 1;
			c.anchor = GridBagConstraints.WEST;
			p2.add(this.editZero, c);
			
			c.gridx = 2;
			c.anchor = GridBagConstraints.EAST;
			p2.add(new Label("One"), c);
			
			c.gridx = 3;
			c.anchor = GridBagConstraints.WEST;
			p2.add(this.editOne, c);
			
			big.add(p2, BorderLayout.CENTER);
			this.add(big, BorderLayout.NORTH);
			
			// speed
			big = new Panel(new BorderLayout(0, 15));
			p = new Panel(new BorderLayout());
			p.add(this.speed, BorderLayout.WEST);
			p.add(new SimSeparator(), BorderLayout.CENTER);
			big.add(p, BorderLayout.NORTH);
			
			p2 = new Panel(new GridBagLayout());
			
			c.insets = new Insets(0, 0, 15, 0);
			c.gridx = 0;
			c.gridy = 0;
			c.gridwidth = 3;
			c.anchor = GridBagConstraints.WEST;
			
			p = new Panel(new FlowLayout(FlowLayout.LEFT, 0, 0));
			p.add(new Label("Step size"));
			p.add(this.editStep);
			
			p2.add(p, c);
			
			c.weightx = 0;
			c.gridwidth = 1;
			c.gridx = 0;
			c.gridy = 1;
			c.insets = new Insets(0, 0, 0, 10);
			c.anchor = GridBagConstraints.CENTER;
			
			p2.add(new Label("Slowest"), c);
			
			c.gridx = 2;
			c.insets = new Insets(0, 10, 0, 0);
			
			p2.add(new Label("Fastest"), c);
			
			c.weightx = 1;
			c.insets = new Insets(0, 0, 0, 0);
			c.gridx = 1;
			c.fill = GridBagConstraints.HORIZONTAL;
			
			p2.add(this.editSpeed, c);
			
			big.add(p2, BorderLayout.CENTER);
			
			this.add(big, BorderLayout.CENTER);
		}
		
		public void addNotify()
		{
			super.addNotify();
			this.setSize(290, this.editFlow.getPreferredSize().height + this.editOne.getPreferredSize().height + this.editStep.getPreferredSize().height + this.flow.getPreferredSize().height * 3 + 75);
		}
		
		public void initialise()
		{
			this.oldStep = SimulationProperties.STEP_SIZE;
			this.oldOne = SimulationProperties.ONE_COLOR;
			this.oldZero = SimulationProperties.ZERO_COLOR;
			
			this.editStep.setText(Double.toString(this.oldStep));
			this.editFlow.setState(SimulationProperties.SHOW_FLOW);
			
			this.editOne.select(SimulationProperties.getColorName(this.oldOne));
			this.editZero.select(SimulationProperties.getColorName(this.oldZero));
			
			this.editOne.setBackground(this.oldOne);
			this.editZero.setBackground(this.oldZero);
			
			boolean notSimulating = !SimMenuBar.STOP.isEnabled();
			
			this.editFlow.setEnabled(notSimulating);
			this.editOne.setEnabled(notSimulating);
			this.editZero.setEnabled(notSimulating);
			
			this.editSpeed.setValue(100 - (int)(100 * SimulationProperties.SPEED / SimulationProperties.SLOWEST_SPEED));
		}
		
		public void ok()
		{
			this.handeleStepChange();
			
			SimulationProperties.SPEED = SimulationProperties.SLOWEST_SPEED * (100 - this.editSpeed.getValue()) / 100;
			SimulationProperties.SHOW_FLOW = this.editFlow.getState();
			SimulationProperties.STEP_SIZE = this.oldStep;
			SimulationProperties.ONE_COLOR = this.oldOne;
			SimulationProperties.ZERO_COLOR = this.oldZero;
		}
		
		public void actionPerformed(ActionEvent e)
		{
			this.handeleStepChange();
		}
		
		public void adjustmentValueChanged(AdjustmentEvent e)
		{
			this.editSpeed.requestFocus();
		}
		
		public void itemStateChanged(ItemEvent e)
		{
			String selected;
			
			if(e.getSource() == this.editOne)
			{
				selected = this.editOne.getSelectedItem();
				
				if(!selected.equals(SimulationProperties.getColorName(this.oldZero)))
					this.oldOne = SimulationProperties.getColor(selected);
				else
					this.editOne.select(SimulationProperties.getColorName(this.oldOne));
			}
			else
			{
				selected = this.editZero.getSelectedItem();
				
				if(!selected.equals(SimulationProperties.getColorName(this.oldOne)))
					this.oldZero = SimulationProperties.getColor(selected);
				else
					this.editZero.select(SimulationProperties.getColorName(this.oldZero));
			}
		}
		
		public void focusGained(FocusEvent e)
		{
			if(e.getSource() == this.editOne)
				this.editOne.setBackground(Color.white);
			else if(e.getSource() == this.editZero)
				this.editZero.setBackground(Color.white);
		}
		
		public void focusLost(FocusEvent e)
		{
			String selected;
			
			if(e.getSource() == this.editStep)
			{
				this.handeleStepChange();
				this.editStep.setText(this.editStep.getText());
			}
			else if(e.getSource() == this.editOne)
			{
				selected = this.editOne.getSelectedItem();
				
				if(!selected.equals(SimulationProperties.getColorName(this.oldZero)))
					this.oldOne = SimulationProperties.getColor(selected);
				else
					this.editOne.select(SimulationProperties.getColorName(this.oldOne));
				
				this.editOne.setBackground(this.oldOne);
			}
			else
			{
				selected = this.editZero.getSelectedItem();
				
				if(!selected.equals(SimulationProperties.getColorName(this.oldOne)))
					this.oldZero = SimulationProperties.getColor(selected);
				else
					this.editZero.select(SimulationProperties.getColorName(this.oldZero));
				
				this.editZero.setBackground(this.oldZero);
			}
		}
		
		private void handeleStepChange()
		{
			double newStep;
			
			try
			{
				newStep = Double.valueOf(this.editStep.getText()).doubleValue();
				
				if(newStep > 0)
					this.oldStep = newStep;
				else
					this.editStep.setText(Double.toString(this.oldStep));
			}
			catch(NumberFormatException nfe)
			{
				this.editStep.setText(Double.toString(this.oldStep));
			}
		}
		
		public Dimension getPreferredSize()
		{
			return this.getSize();
		}
		
		public Dimension getMinimumSize()
		{
			return this.getSize();
		}
	
		public Dimension getMaximumSize()
		{
			return this.getSize();
		}
	}
}