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.png");
		}

		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) {
				setVisible(false);
			}
		});
	}

	public void setVisible(boolean visible) {
		if (visible) {
			this.properties.initialise();
		}

		super.setVisible(visible);
	}

	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.setVisible(false);

		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();
		}
	}
}
