package sim.lib.others;

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

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

import sim.lib.wires.Junction;
import sim.lib.wires.JunctionList;

public class Multiplexer extends RotatableFlippableWrapperPainted implements EngineModule {
	/* ==================================================================
	 Creation Part
	 ================================================================= */

	public Image getIcon() {
		return GuiFileLink.getImage("sim/lib/others/MuxIcon.gif");
	}

	public Wrapper createWrapper() {
		return this.getCopy();
	}

	public Wrapper createWrapper(Point gridPosition) {
		Multiplexer result = this.getCopy();
		result.setGridLocation(gridPosition);
		return result;
	}

	public String getBubbleHelp() {
		return "Multiplexer";
	}

	/* ==================================================================
	 GUI part
	 ================================================================= */
	public Multiplexer() {
		super();

		this.setNumOfInputs(2);
		this.setBusSize(1);
	}

	private Multiplexer getCopy() {
		Multiplexer result = new Multiplexer();

		result.setNumOfInputs(this.numOfInputs);
		result.setBusSize(this.busSize);
		result.changeDelay(this.delay);

		return result;
	}

	public void initializeGridSize() {
		this.setGridSize(4, 6);
	}
	/* ==================================================================
	 Maintanance Part
	 ================================================================= */
	private JunctionList input = new JunctionList();
	private Junction select = null;
	private Junction output = null;
	private int numOfInputs;	//number of inputs
	private int selectBusSize;	//bus size of select line
	private int busSize;		//bus size of both inputs and outputs

	public void setNumOfInputs(int num) {
		this.numOfInputs = num;
		this.selectBusSize = (this.numOfInputs == 0 ? 0 : 32 - Integer.numberOfLeadingZeros(this.numOfInputs - 1));
		this.adjustToChanges();
	}

	public void setBusSize(int size) {
		this.busSize = size;
	}

	public void selected() {
		for (int loop = 0; loop < this.numOfInputs; loop++) {
			this.input.getItemAt(loop).removePin();
		}

		this.output.removePin();
		this.select.removePin();

		this.changeColor(Color.green);
	}

	public void checkAfterSelected() {
		for (int loop = 0; loop < this.numOfInputs; loop++) {
			Wrapper.checkPin(this.input.getItemAt(loop));
		}

		Wrapper.checkPin(this.output);
		Wrapper.checkPin(this.select);
	}
	/* ==================================================================
	 Simulation part
	 ================================================================= */
	protected double delay = 1;

	public void evaluateOutput(double currentTime, Data[] currentInputs, EnginePeer peer) {
		boolean foundUndefined = false;
		int position = 0;
		int base = 1;
		double time = currentTime + this.delay;

		int loop;

		for (loop = 0; (loop < this.selectBusSize) && (!foundUndefined); loop++) {
			if (currentInputs[loop].isUndefined()) {
				foundUndefined = true;
			} else {
				if (currentInputs[loop].getValue()) {
					position = position + base;
				}

				base = 2 * base;
			}
		}

		if (foundUndefined || (position >= this.numOfInputs)) {
			for (loop = 0; loop < this.busSize; loop++) {
				peer.setOutputPinUndefined(loop, time);
			}
		} else {
			base = this.selectBusSize + this.busSize * position;

			for (loop = 0; loop < this.busSize; loop++) {
				if (currentInputs[base].isUndefined()) {
					peer.setOutputPinUndefined(loop, time);
				} else {
					peer.setOutputPinValue(loop, currentInputs[base].getValue(), time);
				}

				base++;
			}
		}
	}

	public void createEnginePeer(EnginePeerList epl) {
		EnginePeer ep = new EnginePeer(this.numOfInputs * this.busSize + this.selectBusSize, this.busSize, this);

		int loop, index, position;

		for (loop = 0; loop < this.selectBusSize; loop++) {
			ep.setInputPin(loop, this.select.getNodes().getItemAt(loop));
		}

		position = this.selectBusSize;

		for (loop = 0; loop < this.numOfInputs; loop++) {
			for (index = 0; index < this.busSize; index++) {
				ep.setInputPin(position, this.input.getItemAt(loop).getNodes().getItemAt(index));
				position++;
			}
		}

		for (loop = 0; loop < this.busSize; loop++) {
			ep.setOutputPin(loop, this.output.getNodes().getItemAt(loop));
		}

		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 (Integer.toString(this.numOfInputs) + Wrapper.SEPARATOR + Integer.toString(this.busSize) + Wrapper.SEPARATOR + Double.toString(this.delay) + Wrapper.SEPARATOR);
	}

	public void loadWrapper(String[] specificParameters) throws SimException {
		if (specificParameters.length == this.getNumberOfSpecificParameters()) {
			try {
				this.setNumOfInputs(Integer.valueOf(specificParameters[0]).intValue());
				this.setBusSize(Integer.valueOf(specificParameters[1]).intValue());
				this.delay = Double.valueOf(specificParameters[2]).doubleValue();
			} catch (NumberFormatException e) {
				throw (new SimException("incorrect parameter type"));
			}
		} 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 increment = gridGap / 4;
		int middle = this.numOfInputs / 2;
		int textOffset = gridGap + increment;

		g.setColor(this.brush);

		int up = 7 * increment;
		int height = gridGap * this.getGridSize().height;
		int center = 3 * gridGap;

		g.drawLine(gridGap, gridGap, gridGap, height - gridGap);
		g.drawLine(center, up, center, height - up);

		g.drawLine(gridGap, gridGap, center, up);
		g.drawLine(gridGap, height - gridGap, center, height - up);

		up = 2 * gridGap;

		if (this.selectBusSize == 1) {
			g.drawLine(up, 0, up, textOffset);
		} else {
			g.fillRect(up - 1, 0, 3, textOffset);
		}


		center = height / 2;
		g.setFont(new Font(Wrapper.FONT_NAME, Font.PLAIN, 3 * increment));

		int offset = 0;
		int thickness = 1;

		if (this.busSize != 1) {
			offset = -1;
			thickness = 3;
		}

		g.fillRect(3 * gridGap, center + offset, gridGap, thickness);
		g.drawString("M", 2 * gridGap, center + offset + increment);

		for (height = 0; height < middle; height++) {
			g.drawString(Integer.toString(height), textOffset, up + increment);
			g.fillRect(0, up + offset, gridGap, thickness);
			up = up + gridGap;
		}

		if ((this.numOfInputs % 2) != 0) {
			g.drawString(Integer.toString(height), textOffset, up + increment);
			g.fillRect(0, up + offset, gridGap, thickness);
			up = up + gridGap;

			for (height = middle + 1; height < this.numOfInputs; height++) {
				g.drawString(Integer.toString(height), textOffset, up + increment);
				g.fillRect(0, up + offset, gridGap, thickness);
				up = up + gridGap;
			}
		} else {
			up = up + gridGap;

			for (height = middle; height < this.numOfInputs; height++) {
				g.drawString(Integer.toString(height), textOffset, up + increment);
				g.fillRect(0, up + offset, gridGap, thickness);
				up = up + gridGap;
			}
		}
	}

	protected void paintNormal_90(Graphics g) {
		int gridGap = CentralPanel.ACTIVE_GRID.getCurrentGridGap();
		int increment = gridGap / 4;
		int middle = this.numOfInputs / 2;
		int textOffset = gridGap + increment;
		int tripple = 3 * gridGap;

		g.setColor(this.brush);

		int up = 7 * increment;
		int height = gridGap * this.getGridSize().width;
		int center = height / 2;

		g.drawLine(gridGap, tripple, height - gridGap, tripple);
		g.drawLine(up, gridGap, height - up, gridGap);

		g.drawLine(gridGap, tripple, up, gridGap);
		g.drawLine(height - gridGap, tripple, height - up, gridGap);

		up = 2 * gridGap;

		if (this.selectBusSize == 1) {
			g.drawLine(0, up, textOffset, up);
		} else {
			g.fillRect(0, up - 1, textOffset, 3);
		}

		g.setFont(new Font(Wrapper.FONT_NAME, Font.PLAIN, 3 * increment));

		int offset = 0;
		int thickness = 1;

		if (this.busSize != 1) {
			offset = -1;
			thickness = 3;
		}

		g.fillRect(center + offset, 0, thickness, gridGap);
		g.drawString("M", center - increment, 2 * gridGap);

		textOffset = tripple - increment;
		FontMetrics fm = g.getFontMetrics();
		String toDraw;

		for (height = 0; height < middle; height++) {
			toDraw = Integer.toString(height);
			g.drawString(toDraw, up - fm.stringWidth(toDraw) / 2, textOffset);
			g.fillRect(up + offset, tripple, thickness, gridGap);
			up = up + gridGap;
		}

		if ((this.numOfInputs % 2) != 0) {
			toDraw = Integer.toString(height);
			g.drawString(toDraw, up - fm.stringWidth(toDraw) / 2, textOffset);
			g.fillRect(up + offset, tripple, thickness, gridGap);
			up = up + gridGap;

			for (height = middle + 1; height < this.numOfInputs; height++) {
				toDraw = Integer.toString(height);
				g.drawString(toDraw, up - fm.stringWidth(toDraw) / 2, textOffset);
				g.fillRect(up + offset, tripple, thickness, gridGap);
				up = up + gridGap;
			}
		} else {
			up = up + gridGap;

			for (height = middle; height < this.numOfInputs; height++) {
				toDraw = Integer.toString(height);
				g.drawString(toDraw, up - fm.stringWidth(toDraw) / 2, textOffset);
				g.fillRect(up + offset, tripple, thickness, gridGap);
				up = up + gridGap;
			}
		}
	}

	protected void paintNormal_180(Graphics g) {
		int gridGap = CentralPanel.ACTIVE_GRID.getCurrentGridGap();
		int increment = gridGap / 4;
		int middle = this.numOfInputs / 2;
		int textOffset = gridGap + increment;
		int tripple = 3 * gridGap;

		g.setColor(this.brush);

		int up = 7 * increment;
		int height = gridGap * this.getGridSize().height;
		int center = height / 2;

		g.drawLine(tripple, gridGap, tripple, height - gridGap);
		g.drawLine(gridGap, up, gridGap, height - up);

		g.drawLine(tripple, gridGap, gridGap, up);
		g.drawLine(tripple, height - gridGap, gridGap, height - up);

		up = 2 * gridGap;

		if (this.selectBusSize == 1) {
			g.drawLine(up, this.getSize().height - textOffset, up, this.getSize().height);
		} else {
			g.fillRect(up - 1, this.getSize().height - textOffset, 3, textOffset);
		}

		g.setFont(new Font(Wrapper.FONT_NAME, Font.PLAIN, 3 * increment));

		int offset = 0;
		int thickness = 1;

		if (this.busSize != 1) {
			offset = -1;
			thickness = 3;
		}

		g.fillRect(0, center + offset, gridGap, thickness);
		g.drawString("M", gridGap + increment, center + increment);

		textOffset = tripple - increment;
		FontMetrics fm = g.getFontMetrics();
		String toDraw;

		for (height = 0; height < middle; height++) {
			toDraw = Integer.toString(this.numOfInputs - 1 - height);
			g.drawString(toDraw, textOffset - fm.stringWidth(toDraw), up + increment);
			g.fillRect(tripple, up + offset, gridGap, thickness);
			up = up + gridGap;
		}

		if ((this.numOfInputs % 2) != 0) {
			toDraw = Integer.toString(this.numOfInputs - 1 - height);
			g.drawString(toDraw, textOffset - fm.stringWidth(toDraw), up + increment);
			g.fillRect(tripple, up + offset, gridGap, thickness);
			up = up + gridGap;

			for (height = middle + 1; height < this.numOfInputs; height++) {
				toDraw = Integer.toString(this.numOfInputs - 1 - height);
				g.drawString(toDraw, textOffset - fm.stringWidth(toDraw), up + increment);
				g.fillRect(tripple, up + offset, gridGap, thickness);
				up = up + gridGap;
			}
		} else {
			up = up + gridGap;

			for (height = middle; height < this.numOfInputs; height++) {
				toDraw = Integer.toString(this.numOfInputs - 1 - height);
				g.drawString(toDraw, textOffset - fm.stringWidth(toDraw), up + increment);
				g.fillRect(tripple, up + offset, gridGap, thickness);
				up = up + gridGap;
			}
		}
	}

	protected void paintNormal_270(Graphics g) {
		int gridGap = CentralPanel.ACTIVE_GRID.getCurrentGridGap();
		int increment = gridGap / 4;
		int middle = this.numOfInputs / 2;
		int textOffset = gridGap + increment;

		g.setColor(this.brush);

		int up = 7 * increment;
		int height = gridGap * this.getGridSize().width;
		int center = 3 * gridGap;

		g.drawLine(gridGap, gridGap, height - gridGap, gridGap);
		g.drawLine(up, center, height - up, center);

		g.drawLine(gridGap, gridGap, up, center);
		g.drawLine(height - gridGap, gridGap, height - up, center);

		up = 2 * gridGap;

		if (this.selectBusSize == 1) {
			g.drawLine(this.getSize().width - textOffset, up, this.getSize().width, up);
		} else {
			g.fillRect(this.getSize().width - textOffset, up - 1, textOffset, 3);
		}


		center = height / 2;
		g.setFont(new Font(Wrapper.FONT_NAME, Font.PLAIN, 3 * increment));

		int offset = 0;
		int thickness = 1;

		if (this.busSize != 1) {
			offset = -1;
			thickness = 3;
		}

		g.fillRect(center + offset, 3 * gridGap, thickness, gridGap);
		g.drawString("M", center - increment, 3 * gridGap - increment);

		FontMetrics fm = g.getFontMetrics();
		String toDraw;
		textOffset = textOffset + fm.getAscent();

		for (height = 0; height < middle; height++) {
			toDraw = Integer.toString(this.numOfInputs - 1 - height);
			g.drawString(toDraw, up - fm.stringWidth(toDraw) / 2, textOffset);
			g.fillRect(up + offset, 0, thickness, gridGap);
			up = up + gridGap;
		}

		if ((this.numOfInputs % 2) != 0) {
			toDraw = Integer.toString(this.numOfInputs - 1 - height);
			g.drawString(toDraw, up - fm.stringWidth(toDraw) / 2, textOffset);
			g.fillRect(up + offset, 0, thickness, gridGap);
			up = up + gridGap;

			for (height = middle + 1; height < this.numOfInputs; height++) {
				toDraw = Integer.toString(this.numOfInputs - 1 - height);
				g.drawString(toDraw, up - fm.stringWidth(toDraw) / 2, textOffset);
				g.fillRect(up + offset, 0, thickness, gridGap);
				up = up + gridGap;
			}
		} else {
			up = up + gridGap;

			for (height = middle; height < this.numOfInputs; height++) {
				toDraw = Integer.toString(this.numOfInputs - 1 - height);
				g.drawString(toDraw, up - fm.stringWidth(toDraw) / 2, textOffset);
				g.fillRect(up + offset, 0, thickness, gridGap);
				up = up + gridGap;
			}
		}

	}

	protected void paintFlipped_0(Graphics g) {
		int gridGap = CentralPanel.ACTIVE_GRID.getCurrentGridGap();
		int increment = gridGap / 4;
		int middle = this.numOfInputs / 2;
		int textOffset = gridGap + increment;

		g.setColor(this.brush);

		int up = 7 * increment;
		int height = gridGap * this.getGridSize().height;
		int center = 3 * gridGap;

		g.drawLine(gridGap, gridGap, gridGap, height - gridGap);
		g.drawLine(center, up, center, height - up);

		g.drawLine(gridGap, gridGap, center, up);
		g.drawLine(gridGap, height - gridGap, center, height - up);

		up = 2 * gridGap;

		if (this.selectBusSize == 1) {
			g.drawLine(up, this.getSize().height - textOffset, up, this.getSize().height);
		} else {
			g.fillRect(up - 1, this.getSize().height - textOffset, 3, textOffset);
		}


		center = height / 2;
		g.setFont(new Font(Wrapper.FONT_NAME, Font.PLAIN, 3 * increment));

		int offset = 0;
		int thickness = 1;
		//int tripple = 3 * gridGap;

		if (this.busSize != 1) {
			offset = -1;
			thickness = 3;
		}

		g.fillRect(3 * gridGap, center + offset, gridGap, thickness);
		g.drawString("M", 2 * gridGap, center + offset + increment);

		for (height = 0; height < middle; height++) {
			g.drawString(Integer.toString(this.numOfInputs - 1 - height), textOffset, up + increment);
			g.fillRect(0, up + offset, gridGap, thickness);
			up = up + gridGap;
		}

		if ((this.numOfInputs % 2) != 0) {
			g.drawString(Integer.toString(this.numOfInputs - 1 - height), textOffset, up + increment);
			g.fillRect(0, up + offset, gridGap, thickness);
			up = up + gridGap;

			for (height = middle + 1; height < this.numOfInputs; height++) {
				g.drawString(Integer.toString(this.numOfInputs - 1 - height), textOffset, up + increment);
				g.fillRect(0, up + offset, gridGap, thickness);
				up = up + gridGap;
			}
		} else {
			up = up + gridGap;

			for (height = middle; height < this.numOfInputs; height++) {
				g.drawString(Integer.toString(this.numOfInputs - 1 - height), textOffset, up + increment);
				g.fillRect(0, up + offset, gridGap, thickness);
				up = up + gridGap;
			}
		}
	}

	protected void paintFlipped_90(Graphics g) {
		int gridGap = CentralPanel.ACTIVE_GRID.getCurrentGridGap();
		int increment = gridGap / 4;
		int middle = this.numOfInputs / 2;
		int textOffset = gridGap + increment;

		g.setColor(this.brush);

		int up = 7 * increment;
		int height = gridGap * this.getGridSize().width;
		int center = 3 * gridGap;

		g.drawLine(gridGap, gridGap, height - gridGap, gridGap);
		g.drawLine(up, center, height - up, center);

		g.drawLine(gridGap, gridGap, up, center);
		g.drawLine(height - gridGap, gridGap, height - up, center);

		up = 2 * gridGap;

		if (this.selectBusSize == 1) {
			g.drawLine(0, up, textOffset, up);
		} else {
			g.fillRect(0, up - 1, textOffset, 3);
		}


		center = height / 2;
		g.setFont(new Font(Wrapper.FONT_NAME, Font.PLAIN, 3 * increment));

		int offset = 0;
		int thickness = 1;

		if (this.busSize != 1) {
			offset = -1;
			thickness = 3;
		}

		g.fillRect(center + offset, 3 * gridGap, thickness, gridGap);
		g.drawString("M", center - increment, 3 * gridGap - increment);

		FontMetrics fm = g.getFontMetrics();
		String toDraw;
		textOffset = textOffset + fm.getAscent();

		for (height = 0; height < middle; height++) {
			toDraw = Integer.toString(height);
			g.drawString(toDraw, up - fm.stringWidth(toDraw) / 2, textOffset);
			g.fillRect(up + offset, 0, thickness, gridGap);
			up = up + gridGap;
		}

		if ((this.numOfInputs % 2) != 0) {
			toDraw = Integer.toString(height);
			g.drawString(toDraw, up - fm.stringWidth(toDraw) / 2, textOffset);
			g.fillRect(up + offset, 0, thickness, gridGap);
			up = up + gridGap;

			for (height = middle + 1; height < this.numOfInputs; height++) {
				toDraw = Integer.toString(height);
				g.drawString(toDraw, up - fm.stringWidth(toDraw) / 2, textOffset);
				g.fillRect(up + offset, 0, thickness, gridGap);
				up = up + gridGap;
			}
		} else {
			up = up + gridGap;

			for (height = middle; height < this.numOfInputs; height++) {
				toDraw = Integer.toString(height);
				g.drawString(toDraw, up - fm.stringWidth(toDraw) / 2, textOffset);
				g.fillRect(up + offset, 0, thickness, gridGap);
				up = up + gridGap;
			}
		}
	}

	protected void paintFlipped_180(Graphics g) {
		int gridGap = CentralPanel.ACTIVE_GRID.getCurrentGridGap();
		int increment = gridGap / 4;
		int middle = this.numOfInputs / 2;
		int textOffset = gridGap + increment;
		int tripple = 3 * gridGap;

		g.setColor(this.brush);

		int up = 7 * increment;
		int height = gridGap * this.getGridSize().height;
		int center = height / 2;

		g.drawLine(tripple, gridGap, tripple, height - gridGap);
		g.drawLine(gridGap, up, gridGap, height - up);

		g.drawLine(tripple, gridGap, gridGap, up);
		g.drawLine(tripple, height - gridGap, gridGap, height - up);

		up = 2 * gridGap;

		if (this.selectBusSize == 1) {
			g.drawLine(up, 0, up, textOffset);
		} else {
			g.fillRect(up - 1, 0, 3, textOffset);
		}

		g.setFont(new Font(Wrapper.FONT_NAME, Font.PLAIN, 3 * increment));

		int offset = 0;
		int thickness = 1;

		if (this.busSize != 1) {
			offset = -1;
			thickness = 3;
		}

		g.fillRect(0, center + offset, gridGap, thickness);
		g.drawString("M", gridGap + increment, center + increment);

		textOffset = tripple - increment;
		FontMetrics fm = g.getFontMetrics();
		String toDraw;

		for (height = 0; height < middle; height++) {
			toDraw = Integer.toString(height);
			g.drawString(toDraw, textOffset - fm.stringWidth(toDraw), up + increment);
			g.fillRect(tripple, up + offset, gridGap, thickness);
			up = up + gridGap;
		}

		if ((this.numOfInputs % 2) != 0) {
			toDraw = Integer.toString(height);
			g.drawString(toDraw, textOffset - fm.stringWidth(toDraw), up + increment);
			g.fillRect(tripple, up + offset, gridGap, thickness);
			up = up + gridGap;

			for (height = middle + 1; height < this.numOfInputs; height++) {
				toDraw = Integer.toString(height);
				g.drawString(toDraw, textOffset - fm.stringWidth(toDraw), up + increment);
				g.fillRect(tripple, up + offset, gridGap, thickness);
				up = up + gridGap;
			}
		} else {
			up = up + gridGap;

			for (height = middle; height < this.numOfInputs; height++) {
				toDraw = Integer.toString(height);
				g.drawString(toDraw, textOffset - fm.stringWidth(toDraw), up + increment);
				g.fillRect(tripple, up + offset, gridGap, thickness);
				up = up + gridGap;
			}
		}
	}

	protected void paintFlipped_270(Graphics g) {
		int gridGap = CentralPanel.ACTIVE_GRID.getCurrentGridGap();
		int increment = gridGap / 4;
		int middle = this.numOfInputs / 2;
		int textOffset = gridGap + increment;
		int tripple = 3 * gridGap;

		g.setColor(this.brush);

		int up = 7 * increment;
		int height = gridGap * this.getGridSize().width;
		int center = height / 2;

		g.drawLine(gridGap, tripple, height - gridGap, tripple);
		g.drawLine(up, gridGap, height - up, gridGap);

		g.drawLine(gridGap, tripple, up, gridGap);
		g.drawLine(height - gridGap, tripple, height - up, gridGap);

		up = 2 * gridGap;

		if (this.selectBusSize == 1) {
			g.drawLine(this.getSize().width - textOffset, up, this.getSize().width, up);
		} else {
			g.fillRect(this.getSize().width - textOffset, up - 1, textOffset, 3);
		}

		g.setFont(new Font(Wrapper.FONT_NAME, Font.PLAIN, 3 * increment));

		int offset = 0;
		int thickness = 1;

		if (this.busSize != 1) {
			offset = -1;
			thickness = 3;
		}

		g.fillRect(center + offset, 0, thickness, gridGap);
		g.drawString("M", center - increment, 2 * gridGap);

		textOffset = tripple - increment;
		FontMetrics fm = g.getFontMetrics();
		String toDraw;

		for (height = 0; height < middle; height++) {
			toDraw = Integer.toString(this.numOfInputs - 1 - height);
			g.drawString(toDraw, up - fm.stringWidth(toDraw) / 2, textOffset);
			g.fillRect(up + offset, tripple, thickness, gridGap);
			up = up + gridGap;
		}

		if ((this.numOfInputs % 2) != 0) {
			toDraw = Integer.toString(this.numOfInputs - 1 - height);
			g.drawString(toDraw, up - fm.stringWidth(toDraw) / 2, textOffset);
			g.fillRect(up + offset, tripple, thickness, gridGap);
			up = up + gridGap;

			for (height = middle + 1; height < this.numOfInputs; height++) {
				toDraw = Integer.toString(this.numOfInputs - 1 - height);
				g.drawString(toDraw, up - fm.stringWidth(toDraw) / 2, textOffset);
				g.fillRect(up + offset, tripple, thickness, gridGap);
				up = up + gridGap;
			}
		} else {
			up = up + gridGap;

			for (height = middle; height < this.numOfInputs; height++) {
				toDraw = Integer.toString(this.numOfInputs - 1 - height);
				g.drawString(toDraw, up - fm.stringWidth(toDraw) / 2, textOffset);
				g.fillRect(up + offset, tripple, thickness, gridGap);
				up = up + gridGap;
			}
		}
	}

	protected boolean canDropNormal_0() {
		boolean result = true;
		int middle = this.numOfInputs / 2;
		int loop;

		// check inputs
		for (loop = 0; (loop < middle) && result; loop++) {
			result = Wrapper.canDropJuncion(this.gridLocation.x, this.gridLocation.y + 2 + loop, this.busSize);
		}

		if (result) {
			if ((this.numOfInputs % 2) != 0) {
				result = Wrapper.canDropJuncion(this.gridLocation.x, this.gridLocation.y + 2 + middle, this.busSize);
				for (loop = middle + 1; (loop < this.numOfInputs) && result; loop++) {
					result = Wrapper.canDropJuncion(this.gridLocation.x, this.gridLocation.y + 2 + loop, this.busSize);
				}
			} else {
				for (loop = middle; (loop < this.numOfInputs) && result; loop++) {
					result = Wrapper.canDropJuncion(this.gridLocation.x, this.gridLocation.y + 3 + loop, this.busSize);
				}
			}
		}

		if (result) {
			result = Wrapper.canDropJuncion(this.gridLocation.x + 2, this.gridLocation.y, this.selectBusSize);
		}

		// check output
		if (result) {
			result = Wrapper.canDropJuncion(this.gridLocation.x + 4, this.gridLocation.y + 2 + middle, this.busSize);
		}

		return result;
	}

	protected boolean canDropNormal_90() {
		boolean result = true;
		int middle = this.numOfInputs / 2;
		int loop;

		// check inputs
		for (loop = 0; (loop < middle) && result; loop++) {
			result = Wrapper.canDropJuncion(this.gridLocation.x + 2 + loop, this.gridLocation.y + 4, this.busSize);
		}

		if (result) {
			if ((this.numOfInputs % 2) != 0) {
				result = Wrapper.canDropJuncion(this.gridLocation.x + 2 + middle, this.gridLocation.y + 4, this.busSize);
				for (loop = middle + 1; (loop < this.numOfInputs) && result; loop++) {
					result = Wrapper.canDropJuncion(this.gridLocation.x + 2 + loop, this.gridLocation.y + 4, this.busSize);
				}
			} else {
				for (loop = middle; (loop < this.numOfInputs) && result; loop++) {
					result = Wrapper.canDropJuncion(this.gridLocation.x + 3 + loop, this.gridLocation.y + 4, this.busSize);
				}
			}
		}

		if (result) {
			result = Wrapper.canDropJuncion(this.gridLocation.x, this.gridLocation.y + 2, this.selectBusSize);
		}

		// check output
		if (result) {
			result = Wrapper.canDropJuncion(this.gridLocation.x + 2 + middle, this.gridLocation.y, this.busSize);
		}

		return result;
	}

	protected boolean canDropNormal_180() {
		boolean result = true;
		int middle = this.numOfInputs / 2;
		int loop;

		// check inputs
		for (loop = 0; (loop < middle) && result; loop++) {
			result = Wrapper.canDropJuncion(this.gridLocation.x + 4, this.gridLocation.y + 2 + loop, this.busSize);
		}

		if (result) {
			if ((this.numOfInputs % 2) != 0) {
				result = Wrapper.canDropJuncion(this.gridLocation.x + 4, this.gridLocation.y + 2 + middle, this.busSize);
				for (loop = middle + 1; (loop < this.numOfInputs) && result; loop++) {
					result = Wrapper.canDropJuncion(this.gridLocation.x + 4, this.gridLocation.y + 2 + loop, this.busSize);
				}
			} else {
				for (loop = middle; (loop < this.numOfInputs) && result; loop++) {
					result = Wrapper.canDropJuncion(this.gridLocation.x + 4, this.gridLocation.y + 3 + loop, this.busSize);
				}
			}
		}

		if (result) {
			result = Wrapper.canDropJuncion(this.gridLocation.x + 2, this.gridLocation.y + this.gridSize.height, this.selectBusSize);
		}

		// check output
		if (result) {
			result = Wrapper.canDropJuncion(this.gridLocation.x, this.gridLocation.y + 2 + middle, this.busSize);
		}

		return result;
	}

	protected boolean canDropNormal_270() {
		boolean result = true;
		int middle = this.numOfInputs / 2;
		int loop;

		// check inputs
		for (loop = 0; (loop < middle) && result; loop++) {
			result = Wrapper.canDropJuncion(this.gridLocation.x + 2 + loop, this.gridLocation.y, this.busSize);
		}

		if (result) {
			if ((this.numOfInputs % 2) != 0) {
				result = Wrapper.canDropJuncion(this.gridLocation.x + 2 + middle, this.gridLocation.y, this.busSize);
				for (loop = middle + 1; (loop < this.numOfInputs) && result; loop++) {
					result = Wrapper.canDropJuncion(this.gridLocation.x + 2 + loop, this.gridLocation.y, this.busSize);
				}
			} else {
				for (loop = middle; (loop < this.numOfInputs) && result; loop++) {
					result = Wrapper.canDropJuncion(this.gridLocation.x + 3 + loop, this.gridLocation.y, this.busSize);
				}
			}
		}

		if (result) {
			result = Wrapper.canDropJuncion(this.gridLocation.x + this.gridSize.width, this.gridLocation.y + 2, this.selectBusSize);
		}

		// check output
		if (result) {
			result = Wrapper.canDropJuncion(this.gridLocation.x + 2 + middle, this.gridLocation.y + 4, this.busSize);
		}

		return result;
	}

	protected boolean canDropFlipped_0() {
		boolean result = true;
		int middle = this.numOfInputs / 2;
		int loop;

		// check inputs
		for (loop = 0; (loop < middle) && result; loop++) {
			result = Wrapper.canDropJuncion(this.gridLocation.x, this.gridLocation.y + 2 + loop, this.busSize);
		}

		if (result) {
			if ((this.numOfInputs % 2) != 0) {
				result = Wrapper.canDropJuncion(this.gridLocation.x, this.gridLocation.y + 2 + middle, this.busSize);
				for (loop = middle + 1; (loop < this.numOfInputs) && result; loop++) {
					result = Wrapper.canDropJuncion(this.gridLocation.x, this.gridLocation.y + 2 + loop, this.busSize);
				}
			} else {
				for (loop = middle; (loop < this.numOfInputs) && result; loop++) {
					result = Wrapper.canDropJuncion(this.gridLocation.x, this.gridLocation.y + 3 + loop, this.busSize);
				}
			}
		}

		if (result) {
			result = Wrapper.canDropJuncion(this.gridLocation.x + 2, this.gridLocation.y + this.gridSize.height, this.selectBusSize);
		}

		// check output
		if (result) {
			result = Wrapper.canDropJuncion(this.gridLocation.x + 4, this.gridLocation.y + 2 + middle, this.busSize);
		}

		return result;
	}

	protected boolean canDropFlipped_90() {
		boolean result = true;
		int middle = this.numOfInputs / 2;
		int loop;

		// check inputs
		for (loop = 0; (loop < middle) && result; loop++) {
			result = Wrapper.canDropJuncion(this.gridLocation.x + 2 + loop, this.gridLocation.y, this.busSize);
		}

		if (result) {
			if ((this.numOfInputs % 2) != 0) {
				result = Wrapper.canDropJuncion(this.gridLocation.x + 2 + middle, this.gridLocation.y, this.busSize);
				for (loop = middle + 1; (loop < this.numOfInputs) && result; loop++) {
					result = Wrapper.canDropJuncion(this.gridLocation.x + 2 + loop, this.gridLocation.y, this.busSize);
				}
			} else {
				for (loop = middle; (loop < this.numOfInputs) && result; loop++) {
					result = Wrapper.canDropJuncion(this.gridLocation.x + 3 + loop, this.gridLocation.y, this.busSize);
				}
			}
		}

		if (result) {
			result = Wrapper.canDropJuncion(this.gridLocation.x, this.gridLocation.y + 2, this.selectBusSize);
		}

		// check output
		if (result) {
			result = Wrapper.canDropJuncion(this.gridLocation.x + 2 + middle, this.gridLocation.y + 4, this.busSize);
		}

		return result;
	}

	protected boolean canDropFlipped_180() {
		boolean result = true;
		int middle = this.numOfInputs / 2;
		int loop;

		// check inputs
		for (loop = 0; (loop < middle) && result; loop++) {
			result = Wrapper.canDropJuncion(this.gridLocation.x + 4, this.gridLocation.y + 2 + loop, this.busSize);
		}

		if (result) {
			if ((this.numOfInputs % 2) != 0) {
				result = Wrapper.canDropJuncion(this.gridLocation.x + 4, this.gridLocation.y + 2 + middle, this.busSize);
				for (loop = middle + 1; (loop < this.numOfInputs) && result; loop++) {
					result = Wrapper.canDropJuncion(this.gridLocation.x + 4, this.gridLocation.y + 2 + loop, this.busSize);
				}
			} else {
				for (loop = middle; (loop < this.numOfInputs) && result; loop++) {
					result = Wrapper.canDropJuncion(this.gridLocation.x + 4, this.gridLocation.y + 3 + loop, this.busSize);
				}
			}
		}

		if (result) {
			result = Wrapper.canDropJuncion(this.gridLocation.x + 2, this.gridLocation.y, this.selectBusSize);
		}

		// check output
		if (result) {
			result = Wrapper.canDropJuncion(this.gridLocation.x, this.gridLocation.y + 2 + middle, this.busSize);
		}

		return result;
	}

	protected boolean canDropFlipped_270() {
		boolean result = true;
		int middle = this.numOfInputs / 2;
		int loop;

		// check inputs
		for (loop = 0; (loop < middle) && result; loop++) {
			result = Wrapper.canDropJuncion(this.gridLocation.x + 2 + loop, this.gridLocation.y + 4, this.busSize);
		}

		if (result) {
			if ((this.numOfInputs % 2) != 0) {
				result = Wrapper.canDropJuncion(this.gridLocation.x + 2 + middle, this.gridLocation.y + 4, this.busSize);
				for (loop = middle + 1; (loop < this.numOfInputs) && result; loop++) {
					result = Wrapper.canDropJuncion(this.gridLocation.x + 2 + loop, this.gridLocation.y + 4, this.busSize);
				}
			} else {
				for (loop = middle; (loop < this.numOfInputs) && result; loop++) {
					result = Wrapper.canDropJuncion(this.gridLocation.x + 3 + loop, this.gridLocation.y + 4, this.busSize);
				}
			}
		}

		if (result) {
			result = Wrapper.canDropJuncion(this.gridLocation.x + this.gridSize.width, this.gridLocation.y + 2, this.selectBusSize);
		}

		// check output
		if (result) {
			result = Wrapper.canDropJuncion(this.gridLocation.x + 2 + middle, this.gridLocation.y, this.busSize);
		}

		return result;
	}

	protected void dropedNormal_0() {
		int loop;
		int middle = this.numOfInputs / 2;

		this.input.setSize(this.numOfInputs);

		for (loop = 0; loop < middle; loop++) {
			this.input.changeItem(loop, Wrapper.setPinAt(this.gridLocation.x, this.gridLocation.y + 2 + loop, this.busSize));
		}

		if ((this.numOfInputs % 2) != 0) {
			this.input.changeItem(middle, Wrapper.setPinAt(this.gridLocation.x, this.gridLocation.y + 2 + middle, this.busSize));
			for (loop = middle + 1; loop < this.numOfInputs; loop++) {
				this.input.changeItem(loop, Wrapper.setPinAt(this.gridLocation.x, this.gridLocation.y + 2 + loop, this.busSize));
			}
		} else {
			for (loop = middle; loop < this.numOfInputs; loop++) {
				this.input.changeItem(loop, Wrapper.setPinAt(this.gridLocation.x, this.gridLocation.y + 3 + loop, this.busSize));
			}
		}

		this.select = Wrapper.setPinAt(this.gridLocation.x + 2, this.gridLocation.y, this.selectBusSize);
		this.output = Wrapper.setPinAt(this.gridLocation.x + 4, this.gridLocation.y + 2 + middle, this.busSize);

		this.changeColor(Color.black);
		this.oldBusSize = 0;
	}

	protected void dropedNormal_90() {
		int loop;
		int middle = this.numOfInputs / 2;

		this.input.setSize(this.numOfInputs);

		for (loop = 0; loop < middle; loop++) {
			this.input.changeItem(loop, Wrapper.setPinAt(this.gridLocation.x + 2 + loop, this.gridLocation.y + 4, this.busSize));
		}

		if ((this.numOfInputs % 2) != 0) {
			this.input.changeItem(middle, Wrapper.setPinAt(this.gridLocation.x + 2 + middle, this.gridLocation.y + 4, this.busSize));
			for (loop = middle + 1; loop < this.numOfInputs; loop++) {
				this.input.changeItem(loop, Wrapper.setPinAt(this.gridLocation.x + 2 + loop, this.gridLocation.y + 4, this.busSize));
			}
		} else {
			for (loop = middle; loop < this.numOfInputs; loop++) {
				this.input.changeItem(loop, Wrapper.setPinAt(this.gridLocation.x + 3 + loop, this.gridLocation.y + 4, this.busSize));
			}
		}

		this.select = Wrapper.setPinAt(this.gridLocation.x, this.gridLocation.y + 2, this.selectBusSize);
		this.output = Wrapper.setPinAt(this.gridLocation.x + 2 + middle, this.gridLocation.y, this.busSize);

		this.changeColor(Color.black);
		this.oldBusSize = 0;
	}

	protected void dropedNormal_180() {
		int loop;
		int middle = this.numOfInputs / 2;

		this.input.setSize(this.numOfInputs);

		for (loop = 0; loop < middle; loop++) {
			this.input.changeItem(this.numOfInputs - 1 - loop, Wrapper.setPinAt(this.gridLocation.x + 4, this.gridLocation.y + 2 + loop, this.busSize));
		}

		if ((this.numOfInputs % 2) != 0) {
			this.input.changeItem(this.numOfInputs - 1 - middle, Wrapper.setPinAt(this.gridLocation.x + 4, this.gridLocation.y + 2 + middle, this.busSize));
			for (loop = middle + 1; loop < this.numOfInputs; loop++) {
				this.input.changeItem(this.numOfInputs - 1 - loop, Wrapper.setPinAt(this.gridLocation.x + 4, this.gridLocation.y + 2 + loop, this.busSize));
			}
		} else {
			for (loop = middle; loop < this.numOfInputs; loop++) {
				this.input.changeItem(this.numOfInputs - 1 - loop, Wrapper.setPinAt(this.gridLocation.x + 4, this.gridLocation.y + 3 + loop, this.busSize));
			}
		}

		this.select = Wrapper.setPinAt(this.gridLocation.x + 2, this.gridLocation.y + this.gridSize.height, this.selectBusSize);
		this.output = Wrapper.setPinAt(this.gridLocation.x, this.gridLocation.y + 2 + middle, this.busSize);

		this.changeColor(Color.black);
		this.oldBusSize = 0;
	}

	protected void dropedNormal_270() {
		int loop;
		int middle = this.numOfInputs / 2;

		this.input.setSize(this.numOfInputs);

		for (loop = 0; loop < middle; loop++) {
			this.input.changeItem(this.numOfInputs - 1 - loop, Wrapper.setPinAt(this.gridLocation.x + 2 + loop, this.gridLocation.y, this.busSize));
		}

		if ((this.numOfInputs % 2) != 0) {
			this.input.changeItem(this.numOfInputs - 1 - middle, Wrapper.setPinAt(this.gridLocation.x + 2 + middle, this.gridLocation.y, this.busSize));
			for (loop = middle + 1; loop < this.numOfInputs; loop++) {
				this.input.changeItem(this.numOfInputs - 1 - loop, Wrapper.setPinAt(this.gridLocation.x + 2 + loop, this.gridLocation.y, this.busSize));
			}
		} else {
			for (loop = middle; loop < this.numOfInputs; loop++) {
				this.input.changeItem(this.numOfInputs - 1 - loop, Wrapper.setPinAt(this.gridLocation.x + 3 + loop, this.gridLocation.y, this.busSize));
			}
		}

		this.select = Wrapper.setPinAt(this.gridLocation.x + this.gridSize.width, this.gridLocation.y + 2, this.selectBusSize);
		this.output = Wrapper.setPinAt(this.gridLocation.x + 2 + middle, this.gridLocation.y + 4, this.busSize);

		this.changeColor(Color.black);
		this.oldBusSize = 0;
	}

	protected void dropedFlipped_0() {
		int loop;
		int middle = this.numOfInputs / 2;

		this.input.setSize(this.numOfInputs);

		for (loop = 0; loop < middle; loop++) {
			this.input.changeItem(this.numOfInputs - 1 - loop, Wrapper.setPinAt(this.gridLocation.x, this.gridLocation.y + 2 + loop, this.busSize));
		}

		if ((this.numOfInputs % 2) != 0) {
			this.input.changeItem(this.numOfInputs - 1 - middle, Wrapper.setPinAt(this.gridLocation.x, this.gridLocation.y + 2 + middle, this.busSize));
			for (loop = middle + 1; loop < this.numOfInputs; loop++) {
				this.input.changeItem(this.numOfInputs - 1 - loop, Wrapper.setPinAt(this.gridLocation.x, this.gridLocation.y + 2 + loop, this.busSize));
			}
		} else {
			for (loop = middle; loop < this.numOfInputs; loop++) {
				this.input.changeItem(this.numOfInputs - 1 - loop, Wrapper.setPinAt(this.gridLocation.x, this.gridLocation.y + 3 + loop, this.busSize));
			}
		}

		this.select = Wrapper.setPinAt(this.gridLocation.x + 2, this.gridLocation.y + this.gridSize.height, this.selectBusSize);
		this.output = Wrapper.setPinAt(this.gridLocation.x + 4, this.gridLocation.y + 2 + middle, this.busSize);

		this.changeColor(Color.black);
		this.oldBusSize = 0;
	}

	protected void dropedFlipped_90() {
		int loop;
		int middle = this.numOfInputs / 2;

		this.input.setSize(this.numOfInputs);

		for (loop = 0; loop < middle; loop++) {
			this.input.changeItem(loop, Wrapper.setPinAt(this.gridLocation.x + 2 + loop, this.gridLocation.y, this.busSize));
		}

		if ((this.numOfInputs % 2) != 0) {
			this.input.changeItem(middle, Wrapper.setPinAt(this.gridLocation.x + 2 + middle, this.gridLocation.y, this.busSize));
			for (loop = middle + 1; loop < this.numOfInputs; loop++) {
				this.input.changeItem(loop, Wrapper.setPinAt(this.gridLocation.x + 2 + loop, this.gridLocation.y, this.busSize));
			}
		} else {
			for (loop = middle; loop < this.numOfInputs; loop++) {
				this.input.changeItem(loop, Wrapper.setPinAt(this.gridLocation.x + 3 + loop, this.gridLocation.y, this.busSize));
			}
		}

		this.select = Wrapper.setPinAt(this.gridLocation.x, this.gridLocation.y + 2, this.selectBusSize);
		this.output = Wrapper.setPinAt(this.gridLocation.x + 2 + middle, this.gridLocation.y + 4, this.busSize);

		this.changeColor(Color.black);
		this.oldBusSize = 0;
	}

	protected void dropedFlipped_180() {
		int loop;
		int middle = this.numOfInputs / 2;

		this.input.setSize(this.numOfInputs);

		for (loop = 0; loop < middle; loop++) {
			this.input.changeItem(loop, Wrapper.setPinAt(this.gridLocation.x + 4, this.gridLocation.y + 2 + loop, this.busSize));
		}

		if ((this.numOfInputs % 2) != 0) {
			this.input.changeItem(middle, Wrapper.setPinAt(this.gridLocation.x + 4, this.gridLocation.y + 2 + middle, this.busSize));
			for (loop = middle + 1; loop < this.numOfInputs; loop++) {
				this.input.changeItem(loop, Wrapper.setPinAt(this.gridLocation.x + 4, this.gridLocation.y + 2 + loop, this.busSize));
			}
		} else {
			for (loop = middle; loop < this.numOfInputs; loop++) {
				this.input.changeItem(loop, Wrapper.setPinAt(this.gridLocation.x + 4, this.gridLocation.y + 3 + loop, this.busSize));
			}
		}

		this.select = Wrapper.setPinAt(this.gridLocation.x + 2, this.gridLocation.y, this.selectBusSize);
		this.output = Wrapper.setPinAt(this.gridLocation.x, this.gridLocation.y + 2 + middle, this.busSize);

		this.changeColor(Color.black);
		this.oldBusSize = 0;
	}

	protected void dropedFlipped_270() {
		int loop;
		int middle = this.numOfInputs / 2;

		this.input.setSize(this.numOfInputs);

		for (loop = 0; loop < middle; loop++) {
			this.input.changeItem(this.numOfInputs - 1 - loop, Wrapper.setPinAt(this.gridLocation.x + 2 + loop, this.gridLocation.y + 4, this.busSize));
		}

		if ((this.numOfInputs % 2) != 0) {
			this.input.changeItem(this.numOfInputs - 1 - middle, Wrapper.setPinAt(this.gridLocation.x + 2 + middle, this.gridLocation.y + 4, this.busSize));
			for (loop = middle + 1; loop < this.numOfInputs; loop++) {
				this.input.changeItem(this.numOfInputs - 1 - loop, Wrapper.setPinAt(this.gridLocation.x + 2 + loop, this.gridLocation.y + 4, this.busSize));
			}
		} else {
			for (loop = middle; loop < this.numOfInputs; loop++) {
				this.input.changeItem(this.numOfInputs - 1 - loop, Wrapper.setPinAt(this.gridLocation.x + 3 + loop, this.gridLocation.y + 4, this.busSize));
			}
		}

		this.select = Wrapper.setPinAt(this.gridLocation.x + this.gridSize.width, this.gridLocation.y + 2, this.selectBusSize);
		this.output = Wrapper.setPinAt(this.gridLocation.x + 2 + middle, this.gridLocation.y, this.busSize);

		this.changeColor(Color.black);
		this.oldBusSize = 0;
	}

	protected void adjustToChanges() {
		if (this.angle % 180 == 0) {
			this.setGridSize(4, 2 * (this.numOfInputs / 2) + 4);
		} else {
			this.setGridSize(2 * (this.numOfInputs / 2) + 4, 4);
		}
	}
	/* ==================================================================
	 Popup Part
	 ================================================================= */
	private int oldBusSize = 0;
	private int oldSelectSize;

	public boolean hasProperties() {
		return true;
	}

	public Component getPropertyWindow() {
		return (new MuxProperties(this.busSize, this.selectBusSize, this.delay));
	}

	public void respondToChanges(Component property) {
		MuxProperties dp = (MuxProperties) property;

		this.delay = dp.getDelay();

		if (this.oldBusSize == 0) {
			this.oldBusSize = this.busSize;
			this.oldSelectSize = this.selectBusSize;
		}

		CentralPanel.ACTIVE_GRID.eraseComponent(this);
		this.setBusSize(dp.getBusSize());
		this.setNumOfInputs((int) Math.pow(2, dp.getInputSize()));
		CentralPanel.ACTIVE_GRID.paintComponent(this);

	}

	public void restoreOriginalProperties() {
		if (this.oldBusSize != 0) {
			this.setBusSize(this.oldBusSize);
			this.oldBusSize = 0;
			this.setNumOfInputs((int) Math.pow(2, this.oldSelectSize));
		}
	}
	
	
	@Override
	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(this.getVHDLName())){
					written = true;
				}
			}
			scanner.close();
		} catch (FileNotFoundException e1) {
			e1.printStackTrace();
		}
		
		if(!written){
			Writer writer = null;
			try {
				writer = new FileWriter(path+"\\"+fileName,true);
				writer.write("\nlibrary IEEE;\n");
				writer.write("use IEEE.STD_LOGIC_1164.ALL;\n");
				writer.write("use ieee.numeric_std.all;\n");
				
				writer.write("\nentity " + this.getVHDLName() + " is\n");
				writer.write("port(\n");
				for(int j = 0; j < this.selectBusSize; j++){
					writer.write("s"+j+",");
				}
				for(int j = 0; j < (Math.pow(2,this.selectBusSize)); j++){
					if(j != 0)
						writer.write (",");
					for(int i = 0; i < this.busSize; i++){
						if(i != 0)
							writer.write(",");
						writer.write("x" + j +""+ i); //j - input num, i - bit num
					}
				}
				writer.write(" : in std_logic;\n");
				for(int i = 0; i < this.busSize; i++){
					if(i != 0)
						writer.write(",");
					writer.write("f" + i);
				}
				writer.write(" : out std_logic);\n");
				writer.write("end "+ this.getVHDLName() + ";\n\n");
				
				writer.write("architecture behav of "+ this.getVHDLName() + " is\n");
				writer.write("signal sel : std_logic_vector("+(this.selectBusSize-1)+" downto 0);\n");
				writer.write("begin\n");
				for(int j = 0; j < this.selectBusSize; j++){
					writer.write("sel("+j+") <= s"+j+";\n");
				}
				for(int i = 0; i < this.busSize; i++){
					writer.write("f"+i+" <= ");
					for(int j = 0; j < (Math.pow(2,this.selectBusSize)); j++){
						if(j != 0)
							writer.write(" else \n");
						writer.write("x"+j+i+" when to_integer(unsigned(sel))=" + j);
						if(j == (Math.pow(2,this.selectBusSize)-1))
							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 "MUX_SEL"+this.selectBusSize+"_DATA"+this.busSize;
	}
	
}
