package sim.lib.outputs;

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

import sim.*;
import sim.engine.*;
import sim.lib.wires.Junction;
import sim.util.SimSeparator;

public class Led extends RotatableFlippableWrapperPainted implements EngineModule
{
/* ==================================================================
	Creation Part
	================================================================= */
	private static Image ICON = GuiFileLink.getImage("sim/lib/outputs/LedIcon.gif");
	
	public Image getIcon()
	{
		return Led.ICON;
	}
	
	public Wrapper createWrapper()
	{
		return (new Led());
	}
	
	public Wrapper createWrapper(Point gridPosition)
	{
		Led result = new Led();
		result.setGridLocation(gridPosition);
		return result;
	}
	
	public String getBubbleHelp()
	{
		return "LED";
	}
	
/* ==================================================================
	GUI part
	================================================================= */
	public Led()
	{
		super();
		
		this.fill = WrapperPainted.BACKGROUND;
	}
	
	public void initializeGridSize()
	{
		this.setGridSize(4, 4);
	}
	
/* ==================================================================
	Maintanance Part
	================================================================= */
	private Junction input = null;
	
	public void selected()
	{
		this.input.removePin();
		
		this.changeColor(Color.green);
	}
	
	public void checkAfterSelected()
	{
		Wrapper.checkPin(this.input);
	}
	
/* ==================================================================
	Simulation part
	================================================================= */
	private Color one = SimulationProperties.ONE_COLOR;
	private Color zero = SimulationProperties.ZERO_COLOR;
	private Color fill;
	private boolean useDefault = true;
	
	public void evaluateOutput(double currentTime, Data[] currentInputs, EnginePeer peer)
	{
		if(currentInputs[0].isUndefined())
			this.fill = WrapperPainted.BACKGROUND;
		else if(currentInputs[0].getValue())
			this.fill = this.one;
		else
			this.fill = this.zero;
		
		CentralPanel.ACTIVE_GRID.paintComponent(this);
	}
	
	public void createEnginePeer(EnginePeerList epl)
	{
		EnginePeer ep = new EnginePeer(1, this);
		ep.setInputPin(0, this.input.getNodes().getItemAt(0));
		epl.insertItem(ep);
		
		if(this.useDefault)
		{
			this.one = SimulationProperties.ONE_COLOR;
			this.zero = SimulationProperties.ZERO_COLOR;
		}
	}
	
	public void reset()
	{
		this.fill = WrapperPainted.BACKGROUND;
		CentralPanel.ACTIVE_GRID.paintComponent(this);
	}
	
	public Wrapper getParentWrapper()
	{
		return this;
	}
	
/* ==================================================================
	Storage Part
	================================================================= */
	public String getSpecificParameters()
	{	
		return (SimulationProperties.getColorName(this.one) + Wrapper.SEPARATOR + SimulationProperties.getColorName(this.zero) + Wrapper.SEPARATOR + this.useDefault + Wrapper.SEPARATOR);
	}
	
	public void loadWrapper(String[] specificParameters) throws SimException
	{
		if(specificParameters.length == this.getNumberOfSpecificParameters())
		{
			this.useDefault = Boolean.valueOf(specificParameters[2]).booleanValue();
			
			if(this.useDefault)
			{
				this.one = SimulationProperties.ONE_COLOR;
				this.zero = SimulationProperties.ZERO_COLOR;
			}
			else
			{
				this.one = SimulationProperties.getColor(specificParameters[0]);
				this.zero = SimulationProperties.getColor(specificParameters[1]);
			}
		}
		else
			throw (new SimException("incorrect number of parameters"));
	}
	
	public int getNumberOfSpecificParameters()
	{
		return 3;
	}
	
/* ==================================================================
	Rotation abd Flipping Part
	================================================================= */
	
	protected void paintNormal_0(Graphics g)
	{
		int gridGap = CentralPanel.ACTIVE_GRID.getCurrentGridGap();
		int twice = 2 * gridGap;
		int tripple = 3 * gridGap;
		int top = 3 * gridGap / 2;
		int bottom = 4 * gridGap;
		
		g.setColor(this.brush);
		g.drawRect(gridGap, top, twice - 1, gridGap - 1);
		g.drawLine(tripple, twice, bottom, twice);
		
		bottom = bottom - top;
		
		g.setColor(WrapperPainted.BACKGROUND.brighter());
		g.drawLine(gridGap + 1, top + 1, tripple - 2, top + 1);
		g.drawLine(gridGap + 1, top + 1, gridGap + 1, bottom - 2);
		
		g.setColor(WrapperPainted.BACKGROUND.darker());
		g.drawLine(tripple - 2, top + 2, tripple - 2, bottom - 2);
		g.drawLine(gridGap + 1, bottom - 2, tripple - 2, bottom - 2);
		
		g.setColor(this.fill);
		g.fillRect(gridGap + 2, top + 2, twice - 4, gridGap - 4);
	}
	
	protected void paintNormal_90(Graphics g)
	{
		int gridGap = CentralPanel.ACTIVE_GRID.getCurrentGridGap();
		int twice = 2 * gridGap;
		int tripple = 3 * gridGap;
		int top = 3 * gridGap / 2;
		int bottom = 4 * gridGap;
		
		g.setColor(this.brush);
		g.drawRect(gridGap, top, twice - 1, gridGap - 1);
		g.drawLine(twice, 0, twice, top);
		
		bottom = bottom - top;
		
		g.setColor(WrapperPainted.BACKGROUND.brighter());
		g.drawLine(gridGap + 1, top + 1, tripple - 2, top + 1);
		g.drawLine(gridGap + 1, top + 1, gridGap + 1, bottom - 2);
		
		g.setColor(WrapperPainted.BACKGROUND.darker());
		g.drawLine(tripple - 2, top + 2, tripple - 2, bottom - 2);
		g.drawLine(gridGap + 1, bottom - 2, tripple - 2, bottom - 2);
		
		g.setColor(this.fill);
		g.fillRect(gridGap + 2, top + 2, twice - 4, gridGap - 4);
	}
	
	protected void paintNormal_180(Graphics g)
	{
		int gridGap = CentralPanel.ACTIVE_GRID.getCurrentGridGap();
		int twice = 2 * gridGap;
		int tripple = 3 * gridGap;
		int top = 3 * gridGap / 2;
		int bottom = 4 * gridGap;
		
		g.setColor(this.brush);
		g.drawRect(gridGap, top, twice - 1, gridGap - 1);
		g.drawLine(0, twice, gridGap, twice);
		
		bottom = bottom - top;
		
		g.setColor(WrapperPainted.BACKGROUND.brighter());
		g.drawLine(gridGap + 1, top + 1, tripple - 2, top + 1);
		g.drawLine(gridGap + 1, top + 1, gridGap + 1, bottom - 2);
		
		g.setColor(WrapperPainted.BACKGROUND.darker());
		g.drawLine(tripple - 2, top + 2, tripple - 2, bottom - 2);
		g.drawLine(gridGap + 1, bottom - 2, tripple - 2, bottom - 2);
		
		g.setColor(this.fill);
		g.fillRect(gridGap + 2, top + 2, twice - 4, gridGap - 4);
	}
	
	protected void paintNormal_270(Graphics g)
	{
		int gridGap = CentralPanel.ACTIVE_GRID.getCurrentGridGap();
		int twice = 2 * gridGap;
		int tripple = 3 * gridGap;
		int top = 3 * gridGap / 2;
		int bottom = 4 * gridGap;
		
		g.setColor(this.brush);
		g.drawRect(gridGap, top, twice - 1, gridGap - 1);
		g.drawLine(twice, bottom - top, twice, bottom);
		
		bottom = bottom - top;
		
		g.setColor(WrapperPainted.BACKGROUND.brighter());
		g.drawLine(gridGap + 1, top + 1, tripple - 2, top + 1);
		g.drawLine(gridGap + 1, top + 1, gridGap + 1, bottom - 2);
		
		g.setColor(WrapperPainted.BACKGROUND.darker());
		g.drawLine(tripple - 2, top + 2, tripple - 2, bottom - 2);
		g.drawLine(gridGap + 1, bottom - 2, tripple - 2, bottom - 2);
		
		g.setColor(this.fill);
		g.fillRect(gridGap + 2, top + 2, twice - 4, gridGap - 4);
	}
	
	protected void paintFlipped_0(Graphics g)
	{
		this.paintNormal_0(g);
	}
	
	protected void paintFlipped_90(Graphics g)
	{
		this.paintNormal_270(g);
	}
	
	protected void paintFlipped_180(Graphics g)
	{
		this.paintNormal_180(g);
	}
	
	protected void paintFlipped_270(Graphics g)
	{
		this.paintNormal_90(g);
	}
	
	
	
	
	protected boolean canDropNormal_0()
	{
		return Wrapper.canDropJuncion(this.gridLocation.x + 4, this.gridLocation.y + 2, 1);
	}
	
	protected boolean canDropNormal_90()
	{
		return Wrapper.canDropJuncion(this.gridLocation.x + 2, this.gridLocation.y, 1);
	}
	
	protected boolean canDropNormal_180()
	{
		return Wrapper.canDropJuncion(this.gridLocation.x, this.gridLocation.y + 2, 1);
	}
	
	protected boolean canDropNormal_270()
	{
		return Wrapper.canDropJuncion(this.gridLocation.x + 2, this.gridLocation.y + 4, 1);
	}
	
	protected boolean canDropFlipped_0()
	{
		return this.canDropNormal_0();
	}
	
	protected boolean canDropFlipped_90()
	{
		return this.canDropNormal_270();
	}
	
	protected boolean canDropFlipped_180()
	{
		return this.canDropNormal_180();
	}
	
	protected boolean canDropFlipped_270()
	{
		return this.canDropNormal_90();
	}
	
	
	
	
	protected void dropedNormal_0()
	{
		this.input = Wrapper.setPinAt(this.gridLocation.x + 4, this.gridLocation.y + 2, 1);
		this.changeColor(Color.black);
	}
	
	protected void dropedNormal_90()
	{
		this.input = Wrapper.setPinAt(this.gridLocation.x + 2, this.gridLocation.y, 1);
		this.changeColor(Color.black);
	}
	
	protected void dropedNormal_180()
	{
		this.input = Wrapper.setPinAt(this.gridLocation.x, this.gridLocation.y + 2, 1);
		this.changeColor(Color.black);
	}
	
	protected void dropedNormal_270()
	{
		this.input = Wrapper.setPinAt(this.gridLocation.x + 2, this.gridLocation.y + 4, 1);
		this.changeColor(Color.black);
	}
	
	protected void dropedFlipped_0()
	{
		this.dropedNormal_0();
	}
	
	protected void dropedFlipped_90()
	{
		this.dropedNormal_270();
	}
	
	protected void dropedFlipped_180()
	{
		this.dropedNormal_180();
	}
	
	protected void dropedFlipped_270()
	{
		this.dropedNormal_90();
	}
		
	
	
	
	protected void adjustToChanges()
	{
	}
	
	
/* ==================================================================
	Popup Part
	================================================================= */
	public boolean hasProperties()
	{
		return true;
	}
	
	public Component getPropertyWindow()
	{
		return (new LedProperties(this.one, this.zero, this.useDefault));
	}
		
	public void respondToChanges(Component property)
	{
		LedProperties x = (LedProperties)property;
		this.useDefault = x.useDefault();
		this.one = x.getOne();
		this.zero = x.getZero();
	}
	
	private class LedProperties extends Container implements ItemListener
	{
		private Checkbox editDefault = new Checkbox("Use default");
		
		private Choice editZero = new Choice();
		private Choice editOne = new Choice();
		
		private Color oldOne;
		private Color oldZero;
		
		private Label signal = new Label("Signaling");
		
		public LedProperties(Color one, Color zero, boolean standard)
		{
			super();
			this.setLayout(new BorderLayout(0, 0));
			
			this.editDefault.setState(standard);
			this.editDefault.addItemListener(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.add("white");
			this.editOne.add("gray");
			this.editOne.add("light gray");
			this.editOne.addItemListener(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.add("white");
			this.editZero.add("gray");
			this.editZero.add("light gray");
			this.editZero.addItemListener(this);
			
			if(standard)
			{
				this.editOne.setEnabled(false);
				this.editZero.setEnabled(false);
				this.oldOne = SimulationProperties.ONE_COLOR;
				this.oldZero = SimulationProperties.ZERO_COLOR;
			}
			else
			{
				this.editOne.setEnabled(true);
				this.editZero.setEnabled(true);
				this.oldOne = one;
				this.oldZero = zero;
			}
			
			this.editOne.select(SimulationProperties.getColorName(this.oldOne));
			this.editOne.setBackground(this.oldOne);
			this.editZero.select(SimulationProperties.getColorName(this.oldZero));
			this.editZero.setBackground(this.oldZero);
			
			Panel big = new Panel(new BorderLayout(0, 15));
			
			Panel p = new Panel(new BorderLayout());
			p.add(this.signal, 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.editDefault, 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);
		}
		
		public void addNotify()
		{
			super.addNotify();
			this.setSize(290, this.editOne.getPreferredSize().height + this.editDefault.getPreferredSize().height + this.signal.getPreferredSize().height + 30);
		}
		
		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);
					this.editOne.setBackground(this.oldOne);
				}
				else
					this.editOne.select(SimulationProperties.getColorName(this.oldOne));
			}
			else if(e.getSource() == this.editZero)
			{
				selected = this.editZero.getSelectedItem();
				
				if(!selected.equals(SimulationProperties.getColorName(this.oldOne)))
				{
					this.oldZero = SimulationProperties.getColor(selected);
					this.editZero.setBackground(this.oldZero);
				}
				else
					this.editZero.select(SimulationProperties.getColorName(this.oldZero));
			}
			else
			{
				if(this.editDefault.getState())
				{
					this.editOne.setEnabled(false);
					this.editZero.setEnabled(false);
					this.oldOne = SimulationProperties.ONE_COLOR;
					this.oldZero = SimulationProperties.ZERO_COLOR;
					
					this.editOne.select(SimulationProperties.getColorName(this.oldOne));
					this.editOne.setBackground(this.oldOne);
					this.editZero.select(SimulationProperties.getColorName(this.oldZero));
					this.editZero.setBackground(this.oldZero);
				}
				else
				{
					this.editOne.setEnabled(true);
					this.editZero.setEnabled(true);
				}
			}
		}
		
		public Color getZero()
		{
			return this.oldZero;
		}
		
		public Color getOne()
		{
			return this.oldOne;
		}
		
		public boolean useDefault()
		{
			return this.editDefault.getState();
		}
		
		public Dimension getPreferredSize()
		{
			return this.getSize();
		}
		
		public Dimension getMinimumSize()
		{
			return this.getSize();
		}
	
		public Dimension getMaximumSize()
		{
			return this.getSize();
		}
	}
}