package sim.lib.memory;

import java.awt.*;
import java.io.*;
import java.util.Scanner;
import java.awt.event.*;

import gjt.BulletinLayout;

import sim.*;
import sim.engine.*;
import sim.lib.memory.hex.*;
import sim.util.SimSeparator;
import sim.util.DialogButton;
import sim.lib.wires.Junction;

public class Ram extends MemoryStructure {
	/* ==================================================================
	 Creation Part
	 ================================================================= */

	private static Image ICON = GuiFileLink.getImage("sim/lib/memory/RamIcon.gif");

	public Image getIcon() {
		return Ram.ICON;
	}

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

	/* ==================================================================
	 GUI part
	 ================================================================= */
	public Ram() {
		super();
		this.componentName = "RAM";
	}

	protected Wrapper getCopy() {
		Ram result = new Ram();

		result.setBusSize(this.busSize);
		result.setAddressSpace(this.addressSpace);
		result.initializeMemory();

		return result;
	}
	
	public int getBusSize(){
		return this.busSize;
	}

	public void paint(Graphics g) {
		// draw if visible
		if (this.isVisible()) {
			int gridGap = CentralPanel.ACTIVE_GRID.getCurrentGridGap();
			int increment = gridGap / 4;

			int x = gridGap;
			int y = gridGap;
			int width = 8 * gridGap;
			int height = 5 * gridGap;
			int center = x + width / 2;

			Shape old = g.getClip();

			FontMetrics fm;

			//outer frame
			g.setColor(this.brush);
			g.drawRect(x, y, width, height);

			// Component name
			width = 4 * gridGap;
			x = center - width / 2;
			g.setClip(x, y, width, height);

			g.setFont(new Font(Wrapper.FONT_NAME, Font.BOLD, 3 * increment));
			fm = g.getFontMetrics(g.getFont());
			x = center - fm.stringWidth(this.componentName) / 2;
			y = 2 * gridGap;
			g.drawString(this.componentName, x, y);

			g.setClip(old);

			//address window
			width = 3 * gridGap + 2 * increment;
			height = gridGap + 2 * increment;
			x = gridGap;
			y = 3 * gridGap - increment;
			g.setFont(new Font(Wrapper.FONT_NAME, Font.PLAIN, 3 * increment));

			g.setColor(WrapperPainted.BACKGROUND);
			g.clearRect(x, y, width, height);
			g.fillRect(x, y, width, height);
			g.setColor(this.brush);
			g.drawRect(x, y, width, height);

			g.setClip(x, y, width, height);
			if (this.addressToDraw != null) {
				g.setClip(x, y, width, height);
				x += (width - fm.stringWidth(this.addressToDraw)) / 2;
				g.drawString(this.addressToDraw, x, y + gridGap);
			}
			g.setClip(old);

			//data windows
			x = 9 * gridGap - width;

			g.setColor(WrapperPainted.BACKGROUND);
			g.clearRect(x, y, width, height);
			g.fillRect(x, y, width, height);
			g.setColor(this.brush);
			g.drawRect(x, y, width, height);

			g.setClip(x, y, width, height);
			if (this.dataToDraw != null) {
				g.setClip(x, y, width, height);
				x += (width - fm.stringWidth(this.dataToDraw)) / 2;
				g.drawString(this.dataToDraw, x, y + gridGap);
			}
			g.setClip(old);

			//control wires
			g.setColor(this.brush);
			g.drawLine(2 * gridGap, 6 * gridGap, 2 * gridGap, 7 * gridGap);
			g.drawLine(5 * gridGap, 6 * gridGap, 5 * gridGap, 7 * gridGap);
			g.drawLine(8 * gridGap, 6 * gridGap, 8 * gridGap, 7 * gridGap);

			//IO bus
			g.fillRect(0, 2 * gridGap - 1, gridGap, 3);
			g.fillRect(9 * gridGap, 2 * gridGap - 1, gridGap, 3);

			//labels
			y = 2 * gridGap + increment;
			g.drawString("A" + (this.requiredAddress - 1) + "-0", gridGap + increment, y);
			String toDraw = "D" + (this.busSize - 1) + "-0";
			g.drawString(toDraw, 9 * gridGap - fm.stringWidth(toDraw), y);

			g.drawString("___", 2 * gridGap - fm.stringWidth("___") / 2, 23 * increment - fm.getHeight());
			g.drawString("CE", 2 * gridGap - fm.stringWidth("CE") / 2, 23 * increment);
			g.drawString("___", 8 * gridGap - fm.stringWidth("___") / 2, 23 * increment - fm.getHeight());
			g.drawString("OE", 8 * gridGap - fm.stringWidth("OE") / 2, 23 * increment);
			g.drawString("___", 5 * gridGap - fm.stringWidth("___") / 2, 23 * increment - fm.getHeight());
			g.drawString("WE", 5 * gridGap - fm.stringWidth("WE") / 2, 23 * increment);


		}
	}

	/* ==================================================================
	 Maintanance Part
	 ================================================================= */
	protected Junction notWE = null;

	public boolean canDrop() {
		boolean result = Wrapper.canDropJuncion(this.gridLocation.x, this.gridLocation.y + 2, this.requiredAddress);
		result = result && Wrapper.canDropJuncion(this.gridLocation.x + 10, this.gridLocation.y + 2, this.busSize);
		result = result && Wrapper.canDropJuncion(this.gridLocation.x + 2, this.gridLocation.y + 7, 1);
		result = result && Wrapper.canDropJuncion(this.gridLocation.x + 5, this.gridLocation.y + 7, 1);
		result = result && Wrapper.canDropJuncion(this.gridLocation.x + 8, this.gridLocation.y + 7, 1);

		return result;
	}

	public void droped() {
		this.address = Wrapper.setPinAt(this.gridLocation.x, this.gridLocation.y + 2, this.requiredAddress);
		this.data = Wrapper.setPinAt(this.gridLocation.x + 10, this.gridLocation.y + 2, this.busSize);
		this.notCE = Wrapper.setPinAt(this.gridLocation.x + 2, this.gridLocation.y + 7, 1);
		this.notWE = Wrapper.setPinAt(this.gridLocation.x + 5, this.gridLocation.y + 7, 1);
		this.notOE = Wrapper.setPinAt(this.gridLocation.x + 8, this.gridLocation.y + 7, 1);

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

	public void selected() {
		this.address.removePin();
		this.data.removePin();
		this.notCE.removePin();
		this.notOE.removePin();
		this.notWE.removePin();

		this.changeColor(Color.green);
	}

	public void checkAfterSelected() {
		Wrapper.checkPin(this.address);
		Wrapper.checkPin(this.data);
		Wrapper.checkPin(this.notCE);
		Wrapper.checkPin(this.notOE);
		Wrapper.checkPin(this.notWE);
	}

	/* ==================================================================
	 Simulation part
	 ================================================================= */
	// write cycle times
	protected double aw = 10.5;	// address valid to end of write
	protected double as = 2;	// addess set up
	protected double wp = 7;	// write pulse width
	protected double wr = 0.5;	// write recovery
	protected double whz = 5;	// write to output
	protected double dw = 3.5;	// data to write time overlap
	protected double dh = 0.5;	// data hold from write time
	protected double ow = 0.5;	// output active from end of write
	// simulation variables
	protected double notWE_goesLow;
	protected double notWE_goesHigh;
	protected boolean pastNotWE;
	protected double startWriting;
	protected double stopWriting;
	private double dataChange;
	private int oldData;
	private int writtenData;
	private boolean dataHandled;
	private boolean isWriting;

	public void evaluateOutput(double currentTime, Data[] currentInputs, EnginePeer peer) throws EngineException {
		// check address
		boolean foundUndefined = false;
		int base = 1;
		int newValue = 0;
		int loop;

		for (loop = 0; (loop < this.requiredAddress) && (!foundUndefined); loop++) {
			if (currentInputs[3 + loop + this.busSize].isUndefined()) {
				foundUndefined = true;
				newValue = -1;
			} else if (currentInputs[3 + loop + this.busSize].getValue()) {
				newValue = newValue + base;
			}

			base = 2 * base;
		}

		if (newValue != this.oldAddress) {
			this.addressChange = currentTime;
			this.oldAddress = newValue;
			this.addressHandled = false;

			if (this.oldAddress == -1) {
				this.addressToDraw = "-";
				this.dataToDraw = "-";

				for (newValue = 1; newValue < this.addressLenght; newValue++) {
					this.addressToDraw = this.addressToDraw + "-";
				}

				for (newValue = 1; newValue < this.wordLenght; newValue++) {
					this.dataToDraw = this.dataToDraw + "-";
				}
			} else {
				this.addressToDraw = Integer.toHexString(this.oldAddress);

				for (newValue = this.addressToDraw.length(); newValue < this.addressLenght; newValue++) {
					this.addressToDraw = "0" + this.addressToDraw;
				}

				this.dataToDraw = (new Character(this.memoryContent[this.oldAddress][this.wordLenght - 1])).toString();

				for (newValue = 1; newValue < this.wordLenght; newValue++) {
					this.dataToDraw = this.dataToDraw + this.memoryContent[this.oldAddress][this.wordLenght - newValue - 1];
				}

				this.addressToDraw = this.addressToDraw.toUpperCase();
				this.dataToDraw = this.dataToDraw.toUpperCase();
			}

			CentralPanel.ACTIVE_GRID.paintComponent(this);
		}

		// check data
		foundUndefined = false;
		base = 1;
		newValue = 0;

		for (loop = 0; (loop < this.busSize) && (!foundUndefined); loop++) {
			if (currentInputs[3 + loop].isUndefined()) {
				foundUndefined = true;
				newValue = -1;
			} else if (currentInputs[3 + loop].getValue()) {
				newValue = newValue + base;
			}

			base = 2 * base;
		}

		if (newValue != this.oldData) {
			this.dataChange = currentTime;
			this.oldData = newValue;
		}

		// check notCE
		if (currentInputs[0].isUndefined() || currentInputs[0].getValue()) {
			if (!this.pastNotCE) {
				this.notCE_goesHigh = currentTime;
			}

			this.pastNotCE = true;
		} else {
			if (this.pastNotCE) {
				this.notCE_goesLow = currentTime;
			}

			this.pastNotCE = false;
		}

		// check notOE
		if (currentInputs[1].isUndefined() || currentInputs[1].getValue()) {
			if (!this.pastNotOE) {
				this.notOE_goesHigh = currentTime;
			}

			this.pastNotOE = true;
		} else {
			if (this.pastNotOE) {
				this.notOE_goesLow = currentTime;
			}

			this.pastNotOE = false;
		}

		// check notWE
		if (currentInputs[2].isUndefined() || currentInputs[2].getValue()) {
			if (!this.pastNotWE) {
				this.notWE_goesHigh = currentTime;
			}

			this.pastNotWE = true;
		} else {
			if (this.pastNotWE) {
				this.notWE_goesLow = currentTime;
			}

			this.pastNotWE = false;
		}

		// simulate
		if ((!this.pastNotCE) && (!this.pastNotWE)) {
			//do write
			if (!this.isWriting && ((this.notCE_goesLow == currentTime) || (this.notWE_goesLow == currentTime))) {
				if (this.isReading) {
					this.startFloating = currentTime + this.whz;
					this.floatOutputs(this.startFloating, peer);
					this.isReading = false;
				} else if (this.startFloating > currentTime + this.whz) {
					this.startFloating = currentTime + this.whz;
					this.floatOutputs(this.startFloating, peer);
				}

				this.startWriting = currentTime;
				this.isWriting = true;
			}
		} else {
			// handle stop of writing
			if (this.isWriting && (currentTime > this.startWriting)) {
				this.dataHandled = false;
				this.stopWriting = currentTime;

				if ((currentTime - this.addressChange < this.aw) || (this.startWriting - this.addressChange < this.as)) {
					this.undefineWholeMemory();		// did not hold address long enough for wrinting
					this.writtenData = -1;
				} else if ((currentTime - this.startWriting < this.wp) || (currentTime - this.dataChange < this.dw)) {
					this.writeUndefineToMemory(this.oldAddress);	// did not hold data long enough for wrinting
					this.writtenData = -1;
				} else {
					this.writeDataToMemory(this.oldAddress, this.oldData);
					this.writtenData = this.oldData;
				}
			}

			this.isWriting = false;

			// handle write recovery
			if ((this.dataChange >= this.stopWriting) && (this.dataChange < this.stopWriting + this.wr)) {
				if (!this.dataHandled) {
					if (this.dataChange < this.stopWriting + this.dh) {
						this.putData(this.writtenData, this.dataChange, peer);
						this.undefineOutputs(this.stopWriting + this.dh, peer);
						this.floatOutputs(this.stopWriting + this.wr, peer);
					} else if (this.dataChange < this.stopWriting + this.wr) {
						this.undefineOutputs(this.dataChange, peer);
						this.floatOutputs(this.stopWriting + this.wr, peer);
					}

					this.dataHandled = true;
				}
			}

			// handle read
			if (!this.pastNotCE && !this.pastNotOE) {
				// handle start of reading
				if ((this.notOE_goesLow == currentTime) && (this.notCE_goesLow == currentTime)) {
					this.startPutting = currentTime + Math.max(this.oe, this.acs);
					this.undefineOutputs(currentTime + Math.min(this.olz, this.clz), peer);
					this.addressHandled = false;
					this.isReading = true;
				} else if (this.notOE_goesLow == currentTime) {
					this.startPutting = currentTime + this.oe;
					this.undefineOutputs(currentTime + this.olz, peer);
					this.addressHandled = false;
					this.isReading = true;
				} else if (this.notCE_goesLow == currentTime) {
					this.startPutting = currentTime + this.acs;
					this.undefineOutputs(currentTime + this.clz, peer);
					this.addressHandled = false;
					this.isReading = true;
				} else if (this.stopWriting == currentTime) {
					this.startPutting = currentTime + this.ow;
					this.undefineOutputs(this.startPutting, peer);
					this.addressHandled = false;
					this.isReading = true;
				}

				// handle reading
				if (!this.addressHandled) {
					if (this.startPutting >= this.addressChange + this.oh) // handle start of reading
					{
						this.setSignalsAt(this.oldAddress, this.startPutting, peer);
					} else {
						this.undefineOutputs(this.addressChange + this.oh, peer);
						this.setSignalsAt(this.oldAddress, this.addressChange + this.aa, peer);
					}

					this.addressHandled = true;
				}
			} else {
				// handle stop of reading
				if (this.isReading) {
					if ((this.notOE_goesHigh == currentTime) && (this.notCE_goesHigh == currentTime)) {
						this.startFloating = currentTime + Math.min(this.ohz, this.chz);
						this.floatOutputs(this.startFloating, peer);
					} else if (this.notOE_goesHigh == currentTime) {
						this.startFloating = currentTime + this.ohz;
						this.floatOutputs(this.startFloating, peer);
					} else if (this.notCE_goesHigh == currentTime) {
						this.startFloating = currentTime + this.chz;
						this.floatOutputs(this.startFloating, peer);
					}

					this.isReading = false;
				}

				// handle address change during stop
				if (!this.addressHandled && (this.startFloating > this.addressChange + this.oh)) {
					if (this.startPutting >= this.addressChange + this.oh) // handle start of reading
					{
						this.setSignalsAt(this.oldAddress, this.startPutting, peer);
					} else {
						this.undefineOutputs(this.addressChange + this.oh, peer);
						this.setSignalsAt(this.oldAddress, this.addressChange + this.aa, peer);
					}

					this.floatOutputs(this.startFloating, peer);
					this.addressHandled = true;
				}
			}
		}
	}

	public void createEnginePeer(EnginePeerList epl) {
		int loop;
		EnginePeer ep = new EnginePeer(3 + this.busSize + this.requiredAddress, this.busSize, this);

		ep.setInputPin(0, this.notCE.getNodes().getItemAt(0));
		ep.setInputPin(1, this.notOE.getNodes().getItemAt(0));
		ep.setInputPin(2, this.notWE.getNodes().getItemAt(0));

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

		for (loop = 0; loop < this.requiredAddress; loop++) {
			ep.setInputPin(loop + 3 + this.busSize, this.address.getNodes().getItemAt(loop));
		}

		this.notCE_goesLow = 0;
		this.notCE_goesHigh = 0;
		this.notOE_goesLow = 0;
		this.notOE_goesHigh = 0;
		this.notWE_goesLow = 0;
		this.notWE_goesHigh = 0;

		this.pastNotCE = true;
		this.pastNotOE = true;
		this.pastNotWE = true;

		this.oldAddress = -1;
		this.addressChange = 0;
		this.addressHandled = false;

		this.oldData = -1;
		this.dataChange = 0;
		this.dataHandled = true;

		this.startPutting = Double.MIN_VALUE;
		this.startFloating = Double.MIN_VALUE;
		this.isReading = false;

		this.startWriting = Double.MIN_VALUE;
		this.stopWriting = Double.MIN_VALUE;
		this.isWriting = false;

		epl.insertItem(ep);

		if (this.editor != null) {
			this.editor.prepareForSimulation();
		}
	}

	private void writeUndefineToMemory(int address) {
		int loop;

		if (address == -1) {
			this.undefineWholeMemory();
		} else {
			for (loop = 0; loop < this.wordLenght; loop++) {
				this.memoryContent[address][loop] = '-';
			}

			if (this.editor != null) {
				this.editor.writeTo(address);
			}

			this.dataToDraw = new String(this.memoryContent[address]);
			CentralPanel.ACTIVE_GRID.paintComponent(this);
		}
	}

	private void writeDataToMemory(int address, int data) {
		int loop;
		String value;

		if (address == -1) {
			this.undefineWholeMemory();
		} else if (data == -1) {
			for (loop = 0; loop < this.wordLenght; loop++) {
				this.memoryContent[address][loop] = '-';
			}

			if (this.editor != null) {
				this.editor.writeTo(address);
			}

			this.dataToDraw = new String(this.memoryContent[address]);
			CentralPanel.ACTIVE_GRID.paintComponent(this);
		} else {
			value = Integer.toString(data, 16);

			for (loop = value.length(); loop < this.wordLenght; loop++) {
				value = "0" + value;
			}

			for (loop = 0; loop < this.wordLenght; loop++) {
				this.memoryContent[address][loop] = value.charAt(this.wordLenght - 1 - loop);
			}

			if (this.editor != null) {
				this.editor.writeTo(address);
			}

			this.dataToDraw = (new Character(this.memoryContent[this.oldAddress][this.wordLenght - 1])).toString();

			for (loop = 1; loop < this.wordLenght; loop++) {
				this.dataToDraw = this.dataToDraw + this.memoryContent[this.oldAddress][this.wordLenght - loop - 1];
			}

			this.dataToDraw = this.dataToDraw.toUpperCase();
			CentralPanel.ACTIVE_GRID.paintComponent(this);
		}
	}

	private void undefineWholeMemory() {
		int loop, index;

		for (loop = 0; loop < this.addressSpace; loop++) {
			for (index = 0; index < this.wordLenght; index++) {
				this.memoryContent[loop][index] = '-';
			}
		}

		if (this.editor != null) {
			this.editor.writeToEverywhere();
		}

		this.dataToDraw = new String(this.memoryContent[0]);
		CentralPanel.ACTIVE_GRID.paintComponent(this);
	}

	/* ==================================================================
	 Storage Part
	 ================================================================= */
	public String getSpecificParameters() {
		String result = this.targetFile + Wrapper.SEPARATOR + this.busSize + Wrapper.SEPARATOR + this.addressSpace + Wrapper.SEPARATOR;

		result = result + this.aa + Wrapper.SEPARATOR + this.acs + Wrapper.SEPARATOR + this.clz + Wrapper.SEPARATOR + this.oe + Wrapper.SEPARATOR;
		result = result + this.olz + Wrapper.SEPARATOR + this.chz + Wrapper.SEPARATOR + this.ohz + Wrapper.SEPARATOR + this.oh + Wrapper.SEPARATOR;

		result = result + this.aw + Wrapper.SEPARATOR + this.as + Wrapper.SEPARATOR + this.wp + Wrapper.SEPARATOR + this.wr + Wrapper.SEPARATOR;
		result = result + this.whz + Wrapper.SEPARATOR + this.dw + Wrapper.SEPARATOR + this.dh + Wrapper.SEPARATOR + this.ow + Wrapper.SEPARATOR;

		return result;
	}

	public void loadWrapper(String[] specificParameters) throws SimException {
		if (specificParameters.length == this.getNumberOfSpecificParameters()) {
			try {
				this.targetFile = specificParameters[0];
				this.setBusSize(Integer.valueOf(specificParameters[1]).intValue());
				this.setAddressSpace(Integer.valueOf(specificParameters[2]).intValue());

				this.aa = Double.valueOf(specificParameters[3]).doubleValue();
				this.acs = Double.valueOf(specificParameters[4]).doubleValue();
				this.clz = Double.valueOf(specificParameters[5]).doubleValue();
				this.oe = Double.valueOf(specificParameters[6]).doubleValue();
				this.olz = Double.valueOf(specificParameters[7]).doubleValue();
				this.chz = Double.valueOf(specificParameters[8]).doubleValue();
				this.ohz = Double.valueOf(specificParameters[9]).doubleValue();
				this.oh = Double.valueOf(specificParameters[10]).doubleValue();

				this.aw = Double.valueOf(specificParameters[11]).doubleValue();
				this.as = Double.valueOf(specificParameters[12]).doubleValue();
				this.wp = Double.valueOf(specificParameters[13]).doubleValue();
				this.wr = Double.valueOf(specificParameters[14]).doubleValue();
				this.whz = Double.valueOf(specificParameters[15]).doubleValue();
				this.dw = Double.valueOf(specificParameters[16]).doubleValue();
				this.dh = Double.valueOf(specificParameters[17]).doubleValue();
				this.ow = Double.valueOf(specificParameters[18]).doubleValue();

				this.initializeMemory();
			} catch (NumberFormatException e) {
				throw (new SimException("incorrect parameter type"));
			}
		} else {
			throw (new SimException("incorrect number of parameters"));
		}
	}

	public int getNumberOfSpecificParameters() {
		return 19;
	}

	/* ==================================================================
	 Popup Part
	 ================================================================= */
	private int oldAddressSpace;
	private int oldBusSize = 0;

	public boolean hasProperties() {
		return true;
	}

	public Component getPropertyWindow() {
		return (new RamProperties(this.targetFile, this.componentName, this.busSize, this.requiredAddress, this.aa, this.acs, this.clz, this.oe, this.olz, this.chz, this.ohz, this.oh, this.aw, this.as, this.wp, this.wr, this.whz, this.dw, this.dh, this.ow));
	}

	public void respondToChanges(Component property) {
		try {
			CentralPanel.ACTIVE_GRID.eraseComponent(this, false);

			RamProperties x = (RamProperties) property;

			this.aa = x.getAA();
			this.acs = x.getACS();
			this.clz = x.getCLZ();
			this.oe = x.getOE();
			this.olz = x.getOLZ();
			this.chz = x.getCHZ();
			this.ohz = x.getOHZ();
			this.oh = x.getOH();

			this.aw = x.getAW();
			this.as = x.getAS();
			this.wp = x.getWP();
			this.wr = x.getWR();
			this.whz = x.getWHZ();
			this.dw = x.getDW();
			this.dh = x.getDH();
			this.ow = x.getOW();

			if (this.oldBusSize == 0) {
				this.oldBusSize = this.busSize;
				this.oldAddressSpace = this.requiredAddress;
			}

			this.setBusSize(x.getBusSize());
			this.setAddressSpace((int) Math.pow(2, x.getAddressSize()));

			this.targetFile = x.getFileName();
			this.componentName = x.getComponentName();
			this.initializeMemory();

			CentralPanel.ACTIVE_GRID.paintComponent(this);
		} catch (Throwable err) {
			this.setBusSize(this.oldBusSize);
			this.setAddressSpace((int) Math.pow(2, this.oldAddressSpace));
			this.oldBusSize = 0;
			this.initializeMemory();

			CentralPanel.ACTIVE_GRID.paintComponent(this);

			MainWindow.OK_WINDOW.setDescription("Can not increase memory size");
			MainWindow.OK_WINDOW.setMessage("fail to allocate more memory");
			MainWindow.OK_WINDOW.setVisible(true);
		}

		if (this.editor != null) {
			this.editor.changeParameters(this.memoryContent, this.targetFile, this.busSize, this.addressSpace);
		}
	}

	public void restoreOriginalProperties() {
		if (this.oldBusSize != 0) {
			this.setBusSize(this.oldBusSize);
			this.setAddressSpace((int) Math.pow(2, this.oldAddressSpace));

			this.initializeMemory();
			this.oldBusSize = 0;

			if (this.editor != null) {
				this.editor.changeParameters(this.memoryContent, this.targetFile, this.busSize, this.addressSpace);
			}
		}
	}

	@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( notce,notoe,notwe : in std_logic;\n");
				int addr = this.addressSpace;
				int addr_bits = 0;
				while(addr != 1){
					addr_bits++;
					addr = addr/2;
				}
				for(int i = 0; i < addr_bits; i++){
					if(i != 0)
						writer.write(",");
					writer.write("a" + i);
				}
				writer.write(" : in std_logic;\n");
				for(int i = 0; i < this.busSize; i++){
					if(i != 0)
						writer.write(",");
					writer.write("d" + i);
				}
				writer.write(" : inout std_logic);\n");
				writer.write("end "+ this.getVHDLName() + ";\n\n");
				
				writer.write("architecture behav of "+ this.getVHDLName() + " is\n");
				writer.write("signal address: std_logic_vector("+(addr_bits-1)+" downto 0);\n");
				writer.write("signal data: std_logic_vector("+(this.busSize-1)+" downto 0);\n");
				writer.write("type ram_t is array (0 to "+(this.addressSpace-1)+") of std_logic_vector("+(this.busSize-1)+" downto 0);\n");
				writer.write("signal ram : ram_t := (others => (others => '0'));\n");
				writer.write("begin\n");
				for(int x = 0; x < addr_bits; x++){
					writer.write("address(" + x + ") <= a" + x + ";\n");
				}
				for(int x = 0; x < this.busSize; x++){
					writer.write("d" + x + " <= data(" + x + ") when notwe='1' else 'Z';\n");
				}
				writer.write("process (address,notwe) is\n");
				writer.write("variable temp : std_logic_vector("+(this.busSize-1)+" downto 0);\n");
				writer.write("begin\n");
				writer.write("if(notce='0') then\n");
				writer.write("if(notwe='0') then\n");
				for(int x = 0; x < this.busSize; x++){
					writer.write("temp(" + x + ") := d" + x + ";\n");
				}
				writer.write("ram(to_integer(unsigned(address))) <= temp;\n");
				writer.write("else\n");
				writer.write("if(notoe='0') then\n");
				writer.write("data <= ram(to_integer(unsigned(address)));\n");
				writer.write("end if;\n");
				writer.write("end if;\n");
				writer.write("end if;\n");
				writer.write("end process;\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 "RAM_ADDR"+this.addressSpace+"_DATA"+this.busSize;
	}
}
