package sim.lib.functions;

import java.awt.*;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Scanner;

import sim.*;
import sim.engine.*;
import sim.lib.functions.VHDLGeneral;

import sim.lib.wires.Junction;

public class BitwiseAnd extends Function2in1fatOut
{
/* ==================================================================
	Creation Part
	================================================================= */
	private static Image ICON = GuiFileLink.getImage("sim/lib/functions/AndUnitIcon.gif");
	
	public Image getIcon()
	{
		return BitwiseAnd.ICON;
	}
	
	public String getBubbleHelp()
	{
		return "AND unit";
	}
	
/* ==================================================================
	GUI part
	================================================================= */
	public BitwiseAnd()
	{
		super();
	}
	
	protected Wrapper getCopy()
	{
		BitwiseAnd result = new BitwiseAnd();
		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 tripple = 3 * gridGap;
			
			g.setColor(this.brush);
			
			g.drawLine(gridGap + increment, gridGap, 10 * increment, gridGap);
			g.drawLine(14 * increment, gridGap, 19 * increment, gridGap);
			
			g.drawLine(10 * increment, gridGap, tripple, 6 * increment);
			g.drawLine(14 * increment, gridGap, tripple, 6 * increment);
			
			g.drawLine(gridGap + increment, tripple, 19 * increment, tripple);
			
			g.drawLine(gridGap + increment, gridGap, gridGap + increment, tripple);
			g.drawLine(19 * increment, gridGap, 19 * increment, tripple);
			
			g.fillRect(2 * gridGap - 1, 0, 3, gridGap);
			g.fillRect(4 * gridGap - 1, 0, 3, gridGap);
			g.fillRect(tripple - 1, tripple, 3, gridGap);
			
			g.setFont(new Font(Wrapper.FONT_NAME, Font.PLAIN, 3 * increment));
			
			FontMetrics fm = g.getFontMetrics(g.getFont());
			g.drawString("and", tripple - fm.stringWidth("and") / 2, 10 * increment);
		}
	}
	
/* ==================================================================
	Simulation part
	================================================================= */
	public void evaluateOutput(double currentTime, Data[] currentInputs, EnginePeer peer)
	{
		double time = this.delay + currentTime;
		
		int loop;
		int x = 0;
		int y = 0;
		int base = 1;
		boolean foundUndefined = false;
		String bitValue;
		
		for(loop = 0; (loop < this.busSize) && (!foundUndefined); loop++)
		{
			if(currentInputs[loop].isUndefined() || currentInputs[loop + this.busSize].isUndefined())
				foundUndefined = true;
			else
			{
				if(currentInputs[loop].getValue())
					x = x + base;
				
				if(currentInputs[loop + this.busSize].getValue())
					y = y + base;
			}
			
			base = 2 * base;
		}
		
		if(foundUndefined)
		{
			for(loop = 0; loop < this.busSize;loop++)
				peer.setOutputPinUndefined(loop, time);
		}
		else
		{
			x = x & y;
			
			bitValue = Integer.toBinaryString(x);
			
			for(loop = bitValue.length(); loop < this.busSize; loop ++)
				bitValue = "0" + bitValue;
			
			for(loop = 0; loop < this.busSize; loop++)
				peer.setOutputPinValue(loop, bitValue.charAt(bitValue.length() - 1 - loop) == '1', time);
		}
	}

	@Override
	public void writeVHDLEntity(String path) {
		VHDLGeneral.write2busto1busFunction(path,getVHDLName(),this.busSize,"f <= x and y;",false,false);
		//writeFunction(path,getVHDLName(),this.busSize,"f <= x and y;");
		/*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){
			Writer writer = null;
			try {
				writer = new FileWriter(path+"\\"+fileName,true);
				
				writer.write("\nentity ANDbus_ent_" + this.busSize + " is\n");
				//if(this.inputSize == 1){
				writer.write("port( x0: in std_logic;\n");
				for(int x = 1; x < this.busSize; x++){
					writer.write("x" + x + ": in std_logic;\n");
				}
				
				//writer.write("y0: in std_logic;\n");
				for(int x = 0; x < this.busSize; x++){
					writer.write("y" + x + ": in std_logic;\n");
				}
				
				for(int x = 0; x < this.busSize; x++){
					writer.write("F" + x + ": out std_logic;\n");
				}
				writer.write(");\n");
				
				writer.write("end ANDbus_ent_" + this.busSize +";\n\n");
				
				writer.write("architecture behav of ANDbus_ent_" + this.busSize + " is\n");
				writer.write("begin\n");
				for(int x = 0; x < this.busSize; x++){
					writer.write("F" + x + "<=x" + x + " and " + "y" + x + ";\n");
				}
				//writer.write(";\n");
				writer.write("end behav;\n");
				
				writer.close();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}*/
		
	}

	@Override
	public String getVHDLName() {
		// TODO Auto-generated method stub
		return "ANDbus_ent_" + this.busSize;
	}
}