package sim.lib.memory;

import java.awt.*;
import java.io.*;
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();
	}
	
	protected Wrapper getCopy()
	{
		Ram result = new Ram();
		
		result.setBusSize(this.busSize);
		result.setAddressSpace(this.addressSpace);
		result.initializeMemory();
		
		return result;
	}
	
	public void paint(Graphics g)
	{
		// draw if visible
		if(this.isVisible())
		{
			int gridGap = CentralPanel.ACTIVE_GRID.getCurrentGridGap();
			int increment = gridGap / 4;
			
			g.setColor(Color.white);
			g.fillRect(gridGap, 11 * increment, 14 * increment, 6 * increment);
			g.fillRect(22 * increment, 11 * increment, 14 * increment, 6 * increment);
			
			g.setColor(this.brush);
			g.drawRect(gridGap, gridGap, 8 * gridGap, 5 * gridGap);
			
			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);
			
			g.fillRect(0, 2 * gridGap - 1, gridGap, 3);
			g.fillRect(9 * gridGap, 2 * gridGap - 1, gridGap, 3);
			
			g.setFont(new Font(Wrapper.FONT_NAME, Font.BOLD, 3 * increment));
			FontMetrics fm = g.getFontMetrics(g.getFont());
			g.drawString("RAM", 5 * gridGap - fm.stringWidth("RAM") / 2, 2 * gridGap);
			
			g.setFont(new Font(Wrapper.FONT_NAME, Font.PLAIN, 3 * increment));
			fm = g.getFontMetrics(g.getFont());
			
			g.drawString("A" + (this.requiredAddress - 1) + "-0", gridGap + increment, 9 * increment);
			String toDraw = "D" + (this.busSize - 1) + "-0";
			g.drawString(toDraw, 9 * gridGap - increment - fm.stringWidth(toDraw), 9 * increment);
			
			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);
			
			g.drawRect(gridGap, 11 * increment, 14 * increment, 6 * increment);
			g.drawRect(22 * increment, 11 * increment, 14 * increment, 6 * increment);
			
			Shape old = g.getClip();
			
			if(this.addressToDraw != null)
			{
				g.setClip(gridGap, 11 * increment, 14 * increment, 6 * increment);
				g.drawString(this.addressToDraw, 11 * increment - fm.stringWidth(this.addressToDraw) / 2, 15 * increment);
			}
			
			if(this.dataToDraw != null)
			{
				g.setClip(22 * increment, 11 * increment, 14 * increment, 6 * increment);
				g.drawString(this.dataToDraw, 29 * increment - fm.stringWidth(this.dataToDraw) / 2, 15 * increment);
			}
			
			g.setClip(old);
		}
	}
	
/* ==================================================================
	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.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.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.show();
		}
		
		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);
		}
	}
	
	private class RamProperties extends Container implements ActionListener, FocusListener
	{
		private DialogButton browse = new DialogButton("Browse...");
		
		private TextField editFileName = new TextField();
		private TextField editBusSize = new TextField(5);
		private TextField editAddressSize = new TextField(5);
		private TextField editAA = new TextField(5);
		private TextField editACS = new TextField(5);
		private TextField editCLZ = new TextField(5);
		private TextField editOE = new TextField(5);
		private TextField editOLZ = new TextField(5);
		private TextField editCHZ = new TextField(5);
		private TextField editOHZ = new TextField(5);
		private TextField editOH = new TextField(5);
		private TextField editAW = new TextField(5);
		private TextField editAS = new TextField(5);
		private TextField editWP = new TextField(5);
		private TextField editWR = new TextField(5);
		private TextField editWHZ = new TextField(5);
		private TextField editDW = new TextField(5);
		private TextField editDH = new TextField(5);
		private TextField editOW = new TextField(5);
		
		private Label content = new Label("Memory Content");
		private Label busSize = new Label("Bus Sizes");
		private Label delays = new Label("Propagation Delays");
		
		private String oldName;
		private int oldBusSize;
		private int oldAddressSize;
		
		private double oldAA;
		private double oldACS;
		private double oldCLZ;
		private double oldOE;
		private double oldOLZ;
		private double oldCHZ;
		private double oldOHZ;
		private double oldOH;
		private double oldAW;
		private double oldAS;
		private double oldWP;
		private double oldWR;
		private double oldWHZ;
		private double oldDW;
		private double oldDH;
		private double oldOW;
		
		private ScrollPane scroller = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED);
		
		public RamProperties(String file, int bus, int address, double aa, double acs, double clz, double oe, double olz, double chz, double ohz, double oh, double aw, double as, double wp, double wr, double whz, double dw, double dh, double ow)
		{
			super();
			this.setLayout(new GridBagLayout());
			
			if(MainWindow.MASTER != null)
			{
				this.editFileName.setEnabled(false);
				this.browse.setEnabled(false);
			}
			
			this.oldName = file;
			this.oldBusSize = bus;
			this.oldAddressSize = address;
			this.oldAA = aa;
			this.oldACS = acs;
			this.oldCLZ = clz;
			this.oldOE = oe;
			this.oldOLZ = olz;
			this.oldCHZ = chz;
			this.oldOHZ = ohz;
			this.oldOH = oh;
			this.oldAW = aw;
			this.oldAS = as;
			this.oldWP = wp;
			this.oldWR = wr;
			this.oldWHZ = whz;
			this.oldDW = dw;
			this.oldDH = dh;
			this.oldOW = ow;
			
			this.editFileName.setText(this.oldName);
			this.editBusSize.setText(Integer.toString(this.oldBusSize));
			this.editAddressSize.setText(Integer.toString(this.oldAddressSize));
			this.editAA.setText(Double.toString(this.oldAA));
			this.editACS.setText(Double.toString(this.oldACS));
			this.editCLZ.setText(Double.toString(this.oldCLZ));
			this.editOE.setText(Double.toString(this.oldOE));
			this.editOLZ.setText(Double.toString(this.oldOLZ));
			this.editCHZ.setText(Double.toString(this.oldCHZ));
			this.editOHZ.setText(Double.toString(this.oldOHZ));
			this.editOH.setText(Double.toString(this.oldOH));
			this.editAW.setText(Double.toString(this.oldAW));
			this.editAS.setText(Double.toString(this.oldAS));
			this.editWP.setText(Double.toString(this.oldWP));
			this.editWR.setText(Double.toString(this.oldWR));
			this.editWHZ.setText(Double.toString(this.oldWHZ));
			this.editDW.setText(Double.toString(this.oldDW));
			this.editDH.setText(Double.toString(this.oldDH));
			this.editOW.setText(Double.toString(this.oldOW));
			
			this.browse.addActionListener(this);
			this.editFileName.addActionListener(this);
			this.editBusSize.addActionListener(this);
			this.editAddressSize.addActionListener(this);
			this.editAA.addActionListener(this);
			this.editACS.addActionListener(this);
			this.editCLZ.addActionListener(this);
			this.editOE.addActionListener(this);
			this.editOLZ.addActionListener(this);
			this.editCHZ.addActionListener(this);
			this.editOHZ.addActionListener(this);
			this.editOH.addActionListener(this);
			this.editAW.addActionListener(this);
			this.editAS.addActionListener(this);
			this.editWP.addActionListener(this);
			this.editWR.addActionListener(this);
			this.editWHZ.addActionListener(this);
			this.editDW.addActionListener(this);
			this.editDH.addActionListener(this);
			this.editOW.addActionListener(this);
			
			this.editFileName.addFocusListener(this);
			this.editBusSize.addFocusListener(this);
			this.editAddressSize.addFocusListener(this);
			this.editAA.addFocusListener(this);
			this.editACS.addFocusListener(this);
			this.editCLZ.addFocusListener(this);
			this.editOE.addFocusListener(this);
			this.editOLZ.addFocusListener(this);
			this.editCHZ.addFocusListener(this);
			this.editOHZ.addFocusListener(this);
			this.editOH.addFocusListener(this);
			this.editAW.addFocusListener(this);
			this.editAS.addFocusListener(this);
			this.editWP.addFocusListener(this);
			this.editWR.addFocusListener(this);
			this.editWHZ.addFocusListener(this);
			this.editDW.addFocusListener(this);
			this.editDH.addFocusListener(this);
			this.editOW.addFocusListener(this);
			
			// content
			Panel big = new Panel(new BorderLayout(0, 15));
			
			Panel p = new Panel(new BorderLayout());
			p.add(this.content, BorderLayout.WEST);
			p.add(new SimSeparator(), BorderLayout.CENTER);
			big.add(p, BorderLayout.NORTH);
			
			p = new Panel(new GridBagLayout());
			
			GridBagConstraints c = new GridBagConstraints();
			c.gridy = 0;
			c.gridwidth = 1;
			c.gridheight = 1;
			c.anchor = GridBagConstraints.WEST;
			c.weighty = 0;
			
			c.fill = GridBagConstraints.HORIZONTAL;
			c.weightx = 1;
			c.gridx = 0;
			
			p.add(this.editFileName, c);
			
			c.fill = GridBagConstraints.NONE;
			c.weightx = 0;
			c.gridx = 1;
			c.insets = new Insets(0, 10, 0, 0);
			
			p.add(this.browse, c);
			big.add(p, BorderLayout.CENTER);
			
			c.gridx = 0;
			c.insets = new Insets(0, 0, 0, 0);
			c.weightx = 1;
			c.fill = GridBagConstraints.HORIZONTAL;
			
			this.add(big, c);
			
			// bus size
			big = new Panel(new BorderLayout(0, 15));
			
			p = new Panel(new BorderLayout());
			p.add(this.busSize, BorderLayout.WEST);
			p.add(new SimSeparator(), BorderLayout.CENTER);
			big.add(p, BorderLayout.NORTH);
			
			p = new Panel(new GridBagLayout());
			
			Panel p2 = new Panel(new FlowLayout(FlowLayout.LEFT, 0, 0));
			p2.add(new Label("Data"));
			p2.add(this.editBusSize);
			
			c.fill = GridBagConstraints.NONE;
			p.add(p2, c);
			
			p2 = new Panel(new FlowLayout(FlowLayout.RIGHT, 0, 0));
			p2.add(new Label("Address"));
			p2.add(this.editAddressSize);
			
			c.anchor = GridBagConstraints.EAST;
			c.gridx = 1;
			p.add(p2, c);
			
			big.add(p, BorderLayout.CENTER);
			
			c.gridx = 0;
			c.gridy = 1;
			c.insets = new Insets(15, 0, 15, 0);
			c.fill = GridBagConstraints.HORIZONTAL;
			this.add(big, c);
			
			// simulaion
			big = new Panel(new BorderLayout(0, 15));
			
			p = new Panel(new BorderLayout());
			p.add(this.delays, BorderLayout.WEST);
			p.add(new SimSeparator(), BorderLayout.CENTER);
			big.add(p, BorderLayout.NORTH);
			
			p = new Panel(new GridBagLayout());
			
			c.insets = new Insets(2, 5, 2, 0);
			
			c.gridy = 0;
			p.add(new Label("address access"), c);
			c.gridx = 1;
			p.add(this.editAA, c);
			
			c.gridy = 1;
			c.gridx = 0;
			p.add(new Label("chip select access"), c);
			c.gridx = 1;
			p.add(this.editACS, c);
			
			c.gridy = 2;
			c.gridx = 0;
			p.add(new Label("chip select to output"), c);
			c.gridx = 1;
			p.add(this.editCLZ, c);
			
			c.gridy = 3;
			c.gridx = 0;
			p.add(new Label("output ebable to output valid"), c);
			c.gridx = 1;
			p.add(this.editOE, c);
			
			c.gridy = 4;
			c.gridx = 0;
			p.add(new Label("output enable to output"), c);
			c.gridx = 1;
			p.add(this.editOLZ, c);
			
			c.gridy = 5;
			c.gridx = 0;
			p.add(new Label("chip deselection to output"), c);
			c.gridx = 1;
			p.add(this.editCHZ, c);
			
			c.gridy = 6;
			c.gridx = 0;
			p.add(new Label("chip disable to output"), c);
			c.gridx = 1;
			p.add(this.editOHZ, c);
			
			c.gridy = 7;
			c.gridx = 0;
			p.add(new Label("output hold from output change"), c);
			c.gridx = 1;
			p.add(this.editOH, c);
			
			c.gridy = 8;
			c.gridx = 0;
			p.add(new Label("address valid to end of write"), c);
			c.gridx = 1;
			p.add(this.editAW, c);
			
			c.gridy = 9;
			c.gridx = 0;
			p.add(new Label("address set up"), c);
			c.gridx = 1;
			p.add(this.editAS, c);
			
			c.gridy = 10;
			c.gridx = 0;
			p.add(new Label("write pulse width"), c);
			c.gridx = 1;
			p.add(this.editWP, c);
			
			c.gridy = 11;
			c.gridx = 0;
			p.add(new Label("write recovery"), c);
			c.gridx = 1;
			p.add(this.editWR, c);
			
			c.gridy = 12;
			c.gridx = 0;
			p.add(new Label("write to output"), c);
			c.gridx = 1;
			p.add(this.editWHZ, c);
			
			c.gridy = 13;
			c.gridx = 0;
			p.add(new Label("data to write pulse overlap"), c);
			c.gridx = 1;
			p.add(this.editDW, c);
			
			c.gridy = 14;
			c.gridx = 0;
			p.add(new Label("data hold from write"), c);
			c.gridx = 1;
			p.add(this.editDH, c);
			
			c.gridy = 15;
			c.gridx = 0;
			p.add(new Label("output active from end of write"), c);
			c.gridx = 1;
			p.add(this.editOW, c);
			
			this.scroller.getVAdjustable().setBlockIncrement(50);
			this.scroller.getVAdjustable().setUnitIncrement(25);
			
			p2 = new Panel(new BulletinLayout());
			p2.add(p);
			this.scroller.add(p2);
			big.add(this.scroller, BorderLayout.CENTER);
			
			c.gridx = 0;
			c.gridy = 2;
			c.insets = new Insets(0, 0, 0, 0);
			this.add(big, c);
		}
		
		public void addNotify()
		{
			super.addNotify();
			this.setSize(290, this.editBusSize.getPreferredSize().height * 2 + this.delays.getPreferredSize().height * 3 + 175);
			
			this.scroller.validate();
		}
		
		public void actionPerformed(ActionEvent e)
		{
			Component source = (Component)e.getSource();
			
			if(source == this.editFileName)
				this.getFileName();
			else if(source == this.editBusSize)
				this.getBusSize();
			else if(source == this.editAddressSize)
				this.getAddressSize();
			else if(source == this.editAA)
				this.getAA();
			else if(source == this.editACS)
				this.getACS();
			else if(source == this.editCLZ)
				this.getCLZ();
			else if(source == this.editOE)
				this.getOE();
			else if(source == this.editOLZ)
				this.getOLZ();
			else if(source == this.editCHZ)
				this.getCHZ();
			else if(source == this.editOHZ)
				this.getOHZ();
			else if(source == this.editOH)
				this.getOH();
			else if(source == this.editAW)
				this.getAW();
			else if(source == this.editAS)
				this.getAS();
			else if(source == this.editWP)
				this.getWP();
			else if(source == this.editWR)
				this.getWR();
			else if(source == this.editWHZ)
				this.getWHZ();
			else if(source == this.editDW)
				this.getDH();
			else if(source == this.editDH)
				this.getDH();
			else if(source == this.editOW)
				this.getOW();
			else if(source == this.browse)
			{
				SaveLoadShortcut.FILEDIALOG.setTitle("Open");
				SaveLoadShortcut.FILEDIALOG.setMode(FileDialog.LOAD);
				SaveLoadShortcut.FILEDIALOG.setFile("*.mem");
				SaveLoadShortcut.FILEDIALOG.show();
				
				String inFile = SaveLoadShortcut.FILEDIALOG.getFile();
					
				if(inFile != null)
				{
					this.oldName = SaveLoadShortcut.FILEDIALOG.getDirectory() + inFile;
					this.editFileName.setText(this.oldName);
				}
			}
		}
		
		public void focusGained(FocusEvent e)
		{
		}
		
		public void focusLost(FocusEvent e)
		{
			TextField source = (TextField)e.getSource();
			
			if(source == this.editFileName)
				this.getFileName();
			else if(source == this.editBusSize)
				this.getBusSize();
			else if(source == this.editAddressSize)
				this.getAddressSize();
			else if(source == this.editAA)
				this.getAA();
			else if(source == this.editACS)
				this.getACS();
			else if(source == this.editCLZ)
				this.getCLZ();
			else if(source == this.editOE)
				this.getOE();
			else if(source == this.editOLZ)
				this.getOLZ();
			else if(source == this.editCHZ)
				this.getCHZ();
			else if(source == this.editOHZ)
				this.getOHZ();
			else if(source == this.editOH)
				this.getOH();
			else if(source == this.editAW)
				this.getAW();
			else if(source == this.editAS)
				this.getAS();
			else if(source == this.editWP)
				this.getWP();
			else if(source == this.editWR)
				this.getWR();
			else if(source == this.editWHZ)
				this.getWHZ();
			else if(source == this.editDW)
				this.getDH();
			else if(source == this.editDH)
				this.getDH();
			else if(source == this.editOW)
				this.getOW();
			
			source.setText(source.getText());
		}
		
		public int getBusSize()
		{
			int newBus;
			
			try
			{
				newBus = Integer.valueOf(this.editBusSize.getText()).intValue();
				
				if((newBus > 1) && (newBus <= 32))
					this.oldBusSize = newBus;
				else
					this.editBusSize.setText(Integer.toString(this.oldBusSize));
			}
			catch(NumberFormatException nfe)
			{
				this.editBusSize.setText(Integer.toString(this.oldBusSize));
			}
			
			return this.oldBusSize;
		}
		
		public int getAddressSize()
		{
			int newAddress;
			
			try
			{
				newAddress = Integer.valueOf(this.editAddressSize.getText()).intValue();
				
				if((newAddress > 1) && (newAddress <= 8))
					this.oldAddressSize = newAddress;
				else
					this.editAddressSize.setText(Integer.toString(this.oldAddressSize));
			}
			catch(NumberFormatException nfe)
			{
				this.editAddressSize.setText(Integer.toString(this.oldAddressSize));
			}
			
			return this.oldAddressSize;
		}
		
		public String getFileName()
		{
			String newName = this.editFileName.getText();
			
			if(this.browse.isEnabled())
			{
				try
				{
					FileWriter f = new FileWriter(newName, true);
					f.close();
					
					this.oldName = newName;
				}
				catch(IOException ex)
				{
					this.editFileName.setText(this.oldName);
				}
			}
			
			return this.oldName;
		}
		
		public double getAA()
		{
			double newValue;
			
			try
			{
				newValue = Double.valueOf(this.editAA.getText()).doubleValue();
				
				if(newValue >= 0)
					this.oldAA = newValue;
				else
					this.editAA.setText(Double.toString(this.oldAA));
			}
			catch(NumberFormatException nfe)
			{
				this.editAA.setText(Double.toString(this.oldAA));
			}
			
			return this.oldAA;
		}
		
		public double getACS()
		{
			double newValue;
			
			try
			{
				newValue = Double.valueOf(this.editACS.getText()).doubleValue();
				
				if((newValue >= 0) && (newValue >= this.oldCLZ))
					this.oldACS = newValue;
				else
					this.editACS.setText(Double.toString(this.oldACS));
			}
			catch(NumberFormatException nfe)
			{
				this.editACS.setText(Double.toString(this.oldACS));
			}
			
			return this.oldACS;
		}
		
		public double getCLZ()
		{
			double newValue;
			
			try
			{
				newValue = Double.valueOf(this.editCLZ.getText()).doubleValue();
				
				if((newValue >= 0) && (newValue <= this.oldACS))
					this.oldCLZ = newValue;
				else
					this.editCLZ.setText(Double.toString(this.oldCLZ));
			}
			catch(NumberFormatException nfe)
			{
				this.editCLZ.setText(Double.toString(this.oldCLZ));
			}
			
			return this.oldCLZ;
		}
		
		public double getOE()
		{
			double newValue;
			
			try
			{
				newValue = Double.valueOf(this.editOE.getText()).doubleValue();
				
				if((newValue >= 0) && (newValue >= this.oldOLZ))
					this.oldOE = newValue;
				else
					this.editOE.setText(Double.toString(this.oldOE));
			}
			catch(NumberFormatException nfe)
			{
				this.editOE.setText(Double.toString(this.oldOE));
			}
			
			return this.oldOE;
		}
		
		public double getOLZ()
		{
			double newValue;
			
			try
			{
				newValue = Double.valueOf(this.editOLZ.getText()).doubleValue();
				
				if((newValue >= 0) && (newValue <= this.oldOE))
					this.oldOLZ = newValue;
				else
					this.editOLZ.setText(Double.toString(this.oldOLZ));
			}
			catch(NumberFormatException nfe)
			{
				this.editOLZ.setText(Double.toString(this.oldOLZ));
			}
			
			return this.oldOLZ;
		}
		
		public double getCHZ()
		{
			double newValue;
			
			try
			{
				newValue = Double.valueOf(this.editCHZ.getText()).doubleValue();
				
				if(newValue >= 0)
					this.oldCHZ = newValue;
				else
					this.editCHZ.setText(Double.toString(this.oldCHZ));
			}
			catch(NumberFormatException nfe)
			{
				this.editCHZ.setText(Double.toString(this.oldCHZ));
			}
			
			return this.oldCHZ;
		}
		
		public double getOHZ()
		{
			double newValue;
			
			try
			{
				newValue = Double.valueOf(this.editOHZ.getText()).doubleValue();
				
				if(newValue >= 0)
					this.oldOHZ = newValue;
				else
					this.editOHZ.setText(Double.toString(this.oldOHZ));
			}
			catch(NumberFormatException nfe)
			{
				this.editOHZ.setText(Double.toString(this.oldOHZ));
			}
			
			return this.oldOHZ;
		}
		
		public double getOH()
		{
			double newValue;
			
			try
			{
				newValue = Double.valueOf(this.editOH.getText()).doubleValue();
				
				if(newValue >= 0)
					this.oldOH = newValue;
				else
					this.editOH.setText(Double.toString(this.oldOH));
			}
			catch(NumberFormatException nfe)
			{
				this.editOH.setText(Double.toString(this.oldOH));
			}
			
			return this.oldOH;
		}
		
		public double getAW()
		{
			double newValue;
			
			try
			{
				newValue = Double.valueOf(this.editAW.getText()).doubleValue();
				
				if((newValue >= 0) && (newValue <= this.oldAS + this.oldWP) && (newValue >= this.oldAS))
					this.oldAW = newValue;
				else
					this.editAW.setText(Double.toString(this.oldAW));
			}
			catch(NumberFormatException nfe)
			{
				this.editAW.setText(Double.toString(this.oldAW));
			}
			
			return this.oldAW;
		}
		
		public double getAS()
		{
			double newValue;
			
			try
			{
				newValue = Double.valueOf(this.editAS.getText()).doubleValue();
				
				if((newValue >= 0) && (newValue <= this.oldAW) && (newValue <= this.oldAW - this.oldWP))
					this.oldAS = newValue;
				else
					this.editAS.setText(Double.toString(this.oldAS));
			}
			catch(NumberFormatException nfe)
			{
				this.editAS.setText(Double.toString(this.oldAS));
			}
			
			return this.oldAS;
		}
		
		public double getWP()
		{
			double newValue;
			
			try
			{
				newValue = Double.valueOf(this.editWP.getText()).doubleValue();
				
				if((newValue >= 0) && (newValue >= this.oldAW - this.oldAS) && (newValue >= this.oldWHZ + this.oldDW))
					this.oldWP = newValue;
				else
					this.editWP.setText(Double.toString(this.oldWP));
			}
			catch(NumberFormatException nfe)
			{
				this.editWP.setText(Double.toString(this.oldWP));
			}
			
			return this.oldWP;
		}
		
		public double getWR()
		{
			double newValue;
			
			try
			{
				newValue = Double.valueOf(this.editWR.getText()).doubleValue();
				
				if((newValue >= 0) && (newValue <= this.oldOW) && (newValue >= this.oldDH))
					this.oldWR = newValue;
				else
					this.editWR.setText(Double.toString(this.oldWR));
			}
			catch(NumberFormatException nfe)
			{
				this.editWR.setText(Double.toString(this.oldWR));
			}
			
			return this.oldWR;
		}
		
		public double getWHZ()
		{
			double newValue;
			
			try
			{
				newValue = Double.valueOf(this.editWHZ.getText()).doubleValue();
				
				if((newValue >= 0) && (newValue <= this.oldWP - this.oldDW))
					this.oldWHZ = newValue;
				else
					this.editWHZ.setText(Double.toString(this.oldWHZ));
			}
			catch(NumberFormatException nfe)
			{
				this.editWHZ.setText(Double.toString(this.oldWHZ));
			}
			
			return this.oldWHZ;
		}
		
		public double getDW()
		{
			double newValue;
			
			try
			{
				newValue = Double.valueOf(this.editDW.getText()).doubleValue();
				
				if((newValue >= 0) && (newValue <= this.oldWP - this.oldWHZ))
					this.oldDW = newValue;
				else
					this.editDW.setText(Double.toString(this.oldDW));
			}
			catch(NumberFormatException nfe)
			{
				this.editDW.setText(Double.toString(this.oldDW));
			}
			
			return this.oldDW;
		}
		
		public double getDH()
		{
			double newValue;
			
			try
			{
				newValue = Double.valueOf(this.editDH.getText()).doubleValue();
				
				if((newValue >= 0) && (newValue < this.oldWR))
					this.oldDH = newValue;
				else
					this.editDH.setText(Double.toString(this.oldDH));
			}
			catch(NumberFormatException nfe)
			{
				this.editDH.setText(Double.toString(this.oldDH));
			}
			
			return this.oldDH;
		}
		
		public double getOW()
		{
			double newValue;
			
			try
			{
				newValue = Double.valueOf(this.editOW.getText()).doubleValue();
				
				if((newValue >= 0) && (newValue >= this.oldWR))
					this.oldOW = newValue;
				else
					this.editOW.setText(Double.toString(this.oldOW));
			}
			catch(NumberFormatException nfe)
			{
				this.editOW.setText(Double.toString(this.oldOW));
			}
			
			return this.oldOW;
		}
		
		public Dimension getPreferredSize()
		{
			return this.getSize();
		}
		
		public Dimension getMinimumSize()
		{
			return this.getSize();
		}
	
		public Dimension getMaximumSize()
		{
			return this.getSize();
		}
	}
}