package sim.lib.functions;

import java.awt.*;

import sim.*;
import sim.engine.*;

import sim.lib.wires.Junction;

public class Increment extends Function1in1fat1thinOut
{
/* ==================================================================
	Creation Part
	================================================================= */
	private static Image ICON = GuiFileLink.getImage("sim/lib/functions/IncrementIcon.gif");
	
	public Image getIcon()
	{
		return Increment.ICON;
	}
	
	public String getBubbleHelp()
	{
		return "Increment";
	}
	
/* ==================================================================
	GUI part
	================================================================= */
	public Increment()
	{
		super();
	}
	
	protected Wrapper getCopy()
	{
		Increment result = new Increment();
		result.changeDelay(this.delay);
		result.setBusSize(this.busSize);
		return result;
	}
	
	public void paint(Graphics g)
	{
		// draw if visible
		if(this.isVisible())
		{
			int gridGap = CentralPanel.ACTIVE_GRID.getCurrentGridGap();
			int increment = gridGap / 4;
			int twice = 2 * gridGap;
			
			g.setColor(this.brush);
			
			g.drawRect(gridGap, gridGap, twice, twice);
			
			g.drawLine(0, 2 * gridGap, gridGap, twice);
			g.fillRect(twice - 1, 0, 3, gridGap);
			g.fillRect(twice - 1, 3 * gridGap, 3, gridGap);
			
			g.setFont(new Font(Wrapper.FONT_NAME, Font.PLAIN, 3 * increment));
			
			FontMetrics fm = g.getFontMetrics(g.getFont());
			g.drawString("+1", twice - fm.stringWidth("+1") / 2, twice + fm.getAscent() / 2);
		}
	}
	
/* ==================================================================
	Simulation part
	================================================================= */
	public void evaluateOutput(double currentTime, Data[] currentInputs, EnginePeer peer)
	{
		double time = this.delay + currentTime;
		
		int loop;
		int value = 0;
		int base = 1;
		boolean foundUndefined = false;
		String bitValue;
		
		for(loop = 0; (loop < this.busSize) && (!foundUndefined); loop++)
		{
			if(currentInputs[loop].isUndefined())
				foundUndefined = true;
			else if(currentInputs[loop].getValue())
				value = value + base;
			
			base = 2 * base;
		}
		
		if(foundUndefined)
		{
			for(loop = 0; loop <= this.busSize;loop++)
				peer.setOutputPinUndefined(loop, time);
		}
		else
		{
			value = value + 1;
			
			
			if(value < Math.pow(2, this.busSize))
			{
				peer.setOutputPinValue(this.busSize, false, time);
				
				bitValue = Integer.toBinaryString(value);
				
				for(loop = bitValue.length(); loop <  this.busSize; loop ++)
					bitValue = "0" + bitValue;
				
				for(loop = 0; loop < this.busSize; loop++)
					peer.setOutputPinValue(loop, bitValue.charAt(this.busSize - 1 - loop) == '1', time);
			}
			else
			{
				peer.setOutputPinValue(this.busSize, true, time);
				
				for(loop = 0; loop < this.busSize; loop++)
					peer.setOutputPinValue(loop, false, time);	
			}
		}
	}
	
	@Override
	public void writeVHDLEntity(String path) {
		VHDLGeneral.write1busto1busFunction(path,getVHDLName(),this.busSize,"f <= unsigned(x) + 1;");
		
	}

	@Override
	public String getVHDLName() {
		return "INCREMENTbus_ent_" + this.busSize;
	}
}