package sim.lib.sorces;

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

import gjt.BulletinLayout;

import sim.*;
import sim.engine.*;
import sim.lib.wires.Junction;
import sim.util.LightButton;
import sim.util.StickyLightButtonListener;


public class Constant extends RotatableFlippableWrapperPainted implements EngineModule
{
/* ==================================================================
	Creation Part
	================================================================= */
	public Image getIcon()
	{
		return GuiFileLink.getImage("sim/lib/sorces/NodeConstantIcon.gif");
	}
	
	public Wrapper createWrapper()
	{
		Constant result = new Constant();
		result.setupWrapper();
		return result;
	}
	
	public Wrapper createWrapper(Point gridPosition)
	{
		Constant result = new Constant();
		result.setupWrapper();
		result.setGridLocation(gridPosition);
		return result;
	}
	
	public String getBubbleHelp()
	{
		return "Node Constant";
	}
	
/* ==================================================================
	GUI part
	================================================================= */
	private LightButton button = null;
	
	public Constant()
	{
		super();
	}
	
	public void setupWrapper()
	{
		int gap = CentralPanel.ACTIVE_GRID.getCurrentGridGap();
		
		this.button = new LightButton(2 * gap, gap);
		this.button.setLocation(3 * gap / 2, 3 * gap / 2);
		this.button.setBackground(WrapperPainted.BACKGROUND);
		this.button.setEnabled(true);
		
		this.button.addActionListener(new ActionListener()
			{
				public void actionPerformed(ActionEvent e)
				{
					if(peer != null)
						peer.normalTransaction(0, new Signal(button.isInset(), RunShortcut.LINK.getRealTime(), false, peer, 0));
					
					CentralPanel.ACTIVE_GRID.paintComponent(Constant.this);
				}
			});
		
		
		StickyLightButtonListener listener = new StickyLightButtonListener();
		this.button.addMouseListener(listener);
		this.button.addMouseMotionListener(listener);
		
		this.setLayout(new BulletinLayout());
		this.add(this.button);
	}
	
	public void initializeGridSize()
	{
		this.setGridSize(6, 4);
	}
	
	public void scale()
	{
		int gap = CentralPanel.ACTIVE_GRID.getCurrentGridGap();
		
		this.button.setSize(2 * gap, gap);
		this.button.setLocation(3 * gap / 2, 3 * gap / 2);
	}
	
/* ==================================================================
	Maintanance Part
	================================================================= */
	private Junction output = null;
	
	public void selected()
	{
		this.output.removePin();
		
		this.changeColor(Color.green);
	}
	
	public void checkAfterSelected()
	{
		Wrapper.checkPin(this.output);
	}
	
/* ==================================================================
	Simulation part
	================================================================= */
	private EnginePeer peer = null;
	
	public void evaluateOutput(double currentTime, Data[] currentInputs, EnginePeer peer)
	{
	}
	
	public void createEnginePeer(EnginePeerList epl)
	{
		this.peer = new EnginePeer(0, 1, this);
		
		this.peer.setOutputPin(0, this.output.getNodes().getItemAt(0));
		this.peer.normalTransaction(0, new Signal(this.button.isInset(), 0, false, this.peer, 0));
		
		CentralPanel.ACTIVE_GRID.paintComponent(this);
		
		epl.insertItem(this.peer);
	}
	
	public void reset()
	{
		this.peer = null;
	}
	
	public Wrapper getParentWrapper()
	{
		return this;
	}
	
/* ==================================================================
	Storage Part
	================================================================= */
	public String getSpecificParameters()
	{
		
		return ((new Boolean(this.button.isRaised())).toString() + Wrapper.SEPARATOR);
	}
	
	public void loadWrapper(String[] specificParameters) throws SimException
	{
		this.setupWrapper();
		
		if(specificParameters.length == this.getNumberOfSpecificParameters())
		{
			if(Boolean.valueOf(specificParameters[0]).booleanValue())
				this.button.setRaised();
			else
				this.button.setInset();
		}
		else
			throw (new SimException("incorrect number of parameters"));
	}
	
	public int getNumberOfSpecificParameters()
	{
		return 1;
	}
	
/* ==================================================================
	Rotation abd Flipping Part
	================================================================= */
	
	protected void paintNormal_0(Graphics g)
	{
		int gridGap = CentralPanel.ACTIVE_GRID.getCurrentGridGap();
		int middle = 2 * gridGap;
		int right = 5 * gridGap;
		int bottom = 3 * gridGap;
		int increment = gridGap / 4;
		
		g.setColor(WrapperPainted.BACKGROUND);
		g.fillRect(gridGap, gridGap, bottom + gridGap, middle);
		g.fill3DRect(15 * increment, 7 * increment, 3 * increment + 1 , 2 * increment + 1, false);
		
		g.setColor(WrapperPainted.BACKGROUND.brighter());
		g.drawLine(gridGap + 1, gridGap + 1, right - 2, gridGap + 1);
		g.drawLine(gridGap + 1, gridGap + 1, gridGap + 1, bottom - 2);
		
		g.setColor(WrapperPainted.BACKGROUND.darker());
		g.drawLine(right - 2, gridGap + 2, right - 2, bottom - 2);
		g.drawLine(gridGap + 1, bottom - 2, right - 2, bottom - 2);
		
		g.setColor(this.brush);
		g.drawLine(right, middle, right + gridGap, middle);
		g.drawRect(gridGap, gridGap, bottom + gridGap - 1, middle - 1);
		
		Rectangle buttonBounds = this.button.getBounds();
		Graphics bg = g.create(buttonBounds.x, buttonBounds.y, buttonBounds.width, buttonBounds.height);
		this.button.paint(bg);
		bg.dispose();
		
		if(this.peer != null)
		{
			if(this.button.isRaised())
				g.setColor(SimulationProperties.ZERO_COLOR);
			else
				g.setColor(SimulationProperties.ONE_COLOR);
			
			g.fillRect(15 * increment + 1, 7 * increment + 1, 3 * increment - 1, 2 * increment - 1);
		}
	}
	
	protected void paintNormal_90(Graphics g)
	{
		int gridGap = CentralPanel.ACTIVE_GRID.getCurrentGridGap();
		int middle = 2 * gridGap;
		int right = 5 * gridGap;
		int bottom = 3 * gridGap;
		int increment = gridGap / 4;
		
		g.setColor(WrapperPainted.BACKGROUND);
		g.fillRect(gridGap, gridGap, bottom + gridGap, middle);
		g.fill3DRect(15 * increment, 7 * increment, 3 * increment + 1 , 2 * increment + 1, false);
		
		g.setColor(WrapperPainted.BACKGROUND.brighter());
		g.drawLine(gridGap + 1, gridGap + 1, right - 2, gridGap + 1);
		g.drawLine(gridGap + 1, gridGap + 1, gridGap + 1, bottom - 2);
		
		g.setColor(WrapperPainted.BACKGROUND.darker());
		g.drawLine(right - 2, gridGap + 2, right - 2, bottom - 2);
		g.drawLine(gridGap + 1, bottom - 2, right - 2, bottom - 2);
		
		g.setColor(this.brush);
		g.drawLine(bottom, 0, bottom, gridGap);
		g.drawRect(gridGap, gridGap, bottom + gridGap - 1, middle - 1);
		
		Rectangle buttonBounds = this.button.getBounds();
		Graphics bg = g.create(buttonBounds.x, buttonBounds.y, buttonBounds.width, buttonBounds.height);
		this.button.paint(bg);
		bg.dispose();
		
		if(this.peer != null)
		{
			if(this.button.isRaised())
				g.setColor(SimulationProperties.ZERO_COLOR);
			else
				g.setColor(SimulationProperties.ONE_COLOR);
			
			g.fillRect(15 * increment + 1, 7 * increment + 1, 3 * increment - 1, 2 * increment - 1);
		}
	}
	
	protected void paintNormal_180(Graphics g)
	{
		int gridGap = CentralPanel.ACTIVE_GRID.getCurrentGridGap();
		int middle = 2 * gridGap;
		int right = 5 * gridGap;
		int bottom = 3 * gridGap;
		int increment = gridGap / 4;
		
		g.setColor(WrapperPainted.BACKGROUND);
		g.fillRect(gridGap, gridGap, bottom + gridGap, middle);
		g.fill3DRect(15 * increment, 7 * increment, 3 * increment + 1 , 2 * increment + 1, false);
		
		g.setColor(WrapperPainted.BACKGROUND.brighter());
		g.drawLine(gridGap + 1, gridGap + 1, right - 2, gridGap + 1);
		g.drawLine(gridGap + 1, gridGap + 1, gridGap + 1, bottom - 2);
		
		g.setColor(WrapperPainted.BACKGROUND.darker());
		g.drawLine(right - 2, gridGap + 2, right - 2, bottom - 2);
		g.drawLine(gridGap + 1, bottom - 2, right - 2, bottom - 2);
		
		g.setColor(this.brush);
		g.drawLine(0, middle, gridGap, middle);
		g.drawRect(gridGap, gridGap, bottom + gridGap - 1, middle - 1);
		
		Rectangle buttonBounds = this.button.getBounds();
		Graphics bg = g.create(buttonBounds.x, buttonBounds.y, buttonBounds.width, buttonBounds.height);
		this.button.paint(bg);
		bg.dispose();
		
		if(this.peer != null)
		{
			if(this.button.isRaised())
				g.setColor(SimulationProperties.ZERO_COLOR);
			else
				g.setColor(SimulationProperties.ONE_COLOR);
			
			g.fillRect(15 * increment + 1, 7 * increment + 1, 3 * increment - 1, 2 * increment - 1);
		}
	}
	
	protected void paintNormal_270(Graphics g)
	{
		int gridGap = CentralPanel.ACTIVE_GRID.getCurrentGridGap();
		int middle = 2 * gridGap;
		int right = 5 * gridGap;
		int bottom = 3 * gridGap;
		int increment = gridGap / 4;
		
		g.setColor(WrapperPainted.BACKGROUND);
		g.fillRect(gridGap, gridGap, bottom + gridGap, middle);
		g.fill3DRect(15 * increment, 7 * increment, 3 * increment + 1 , 2 * increment + 1, false);
		
		g.setColor(WrapperPainted.BACKGROUND.brighter());
		g.drawLine(gridGap + 1, gridGap + 1, right - 2, gridGap + 1);
		g.drawLine(gridGap + 1, gridGap + 1, gridGap + 1, bottom - 2);
		
		g.setColor(WrapperPainted.BACKGROUND.darker());
		g.drawLine(right - 2, gridGap + 2, right - 2, bottom - 2);
		g.drawLine(gridGap + 1, bottom - 2, right - 2, bottom - 2);
		
		g.setColor(this.brush);
		
		g.fillRect(bottom, bottom, 1, gridGap);
		g.drawRect(gridGap, gridGap, bottom + gridGap - 1, middle - 1);
		
		Rectangle buttonBounds = this.button.getBounds();
		Graphics bg = g.create(buttonBounds.x, buttonBounds.y, buttonBounds.width, buttonBounds.height);
		this.button.paint(bg);
		bg.dispose();
		
		if(this.peer != null)
		{
			if(this.button.isRaised())
				g.setColor(SimulationProperties.ZERO_COLOR);
			else
				g.setColor(SimulationProperties.ONE_COLOR);
			
			g.fillRect(15 * increment + 1, 7 * increment + 1, 3 * increment - 1, 2 * increment - 1);
		}
	}
	
	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 + 6, this.gridLocation.y + 2, 1);
	}
	
	protected boolean canDropNormal_90()
	{
		return Wrapper.canDropJuncion(this.gridLocation.x + 3, 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 + 3, 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.output = Wrapper.setPinAt(this.gridLocation.x + 6, this.gridLocation.y + 2, 1);
		this.changeColor(Color.black);
	}
	
	protected void dropedNormal_90()
	{
		this.output = Wrapper.setPinAt(this.gridLocation.x + 3, this.gridLocation.y, 1);
		this.changeColor(Color.black);
	}
	
	protected void dropedNormal_180()
	{
		this.output = Wrapper.setPinAt(this.gridLocation.x, this.gridLocation.y + 2, 1);
		this.changeColor(Color.black);
	}
	
	protected void dropedNormal_270()
	{
		this.output = Wrapper.setPinAt(this.gridLocation.x + 3, 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()
	{
	}
	
	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.write("\nentity CONSTANT_" + (this.button.isRaised() ? 0 : 1) + " is\n");
				writer.write("port( ");
				writer.write("F: out std_logic);\n");
				writer.write("end CONSTANT_" + (this.button.isRaised()?0:1) +";\n\n");
				writer.write("architecture behav of CONSTANT_" + (this.button.isRaised()?0:1) + " is\n");
				writer.write("begin\n");
				writer.write("F<='"+(this.button.isRaised()?0:1)+"';\n");
				writer.write("end behav;\n");
				
				writer.close();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	public String getVHDLName()
	{
		return "CONSTANT_" + (this.button.isRaised()?0:1);
	}	
}