package sim.lib.gates;

import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.util.Scanner;

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

public class GateXOR extends RotatableFlippableWrapperPainted implements EngineModule
{
/* ==================================================================
	Creation Part
	================================================================= */
	private static Image ICON = GuiFileLink.getImage("sim/lib/gates/XorIcon.gif");
	
	public Image getIcon()
	{
		return GateXOR.ICON;
	}
	
	public Wrapper createWrapper()
	{
		return this.getCopy();
	}
	
	public Wrapper createWrapper(Point gridPosition)
	{
		GateXOR result = this.getCopy();
		result.setGridLocation(gridPosition);
		return result;
	}
	
	public String getBubbleHelp()
	{
		return "XOR gate";
	}
	
/* ==================================================================
	GUI part
	================================================================= */
	public GateXOR()
	{
		super();
	}
	
	private GateXOR getCopy()
	{
		GateXOR result = new GateXOR();
		
		result.setOutputInvert(this.invertOutput);
		result.setInput1Invert(this.invertInput1);
		result.setInput2Invert(this.invertInput2);
		
		result.changeDelay(this.delay);
		
		return result;
	}
	
	public void initializeGridSize()
	{
		this.setGridSize(6, 4);
	}
	
/* ==================================================================
	Maintanance Part
	================================================================= */
	private Junction input1 = null;
	private Junction input2 = null;
	private Junction output = null;
	private boolean invertOutput = false;
	private boolean invertInput1 = false;
	private boolean invertInput2 = false;
	
	public void setOutputInvert(boolean invert)
	{
		this.invertOutput = invert;
	}
	
	public void setInput1Invert(boolean invert)
	{
		this.invertInput1 = invert;
	}
	
	public void setInput2Invert(boolean invert)
	{
		this.invertInput2 = invert;
	}
	
	public void selected()
	{
		this.input1.removePin();
		this.input2.removePin();
		this.output.removePin();
		
		this.changeColor(Color.green);
	}
	
	public void checkAfterSelected()
	{
		Wrapper.checkPin(this.input1);
		Wrapper.checkPin(this.input2);
		Wrapper.checkPin(this.output);
	}
/* ==================================================================
	Simulation part
	================================================================= */
	protected double delay = 1;
	
	public void evaluateOutput(double currentTime, Data[] currentInputs, EnginePeer peer)
	{
		double time = this.delay + currentTime;
		
		if(currentInputs[0].isUndefined() || currentInputs[1].isUndefined())
			peer.setOutputPinUndefined(0, time);
		else
			peer.setOutputPinValue(0, this.invertOutput ^ ((currentInputs[0].getValue() ^ this.invertInput1) ^ (currentInputs[1].getValue() ^ this.invertInput2)), time);
	}
	
	public void createEnginePeer(EnginePeerList epl)
	{
		EnginePeer ep = new EnginePeer(2, 1, this);
		
		ep.setInputPin(0, this.input1.getNodes().getItemAt(0));
		ep.setInputPin(1, this.input2.getNodes().getItemAt(0));
		
		ep.setOutputPin(0, this.output.getNodes().getItemAt(0));
		
		epl.insertItem(ep);
	}
	
	public void reset()
	{	
	}
	
	public Wrapper getParentWrapper()
	{
		return this;
	}

	public double getDelay()
	{
		return this.delay;
	}
	
	public void changeDelay(double newValue)
	{
		this.delay = newValue;
	}
	
/* ==================================================================
	Storage Part
	================================================================= */
	public String getSpecificParameters()
	{
		return (Double.toString(this.delay) + Wrapper.SEPARATOR + this.invertOutput + Wrapper.SEPARATOR + this.invertInput1 + Wrapper.SEPARATOR + this.invertInput2 + Wrapper.SEPARATOR);
	}
	
	public void loadWrapper(String[] specificParameters) throws SimException
	{
		if(specificParameters.length == this.getNumberOfSpecificParameters())
		{
			try
			{
				this.delay = Double.valueOf(specificParameters[0]).doubleValue();
				
				this.setOutputInvert(Boolean.valueOf(specificParameters[1]).booleanValue());
				this.setInput1Invert(Boolean.valueOf(specificParameters[2]).booleanValue());
				this.setInput2Invert(Boolean.valueOf(specificParameters[3]).booleanValue());
			}
			catch(NumberFormatException e)
			{
				throw (new SimException("incorrect parameter type"));
			}
		}
		else
			throw (new SimException("incorrect number of parameters"));
	}
	
	public int getNumberOfSpecificParameters()
	{
		return 4;
	}
	
/* ==================================================================
	Rotation abd Flipping Part
	================================================================= */
	
	protected void paintNormal_0(Graphics g)
	{
		int gridGap = CentralPanel.ACTIVE_GRID.getCurrentGridGap();
		int increment = gridGap / 4;
		
		int diameter = 2 * increment;
		int width = 6 * gridGap;
		
		int center = 2 * gridGap;
		
		g.setColor(this.brush);
		
		if(this.invertOutput)
		{
			g.drawLine(20 * increment + 1, center, width, center);
			g.drawOval(18 * increment + 1, 7 * increment, diameter, diameter);
		}
		else
			g.drawLine(18 * increment, center, width, center);
		
		if(this.invertInput1)
		{
			g.drawLine(0, gridGap, gridGap - 1, gridGap);
			g.drawOval(gridGap - 1, 3 * increment, diameter, diameter);
		}
		else
			g.drawLine(0, gridGap, 6 * increment, gridGap);
		
		if(this.invertInput2)
		{
			g.drawLine(0, 3 * gridGap, gridGap - 1, 3 * gridGap);
			g.drawOval(gridGap - 1, 11 * increment, diameter, diameter);
		}
		else
			g.drawLine(0, 3 * gridGap, 6 * increment, 3 * gridGap);
		
		Shape old = g.getClip();
		g.setClip(6 * increment, 3 * increment, 18 * increment, 10 * increment + 1);
		g.drawOval(-increment, 0, center, 4 * gridGap);
		
		g.setClip(center, 3 * increment, 4 * gridGap, 10 * increment);
		g.drawOval(increment, 0, center, 4 * gridGap);
				
		g.setClip(old);
		
		g.drawLine(center, 13 * increment, 11 * increment, 13 * increment);
		
		g.setClip(11 * increment, center, 4 * gridGap, center);
		g.drawOval(diameter, - 5 * increment, 17 * increment, 18 * increment);
		g.setClip(old);
		
		g.drawLine(center, 3 * increment, 11 * increment, 3 * increment);
		
		g.setClip(11 * increment, 0, 4 * gridGap, center);
		g.drawOval(diameter, 3 * increment, 17 * increment, 18 * increment);
		g.setClip(old);
	}
	
	protected void paintNormal_90(Graphics g)
	{
		int gridGap = CentralPanel.ACTIVE_GRID.getCurrentGridGap();
		int increment = gridGap / 4;
		
		int diameter = 2 * increment;
		int width = 6 * gridGap;
		
		int center = 2 * gridGap;
		
		g.setColor(this.brush);
		
		if(this.invertOutput)
		{
			g.drawLine(center, gridGap - 1, center, 0);
			g.drawOval(7 * increment, gridGap - 1, diameter, diameter);
		}
		else
			g.drawLine(center,6 * increment, center, 0);
		
		if(this.invertInput1)
		{
			g.drawLine(gridGap, width, gridGap, 20 * increment + 1);
			g.drawOval(3 * increment, 18 * increment + 1, diameter, diameter);
		}
		else
			g.drawLine(gridGap, width, gridGap, 18 * increment);
		
		if(this.invertInput2)
		{
			g.drawLine(3 * gridGap, width, 3 * gridGap, 20 * increment + 1);
			g.drawOval(11 * increment, 18 * increment + 1, diameter, diameter);
		}
		else
			g.drawLine(3 * gridGap, width, 3 * gridGap, 18 * increment);
		
		Shape old = g.getClip();
		g.setClip(3 * increment, 0, 10 * increment + 1, 18 * increment);
		g.drawOval(0, 17 * increment, 4 * gridGap, center);
		
		g.setClip(3 * increment, 0, 10 * increment, 4 * gridGap);
		g.drawOval(0, 15 * increment, 4 * gridGap, center);
		
		g.setClip(old);
		
		g.drawLine(13 * increment, 4 * gridGap, 13 * increment, 13 * increment);
		
		g.setClip(center, - 3 * increment, center, 4 * gridGap);
		g.drawOval(- 5 * increment, 5 * increment, 18 * increment, 17 * increment);
		g.setClip(old);
		
		g.drawLine(3 * increment, 4 * gridGap, 3 * increment, 13 * increment);
		
		g.setClip(0, - 3 * increment, center, 4 * gridGap);
		g.drawOval(3 * increment, 5 * increment, 18 * increment, 17 * increment);
		g.setClip(old);
	}
	
	protected void paintNormal_180(Graphics g)
	{
		int gridGap = CentralPanel.ACTIVE_GRID.getCurrentGridGap();
		int increment = gridGap / 4;
		
		int diameter = 2 * increment;
		int width = 6 * gridGap;
		
		int center = 2 * gridGap;
		
		g.setColor(this.brush);
		
		if(this.invertOutput)
		{
			g.drawLine(gridGap - 1, center, 0, center);
			g.drawOval(gridGap - 1, 7 * increment, diameter, diameter);
		}
		else
			g.drawLine(6 * increment, center, 0, center);
		
		if(this.invertInput2)
		{
			g.drawLine(width, gridGap, 20 * increment + 1, gridGap);
			g.drawOval(18 * increment + 1, 3 * increment, diameter, diameter);
		}
		else
			g.drawLine(width, gridGap, 18 * increment, gridGap);
		
		if(this.invertInput1)
		{
			g.drawLine(width, 3 * gridGap, 20 * increment + 1, 3 * gridGap);
			g.drawOval(18 * increment + 1, 11 * increment, diameter, diameter);
		}
		else
			g.drawLine(width, 3 * gridGap, 18 * increment, 3 * gridGap);
		
		Shape old = g.getClip();
		g.setClip(0, 3 * increment, 18 * increment, 10 * increment + 1);
		g.drawOval(17 * increment, 0, center, 4 * gridGap);
		
		g.setClip(0, 3 * increment, 4 * gridGap, 10 * increment);
		g.drawOval(15 * increment, 0, center, 4 * gridGap);
		
		g.setClip(old);
		
		g.drawLine(4 * gridGap, 13 * increment, 13 * increment, 13 * increment);
		
		g.setClip(- 3 * increment, center, 4 * gridGap, center);
		g.drawOval(5 * increment, - 5 * increment, 17 * increment, 18 * increment);
		g.setClip(old);
		
		g.drawLine(4 * gridGap, 3 * increment, 13 * increment, 3 * increment);
		
		g.setClip(- 3 * increment, 0, 4 * gridGap, center);
		g.drawOval(5 * increment, 3 * increment, 17 * increment, 18 * increment);
		g.setClip(old);
	}
	
	protected void paintNormal_270(Graphics g)
	{
		int gridGap = CentralPanel.ACTIVE_GRID.getCurrentGridGap();
		int increment = gridGap / 4;
		
		int diameter = 2 * increment;
		int width = 6 * gridGap;
		
		int center = 2 * gridGap;
		
		g.setColor(this.brush);
		
		if(this.invertOutput)
		{
			g.drawLine(center, 20 * increment + 1, center, width);
			g.drawOval(7 * increment, 18 * increment + 1, diameter, diameter);
		}
		else
			g.drawLine(center, 18 * increment, center, width);
		
		if(this.invertInput2)
		{
			g.drawLine(gridGap, 0, gridGap, gridGap - 1);
			g.drawOval(3 * increment, gridGap - 1, diameter, diameter);
		}
		else
			g.drawLine(gridGap, 0, gridGap, 6 * increment);
		
		if(this.invertInput1)
		{
			g.drawLine(3 * gridGap, 0, 3 * gridGap, gridGap - 1);
			g.drawOval(11 * increment, gridGap - 1, diameter, diameter);
		}
		else
			g.drawLine(3 * gridGap, 0, 3 * gridGap, 6 * increment);
		
		Shape old = g.getClip();
		g.setClip(3 * increment, 6 * increment, 10 * increment + 1, 18 * increment);
		g.drawOval(0, -increment, 4 * gridGap, center);
		
		g.setClip(3 * increment, center, 10 * increment, 4 * gridGap);
		g.drawOval(0, increment, 4 * gridGap, center);	
		g.setClip(old);
		
		g.drawLine(13 * increment, center, 13 * increment, 11 * increment);
		
		g.setClip(center, 11 * increment, center, 4 * gridGap);
		g.drawOval(- 5 * increment, diameter, 18 * increment, 17 * increment);
		g.setClip(old);
		
		g.drawLine(3 * increment, center, 3 * increment, 11 * increment);
		
		g.setClip(0, 11 * increment, center, 4 * gridGap);
		g.drawOval(3 * increment, diameter, 18 * increment, 17 * increment);
		g.setClip(old);
	}
	
	protected void paintFlipped_0(Graphics g)
	{
		int gridGap = CentralPanel.ACTIVE_GRID.getCurrentGridGap();
		int increment = gridGap / 4;
		
		int diameter = 2 * increment;
		int width = 6 * gridGap;
		
		int center = 2 * gridGap;
		
		g.setColor(this.brush);
		
		if(this.invertOutput)
		{
			g.drawLine(20 * increment + 1, center, width, center);
			g.drawOval(18 * increment + 1, 7 * increment, diameter, diameter);
		}
		else
			g.drawLine(18 * increment, center, width, center);
		
		if(this.invertInput2)
		{
			g.drawLine(0, gridGap, gridGap - 1, gridGap);
			g.drawOval(gridGap - 1, 3 * increment, diameter, diameter);
		}
		else
			g.drawLine(0, gridGap, 6 * increment, gridGap);
		
		if(this.invertInput1)
		{
			g.drawLine(0, 3 * gridGap, gridGap - 1, 3 * gridGap);
			g.drawOval(gridGap - 1, 11 * increment, diameter, diameter);
		}
		else
			g.drawLine(0, 3 * gridGap, 6 * increment, 3 * gridGap);
		
		Shape old = g.getClip();
		g.setClip(6 * increment, 3 * increment, 18 * increment, 10 * increment + 1);
		g.drawOval(-increment, 0, center, 4 * gridGap);
		
		g.setClip(center, 3 * increment, 4 * gridGap, 10 * increment);
		g.drawOval(increment, 0, center, 4 * gridGap);
				
		g.setClip(old);
		
		g.drawLine(center, 13 * increment, 11 * increment, 13 * increment);
		
		g.setClip(11 * increment, center, 4 * gridGap, center);
		g.drawOval(diameter, - 5 * increment, 17 * increment, 18 * increment);
		g.setClip(old);
		
		g.drawLine(center, 3 * increment, 11 * increment, 3 * increment);
		
		g.setClip(11 * increment, 0, 4 * gridGap, center);
		g.drawOval(diameter, 3 * increment, 17 * increment, 18 * increment);
		g.setClip(old);
	}
	
	protected void paintFlipped_90(Graphics g)
	{
		int gridGap = CentralPanel.ACTIVE_GRID.getCurrentGridGap();
		int increment = gridGap / 4;
		
		int diameter = 2 * increment;
		int width = 6 * gridGap;
		
		int center = 2 * gridGap;
		
		g.setColor(this.brush);
		
		if(this.invertOutput)
		{
			g.drawLine(center, 20 * increment + 1, center, width);
			g.drawOval(7 * increment, 18 * increment + 1, diameter, diameter);
		}
		else
			g.drawLine(center, 18 * increment, center, width);
		
		if(this.invertInput1)
		{
			g.drawLine(gridGap, 0, gridGap, gridGap - 1);
			g.drawOval(3 * increment, gridGap - 1, diameter, diameter);
		}
		else
			g.drawLine(gridGap, 0, gridGap, 6 * increment);
		
		if(this.invertInput2)
		{
			g.drawLine(3 * gridGap, 0, 3 * gridGap, gridGap - 1);
			g.drawOval(11 * increment, gridGap - 1, diameter, diameter);
		}
		else
			g.drawLine(3 * gridGap, 0, 3 * gridGap, 6 * increment);
		
		Shape old = g.getClip();
		g.setClip(3 * increment, 6 * increment, 10 * increment + 1, 18 * increment);
		g.drawOval(0, -increment, 4 * gridGap, center);
		
		g.setClip(3 * increment, center, 10 * increment, 4 * gridGap);
		g.drawOval(0, increment, 4 * gridGap, center);	
		g.setClip(old);
		
		g.drawLine(13 * increment, center, 13 * increment, 11 * increment);
		
		g.setClip(center, 11 * increment, center, 4 * gridGap);
		g.drawOval(- 5 * increment, diameter, 18 * increment, 17 * increment);
		g.setClip(old);
		
		g.drawLine(3 * increment, center, 3 * increment, 11 * increment);
		
		g.setClip(0, 11 * increment, center, 4 * gridGap);
		g.drawOval(3 * increment, diameter, 18 * increment, 17 * increment);
		g.setClip(old);
	}
	
	protected void paintFlipped_180(Graphics g)
	{
		int gridGap = CentralPanel.ACTIVE_GRID.getCurrentGridGap();
		int increment = gridGap / 4;
		
		int diameter = 2 * increment;
		int width = 6 * gridGap;
		
		int center = 2 * gridGap;
		
		g.setColor(this.brush);
		
		if(this.invertOutput)
		{
			g.drawLine(gridGap - 1, center, 0, center);
			g.drawOval(gridGap - 1, 7 * increment, diameter, diameter);
		}
		else
			g.drawLine(6 * increment, center, 0, center);
		
		if(this.invertInput1)
		{
			g.drawLine(width, gridGap, 20 * increment + 1, gridGap);
			g.drawOval(18 * increment + 1, 3 * increment, diameter, diameter);
		}
		else
			g.drawLine(width, gridGap, 18 * increment, gridGap);
		
		if(this.invertInput2)
		{
			g.drawLine(width, 3 * gridGap, 20 * increment + 1, 3 * gridGap);
			g.drawOval(18 * increment + 1, 11 * increment, diameter, diameter);
		}
		else
			g.drawLine(width, 3 * gridGap, 18 * increment, 3 * gridGap);
		
		Shape old = g.getClip();
		g.setClip(0, 3 * increment, 18 * increment, 10 * increment + 1);
		g.drawOval(17 * increment, 0, center, 4 * gridGap);
		
		g.setClip(0, 3 * increment, 4 * gridGap, 10 * increment);
		g.drawOval(15 * increment, 0, center, 4 * gridGap);
		
		g.setClip(old);
		
		g.drawLine(4 * gridGap, 13 * increment, 13 * increment, 13 * increment);
		
		g.setClip(- 3 * increment, center, 4 * gridGap, center);
		g.drawOval(5 * increment, - 5 * increment, 17 * increment, 18 * increment);
		g.setClip(old);
		
		g.drawLine(4 * gridGap, 3 * increment, 13 * increment, 3 * increment);
		
		g.setClip(- 3 * increment, 0, 4 * gridGap, center);
		g.drawOval(5 * increment, 3 * increment, 17 * increment, 18 * increment);
		g.setClip(old);
	}
	
	protected void paintFlipped_270(Graphics g)
	{
		int gridGap = CentralPanel.ACTIVE_GRID.getCurrentGridGap();
		int increment = gridGap / 4;
		
		int diameter = 2 * increment;
		int width = 6 * gridGap;
		
		int center = 2 * gridGap;
		
		g.setColor(this.brush);
		
		if(this.invertOutput)
		{
			g.drawLine(center, gridGap - 1, center, 0);
			g.drawOval(7 * increment, gridGap - 1, diameter, diameter);
		}
		else
			g.drawLine(center,6 * increment, center, 0);
		
		if(this.invertInput2)
		{
			g.drawLine(gridGap, width, gridGap, 20 * increment + 1);
			g.drawOval(3 * increment, 18 * increment + 1, diameter, diameter);
		}
		else
			g.drawLine(gridGap, width, gridGap, 18 * increment);
		
		if(this.invertInput1)
		{
			g.drawLine(3 * gridGap, width, 3 * gridGap, 20 * increment + 1);
			g.drawOval(11 * increment, 18 * increment + 1, diameter, diameter);
		}
		else
			g.drawLine(3 * gridGap, width, 3 * gridGap, 18 * increment);
		
		Shape old = g.getClip();
		g.setClip(3 * increment, 0, 10 * increment + 1, 18 * increment);
		g.drawOval(0, 17 * increment, 4 * gridGap, center);
		
		g.setClip(3 * increment, 0, 10 * increment, 4 * gridGap);
		g.drawOval(0, 15 * increment, 4 * gridGap, center);
		
		g.setClip(old);
		
		g.drawLine(13 * increment, 4 * gridGap, 13 * increment, 13 * increment);
		
		g.setClip(center, - 3 * increment, center, 4 * gridGap);
		g.drawOval(- 5 * increment, 5 * increment, 18 * increment, 17 * increment);
		g.setClip(old);
		
		g.drawLine(3 * increment, 4 * gridGap, 3 * increment, 13 * increment);
		
		g.setClip(0, - 3 * increment, center, 4 * gridGap);
		g.drawOval(3 * increment, 5 * increment, 18 * increment, 17 * increment);
		g.setClip(old);
	}
	
	
	
	
	protected boolean canDropNormal_0()
	{
		boolean result = Wrapper.canDropJuncion(this.gridLocation.x, this.gridLocation.y + 1, 1);
		
		if(result)
			result = Wrapper.canDropJuncion(this.gridLocation.x, this.gridLocation.y + 3, 1);
		
		if(result)
			result = Wrapper.canDropJuncion(this.gridLocation.x + 6, this.gridLocation.y + 2, 1);
		
		return result;
	}
	
	protected boolean canDropNormal_90()
	{
		boolean result = Wrapper.canDropJuncion(this.gridLocation.x + 1, this.gridLocation.y + 6, 1);
		
		if(result)
			result = Wrapper.canDropJuncion(this.gridLocation.x + 3, this.gridLocation.y + 6, 1);
		
		if(result)
			result = Wrapper.canDropJuncion(this.gridLocation.x + 2, this.gridLocation.y, 1);
		
		return result;
	}
	
	protected boolean canDropNormal_180()
	{
		boolean result = Wrapper.canDropJuncion(this.gridLocation.x + 6, this.gridLocation.y + 1, 1);
		
		if(result)
			result = Wrapper.canDropJuncion(this.gridLocation.x + 6, this.gridLocation.y + 3, 1);
		
		if(result)
			result = Wrapper.canDropJuncion(this.gridLocation.x, this.gridLocation.y + 2, 1);
		
		return result;
	}
	
	protected boolean canDropNormal_270()
	{
		boolean result = Wrapper.canDropJuncion(this.gridLocation.x + 1, this.gridLocation.y, 1);
		
		if(result)
			result = Wrapper.canDropJuncion(this.gridLocation.x + 3, this.gridLocation.y, 1);
		
		if(result)
			result = Wrapper.canDropJuncion(this.gridLocation.x + 2, this.gridLocation.y + 6, 1);
		
		return result;
	}
	
	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.input1 = Wrapper.setPinAt(this.gridLocation.x, this.gridLocation.y + 1, 1);
		this.input2 = Wrapper.setPinAt(this.gridLocation.x, this.gridLocation.y + 3, 1);
		this.output = Wrapper.setPinAt(this.gridLocation.x + 6, this.gridLocation.y + 2, 1);
		
		this.changeColor(Color.black);
	}
	
	protected void dropedNormal_90()
	{
		this.input1 = Wrapper.setPinAt(this.gridLocation.x + 1, this.gridLocation.y + 6, 1);
		this.input2 = Wrapper.setPinAt(this.gridLocation.x + 3, this.gridLocation.y + 6, 1);
		this.output = Wrapper.setPinAt(this.gridLocation.x + 2, this.gridLocation.y, 1);
		
		this.changeColor(Color.black);
	}
	
	protected void dropedNormal_180()
	{
		this.input1 = Wrapper.setPinAt(this.gridLocation.x + 6, this.gridLocation.y + 3, 1);
		this.input2 = Wrapper.setPinAt(this.gridLocation.x + 6, this.gridLocation.y + 1, 1);
		this.output = Wrapper.setPinAt(this.gridLocation.x, this.gridLocation.y + 2, 1);
		
		this.changeColor(Color.black);
	}
	
	protected void dropedNormal_270()
	{
		this.input1 = Wrapper.setPinAt(this.gridLocation.x + 3, this.gridLocation.y, 1);
		this.input2 = Wrapper.setPinAt(this.gridLocation.x + 1, this.gridLocation.y, 1);
		this.output = Wrapper.setPinAt(this.gridLocation.x + 2, this.gridLocation.y + 6, 1);
		
		this.changeColor(Color.black);
	}
	
	protected void dropedFlipped_0()
	{
		this.input1 = Wrapper.setPinAt(this.gridLocation.x, this.gridLocation.y + 3, 1);
		this.input2 = Wrapper.setPinAt(this.gridLocation.x, this.gridLocation.y + 1, 1);
		this.output = Wrapper.setPinAt(this.gridLocation.x + 6, this.gridLocation.y + 2, 1);
		
		this.changeColor(Color.black);
	}
	
	protected void dropedFlipped_90()
	{
		this.input1 = Wrapper.setPinAt(this.gridLocation.x + 1, this.gridLocation.y, 1);
		this.input2 = Wrapper.setPinAt(this.gridLocation.x + 3, this.gridLocation.y, 1);
		this.output = Wrapper.setPinAt(this.gridLocation.x + 2, this.gridLocation.y + 6, 1);
		
		this.changeColor(Color.black);
	}
	
	protected void dropedFlipped_180()
	{
		this.input1 = Wrapper.setPinAt(this.gridLocation.x + 6, this.gridLocation.y + 1, 1);
		this.input2 = Wrapper.setPinAt(this.gridLocation.x + 6, this.gridLocation.y + 3, 1);
		this.output = Wrapper.setPinAt(this.gridLocation.x, this.gridLocation.y + 2, 1);
		
		this.changeColor(Color.black);
	}
	
	protected void dropedFlipped_270()
	{
		this.input1 = Wrapper.setPinAt(this.gridLocation.x + 3, this.gridLocation.y + 6, 1);
		this.input2 = Wrapper.setPinAt(this.gridLocation.x + 1, this.gridLocation.y + 6, 1);
		this.output = Wrapper.setPinAt(this.gridLocation.x + 2, this.gridLocation.y, 1);
		
		this.changeColor(Color.black);
	}
		
	
	
	
	protected void adjustToChanges()
	{
		if(this.angle % 180 == 0)
			this.setGridSize(6, 4);
		else
			this.setGridSize(4, 6);
	}
	
/* ==================================================================
	Popup Part
	================================================================= */
	public boolean hasProperties()
	{
		return true;
	}
	
	public Component getPropertyWindow()
	{
		return (new XorProperties(this.delay, this.invertInput1, this.invertInput2, this.invertOutput));
	}
		
	public void respondToChanges(Component property)
	{
		CentralPanel.ACTIVE_GRID.eraseComponent(this, false);
		
		XorProperties x = (XorProperties)property;
		this.delay = x.getDelay();
		this.invertInput1 = x.getInvertInput1();
		this.invertInput2 = x.getInvertInput2();
		this.invertOutput = x.getInvertOutput();
		
		CentralPanel.ACTIVE_GRID.paintComponent(this);
	}
	
	private class XorProperties extends Container implements ActionListener, FocusListener
	{
		private TextField editDelay = new TextField(10);
		private Checkbox input1 = new Checkbox("Invert Input 1");
		private Checkbox input2 = new Checkbox("Invert Input 2");
		private Checkbox output = new Checkbox("Invert Output");
		private double old;
		
		private Label simulation = new Label("Simulation");
		private Label pins = new Label("Pins");
		
		public XorProperties(double initial, boolean invertInput1, boolean invertInput2, boolean invertOutput)
		{
			super();
			this.setLayout(new BorderLayout(0, 15));
			
			this.input1.setState(invertInput1);
			this.input2.setState(invertInput2);
			this.output.setState(invertOutput);
			this.old = initial;
			this.editDelay.addActionListener(this);
			this.editDelay.addFocusListener(this);
			this.editDelay.setText(Double.toString(initial));
			
			Panel big = new Panel(new BorderLayout(0, 15));
			Panel p = new Panel(new BorderLayout());
			p.add(this.pins, BorderLayout.WEST);
			p.add(new SimSeparator(), BorderLayout.CENTER);
			big.add(p, BorderLayout.NORTH);
			
			p = new Panel(new GridLayout(2, 2));
			p.add(this.input1);
			p.add(this.output);
			p.add(this.input2);
			big.add(p, BorderLayout.CENTER);
			
			this.add(big, BorderLayout.NORTH);
			
			big = new Panel(new BorderLayout(0, 15));
			p = new Panel(new BorderLayout());
			p.add(this.simulation, BorderLayout.WEST);
			p.add(new SimSeparator(), BorderLayout.CENTER);
			big.add(p, BorderLayout.NORTH);
			
			p = new Panel(new FlowLayout(FlowLayout.LEFT, 0, 0));
			p.add(new Label("Propagation Delay"));
			p.add(this.editDelay);
			big.add(p, BorderLayout.CENTER);
			
			this.add(big, BorderLayout.CENTER);
		}
		
		public void addNotify()
		{
			super.addNotify();
			this.setSize(290, this.input1.getPreferredSize().height * 2 + this.editDelay.getPreferredSize().height + this.simulation.getPreferredSize().height * 2 + 45);
		}
		
		public void actionPerformed(ActionEvent e)
		{
			double newDelay;
			
			try
			{
				newDelay = Double.valueOf(this.editDelay.getText()).doubleValue();
				
				if(newDelay < 0)
					this.editDelay.setText(Double.toString(this.old));
				else
					this.old = newDelay;
			}
			catch(NumberFormatException nfe)
			{
				this.editDelay.setText(Double.toString(this.old));
			}
		}
		
		public void focusGained(FocusEvent e)
		{
		}
		
		public void focusLost(FocusEvent e)
		{
			double newDelay;
			
			try
			{
				newDelay = Double.valueOf(this.editDelay.getText()).doubleValue();
				
				if(newDelay < 0)
					this.editDelay.setText(Double.toString(this.old));
				else
				{
					this.old = newDelay;
					this.editDelay.setText(this.editDelay.getText());
				}
			}
			catch(NumberFormatException nfe)
			{
				this.editDelay.setText(Double.toString(this.old));
			}
		}
		
		public double getDelay()
		{
			double newDelay;
			
			try
			{
				newDelay = Double.valueOf(this.editDelay.getText()).doubleValue();
				
				if(newDelay >= 0)
					this.old = newDelay;
			}
			catch(NumberFormatException nfe)
			{
			}
			
			return this.old;
		}
		
		public boolean getInvertInput1()
		{
			return this.input1.getState();
		}
		
		public boolean getInvertInput2()
		{
			return this.input2.getState();
		}
		
		public boolean getInvertOutput()
		{
			return this.output.getState();
		}
		
		public Dimension getPreferredSize()
		{
			return this.getSize();
		}
		
		public Dimension getMinimumSize()
		{
			return this.getSize();
		}
	
		public Dimension getMaximumSize()
		{
			return this.getSize();
		}
	}
	
	public void writeVHDLEntity(String path)
	{
		String fileName = "gates.vhd";
		File file = new File(path+"\\"+fileName);
		boolean written = false;
		try {
			Scanner scanner = new Scanner(file);
			while(scanner.hasNextLine()){
				String line = scanner.nextLine();
				if(line.contains(getVHDLName())){
					written = true;
				}
			}
			scanner.close();
		} catch (FileNotFoundException e1) {
			e1.printStackTrace();
		}
		
		if(!written){
			sim.VHDLExporter.writeLib(path);
			FileWriter writer = null;
			try {
				writer = new FileWriter(path+"\\"+fileName,true);
				//writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path+"\\"+fileName)));
				
				writer.write("\nentity XOR_ent_" + 2 + " is\n");
				//if(this.inputSize == 1){
				writer.write("port( x0: in std_logic;\n");
				for(int x = 1; x < 2; x++){
					writer.write("x" + x + ": in std_logic;\n");
				}
				writer.write("F: out std_logic);\n");
				/*}else{ //USE THIS FOR AND FUNCTION (not gate)
					writer.write("port( x: in std_logic_vector (" + (this.inputSize-1) + " DOWNTO 0)");
					writer.write("y: in std_logic_vector (" + (this.inputSize-1) + " DOWNTO 0)");
					writer.write("F: out std_logic_vector (" + (this.inputSize-1) + " DOWNTO 0)");
				}*/
				
				writer.write("end XOR_ent_" + 2 +";\n\n");
				
				writer.write("architecture behav of XOR_ent_" + 2 + " is\n");
				writer.write("begin\n");
				writer.write("F<=x0");
				for(int x = 1; x < 2; x++){
					writer.write(" xor x" + x);
				}
				writer.write(";\n");
				writer.write("end behav;\n");
				
				writer.close();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	public String getVHDLName()
	{
		return "XOR_ent_" + 2;
	}
}
