package sim.lib.others;

import java.awt.*;
import java.awt.geom.AffineTransform;
import java.io.*;
//import java.nio.file.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import javax.swing.*;

import sim.*;
import sim.lib.*;
import sim.engine.*;
import sim.lib.outputs.BusLed;
import sim.lib.wires.Junction;
import sim.lib.wires.SplitterModule;
import sim.lib.wires.Wire;

public class Module extends WrapperPainted implements EngineModule {
	/* ==================================================================
	 Creation Part
	 ================================================================= */

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

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

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

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

	public String getBubbleHelp() {
		return "Module";
	}
	/* ==================================================================
	 GUI part
	 ================================================================= */
	private String value = null;
	private int busSize;
	private int valueLenght;
	private String modpath = null;
	private int numPin;
	private boolean pin99 = false;
	private String[] labels = new String[100];
	private String modLabel = null;
	public static String lastPath;
	//private static String errorPath;
	private static boolean loadError;
	private int[] busSizes = new int[100];
	private static loadedModule[] loaded = new loadedModule[50];
	private String regName;
	private Object regOut = null;
	private String initRegName; //for setting intial value of a register
	private String initRegValue;
	private String[] regList = new String[50];
	private boolean colour = false;
	private int ModID = -1;
	public static int nextID = 0;
	public static Map<String,Integer> CustomIDs = new HashMap<String,Integer>();
	private boolean incremental;
	private int startId;
	private int setId;

	public Module() {
		super();

		this.setBusSize(8);

		//this.setPath(lastPath);
	}

	public Module getCopy() {
		Module result = new Module();
		result.setPath(lastPath);
		result.setRName(this.regName);
		result.defaultLabel();

		//result.setBusSize(this.busSize);

		return result;
	}

	public void defaultLabel() {
		if (this.modpath != null) {
			String parts[] = this.modpath.split("\\\\");
			String name = parts[parts.length - 1];
			name = name.substring(0, name.length() - 4);
			this.modLabel = name;
		}
	}

	public String getLabel() {
		return this.modLabel;
	}

	public void setLabel(String label) {
		this.modLabel = label;
	}
	
	public void setModID(int id){
		this.ModID = id;
	}

	public void setRName(String reg) {
		this.regName = reg;
	}

	public void setRegOut(Object r) {
		this.regOut = r;
	}
	
	public int getModID(int id){
		return this.ModID;
	}

	public String getPath() {
		return this.modpath;
	}

	public void setPath(String file) {
		this.modpath = file;

		//LOAD numPin = number of pin components from file
		//get names for pins into string array
		this.numPin = 0;
		Grid g = new Grid();
		String[] basics, specifics;
		String className, componentName, readIn;
		BufferedReader inStream;
		Wrapper created;
		int z = 0;

		try {
			inStream = new BufferedReader(new FileReader(file));
			readIn = SaveLoadShortcut.GUI_FILE_LINK.extractParameter(inStream);
			SaveLoadShortcut.GUI_FILE_LINK.readBlank(inStream);
			SaveLoadShortcut.GUI_FILE_LINK.extractParameters(g.getNumberOfParameters(), inStream);
			SaveLoadShortcut.GUI_FILE_LINK.readBlank(inStream);
			int size = Integer.valueOf(SaveLoadShortcut.GUI_FILE_LINK.extractParameter(inStream)).intValue();
			for (int index = 0; index < size; index++) {
				SaveLoadShortcut.GUI_FILE_LINK.readBlank(inStream);
				className = SaveLoadShortcut.GUI_FILE_LINK.extractParameter(inStream);
				componentName = SaveLoadShortcut.GUI_FILE_LINK.extractParameter(inStream);
				created = SaveLoadShortcut.GUI_FILE_LINK.getWrapper(className);

				basics = SaveLoadShortcut.GUI_FILE_LINK.extractParameters(created.getNumberOfBasicParameters(), inStream);
				specifics = SaveLoadShortcut.GUI_FILE_LINK.extractParameters(created.getNumberOfSpecificParameters(), inStream);
				if (className.equals("sim.lib.outputs.Pin")) {
					if(Integer.valueOf(specifics[1]) == 99)
						this.pin99 = true;
					else
						this.numPin++;
					this.busSizes[Integer.valueOf(specifics[1]) - 1] = Integer.valueOf(specifics[0]); //get bus size for each pin
					this.labels[Integer.valueOf(specifics[1]) - 1] = specifics[2]; //get label string for each pin

				} else if (className.equals("sim.lib.memory.Register") || className.equals("sim.lib.memory.ShiftRegister")) {
					this.regList[z] = specifics[2];
					z++;
				}
			}
			lastPath = file;

		} catch (Exception e) {
			if (!loadError) {
				JOptionPane.showMessageDialog(null, "Error loading module file, please correct file paths in Control Center", "ERROR", JOptionPane.ERROR_MESSAGE);
				loadError = true;
			}
		}


	}

	public String[] getRegList() {
		return this.regList;
	}

	public void initializeGridSize() {
		this.setGridSize(6, 7);
	}

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

		String max = Integer.toHexString((int) Math.pow(2, this.busSize) - 1).toUpperCase();
		FontMetrics fm = this.getFontMetrics(new Font(Wrapper.FONT_NAME, Font.PLAIN, 3 * Grid.SIZE / 4));

		//this.setGridSize(fm.stringWidth(max) / Grid.SIZE + 4, 4);
		//this.setGridSize(6,6);
		this.valueLenght = max.length();
	}

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

	public void paintValue(Graphics g) {
		if (this.isVisible()) {
			int gridGap = CentralPanel.ACTIVE_GRID.getCurrentGridGap();
			int increment = gridGap / 4;
			int offset = 2 * gridGap;
			String val = "";
			if (this.regOut != null) {
				if (this.regOut instanceof sim.lib.memory.Register) {
					val = ((sim.lib.memory.Register)this.regOut).getValue();
				}else if (this.regOut instanceof sim.lib.memory.ShiftRegister) {
					val = ((sim.lib.memory.ShiftRegister)this.regOut).getValue();
				}
				g.setFont(new Font(Wrapper.FONT_NAME, Font.BOLD, gridGap));
			}
			if (this.colour) {
				int col = Integer.decode(val);
				g.setColor(new Color(col,col,col));
				g.fillRect(2 * gridGap + increment / 2, 2 * gridGap + increment / 2, offset - increment+1, offset - increment+1);
			}else{
				g.drawString(val, 2 * gridGap + increment + 1, gridGap * 2 + 5 * increment);
			}
		}
	}

	public void paint(Graphics g) {

		// draw if visible
		if (this.isVisible()) {
			int gridGap = CentralPanel.ACTIVE_GRID.getCurrentGridGap();
			int increment = gridGap / 4;

			//g.setColor(this.brush);

			int offset = 2 * gridGap;
			g.setColor(Color.WHITE);
			g.fillRect(2 * gridGap + increment / 2, 2 * gridGap + increment / 2, offset - increment, offset - increment);
			g.setColor(this.brush);

			g.drawRect(2 * gridGap, 2 * gridGap, offset, offset);
			g.drawRect(2 * gridGap + increment / 2, 2 * gridGap + increment / 2, offset - increment, offset - increment);

			//g.drawRect(gridGap + gridGap / 5, 2 * increment + gridGap / 5, offset - 2*gridGap/5, offset -2*gridGap/5);

			int start = 3 * gridGap;
			int end = 5 * gridGap;
			offset = 2 * gridGap;
			g.setFont(new Font(Wrapper.FONT_NAME, Font.BOLD, gridGap * 2 / 3));
			Font f = new Font(Wrapper.FONT_NAME, Font.PLAIN, 3 * increment);
			String name;
			if (modLabel == null) {
				String parts[] = this.modpath.split("\\\\");
				name = parts[parts.length - 1];
				name = name.substring(0, name.length() - 4);
				this.modLabel = name;
			} else {
				name = modLabel;
			}
			int col = 0;
			if (this.regOut != null) {
				if (this.regOut instanceof sim.lib.memory.Register) {
					name = ((sim.lib.memory.Register)this.regOut).getValue();
					if(name.equals("--"))
						col = 0;
					else
						col = Integer.decode("0x" + name);
				}else if (this.regOut instanceof sim.lib.memory.ShiftRegister) {
					name = ((sim.lib.memory.ShiftRegister)this.regOut).getValue();
					//col = ((sim.lib.memory.ShiftRegister)this.regOut).getHex();
					if(name.equals("--"))
						col = 0;
					else
						col = Integer.decode("0x" + name);
				}
				if (this.colour) {
					/*System.out.println(name);
					int col = Integer.decode("0x" + name);
					System.out.println(col + "- " + name);*/
					//int col = ((sim.lib.memory.Register)this.regOut).getHex();
					//System.out.println(col);
					g.setColor(new Color(col,col,col));
					g.fillRect(2 * gridGap + increment / 2, 2 * gridGap + increment / 2, offset-increment, offset-increment);
					name = "";
					g.setColor(Color.BLACK);
				}else{
					g.setFont(new Font(Wrapper.FONT_NAME, Font.BOLD, gridGap));
				}
			}
			g.drawString(name, 2 * gridGap + increment + 1, gridGap * 2 + 5 * increment);
			//g.drawString(this.modpath, 0,0);

			offset = offset + gridGap;

			//**********Draw ports based on number of pins in input file**********
			g.setFont(new Font(Wrapper.FONT_NAME, Font.PLAIN, gridGap * 2 / 3));
			if(this.pin99){
				g.drawLine(4 *gridGap, 2 * gridGap, 5 * gridGap, 1 * gridGap); //portF (DIAGONAL)
			}
			if (this.numPin > 0) {
				g.drawString(this.labels[0].substring(0, Math.min(5, this.labels[0].length())), gridGap / 8, gridGap * 5 / 2 + increment); //GET PIN NAMES FROM INPUT FILE
				g.fillRect(0, 3 * gridGap - 1, 2 * gridGap, 3); //portA (LEFT)
			}
			if (this.numPin > 1) {
				AffineTransform tmp = f.getTransform();
				AffineTransform at = new AffineTransform();
				at.rotate(-90 * java.lang.Math.PI / 180);
				Font tf = f.deriveFont(at);
				g.setFont(tf.deriveFont((float) (gridGap * 2 / 3)));
				g.drawString(this.labels[1].substring(0, Math.min(5, this.labels[1].length())), gridGap * 11 / 4, gridGap * 2 - gridGap / 8); //TODO - ACCOUNT FOR GAPS IN PIN INDEXES

				g.fillRect(3 * gridGap - 1, 0, 3, 2 * gridGap); //portB (TOP)
				/*for(int i = 0; i < this.labels[1].length(); i++){
				 if (i > 10){
				 break;
				 }
				 g.drawString(this.labels[1].charAt(i)+"", gridGap*3/2, gridGap*2/3+i*gridGap/2);
				 }*/
			}
			if (this.numPin > 2) {
				g.setFont(new Font(Wrapper.FONT_NAME, Font.PLAIN, gridGap * 2 / 3));
				g.drawString(this.labels[2].substring(0, Math.min(5, this.labels[2].length())), gridGap * 4 + gridGap / 8, gridGap * 5 / 2 + increment);
				g.fillRect(4 * gridGap, 3 * gridGap - 1, 2 * gridGap, 3); //portC (RIGHT)
			}
			if (this.numPin > 3) {
				AffineTransform tmp = f.getTransform();
				AffineTransform at = new AffineTransform();
				at.rotate(-90 * java.lang.Math.PI / 180);
				Font tf = f.deriveFont(at);
				g.setFont(tf.deriveFont((float) (gridGap * 2 / 3)));
				g.drawString(this.labels[3].substring(0, Math.min(5, this.labels[3].length())), gridGap * 7 / 2 + gridGap / 8, gridGap * 6 - gridGap / 8);

				g.fillRect(3 * gridGap - 1, 4 * gridGap, 3, 2 * gridGap); //portD (BOTTOM)
			}

			if (this.numPin > 4) {
				g.drawLine(gridGap, 5 * gridGap, 2 * gridGap, 4 * gridGap); //portE (DIAGONAL)
				g.drawLine(gridGap, 5 * gridGap - 1, 2 * gridGap, 4 * gridGap - 1); //portE (DIAGONAL)
				g.drawLine(gridGap, 5 * gridGap + 1, 2 * gridGap, 4 * gridGap + 1); //portE (DIAGONAL)
			}

		}
	}
	/* ==================================================================
	 Maintanance Part
	 ================================================================= */
	private Junction portA = null; //IN //LEFT
	private Junction portB = null; //TOP
	private Junction portC = null; //OUT //RIGHT
	private Junction portD = null; //BOTTOM
	private Junction portE = null; //DIAGONAL LEFTBOTTOM OUT (Any other bits combined into single bus - except pin 99 (special))
	private Junction portF = null; //DIAGONAL TOPRIGHT OUT single special bit
	//private Junction portO = null; //LCD OUT

	public boolean canDrop() {
		boolean result = false;
		if (this.numPin > 0) {
			result = Wrapper.canDropJuncion(this.gridLocation.x, this.gridLocation.y + 3, this.busSizes[0]); //PORTA
		}
		if (this.numPin > 1) {
			result = result && Wrapper.canDropJuncion(this.gridLocation.x + 3, this.gridLocation.y, this.busSizes[1]); //PORTB
		}
		if (this.numPin > 2) {
			result = result && Wrapper.canDropJuncion(this.gridLocation.x + 6, this.gridLocation.y + 3, this.busSizes[2]); //PORTC
		}
		if (this.numPin > 3) {
			result = result && Wrapper.canDropJuncion(this.gridLocation.x + 3, this.gridLocation.y + 6, this.busSizes[3]); //PORTD
		}
		if (this.numPin > 4) {
			int totalbus = 0;
			for (int i = 4; i < this.busSizes.length - 10; i++) {
				totalbus = totalbus + busSizes[i];
			}
			result = result && Wrapper.canDropJuncion(this.gridLocation.x + 1, this.gridLocation.y + 5, totalbus); //PORTE
		}
		if(this.pin99){
			result = result && Wrapper.canDropJuncion(this.gridLocation.x + 5, this.gridLocation.y + 1, 1); //PORTF
		}
		return result;
	}

	public void droped() {
		if (this.numPin > 0) {
			this.portA = Wrapper.setPinAt(this.gridLocation.x, this.gridLocation.y + 3, this.busSizes[0]);
		}
		if (this.numPin > 1) {
			this.portB = Wrapper.setPinAt(this.gridLocation.x + 3, this.gridLocation.y, this.busSizes[1]);
		}
		if (this.numPin > 2) {
			this.portC = Wrapper.setPinAt(this.gridLocation.x + 6, this.gridLocation.y + 3, this.busSizes[2]);
		}
		if (this.numPin > 3) {
			this.portD = Wrapper.setPinAt(this.gridLocation.x + 3, this.gridLocation.y + 6, this.busSizes[3]);
		}
		if (this.numPin > 4) {
			int totalbus = 0;
			for (int i = 4; i < this.busSizes.length - 5; i++) {
				totalbus = totalbus + busSizes[i];
			}
			this.portE = Wrapper.setPinAt(this.gridLocation.x + 1, this.gridLocation.y + 5, totalbus);
		}
		if(this.pin99){
			this.portF = Wrapper.setPinAt(this.gridLocation.x + 5, this.gridLocation.y + 1, 1); //PORTF
		}

		this.changeColor(Color.black);
	}

	public void selected() {
		if (this.numPin > 0) {
			this.portA.removePin();
		}
		if (this.numPin > 1) {
			this.portB.removePin();
		}
		if (this.numPin > 2) {
			this.portC.removePin();
		}
		if (this.numPin > 3) {
			this.portD.removePin();
		}
		if (this.numPin > 4) {
			this.portE.removePin();
		}
		if (this.pin99) {
			this.portF.removePin();
		}

		this.changeColor(Color.green);
	}

	public void checkAfterSelected() {
		if (this.numPin > 0) {
			Wrapper.checkPin(this.portA);
		}
		if (this.numPin > 1) {
			Wrapper.checkPin(this.portB);
		}
		if (this.numPin > 2) {
			Wrapper.checkPin(this.portD);
		}
		if (this.numPin > 3) {
			Wrapper.checkPin(this.portC);
		}
		if (this.numPin > 4) {
			Wrapper.checkPin(this.portE);
		}
		if (this.pin99) {
			Wrapper.checkPin(this.portF);
		}
	}
	/* ==================================================================
	 Simulation part
	 ================================================================= */

	public void evaluateOutput(double currentTime, Data[] currentInputs, EnginePeer peer) {
		CentralPanel.ACTIVE_GRID.paintComponent(this);
	}

	public void createEnginePeer(EnginePeerList epl) {
	}

	private Object[] loadModule(String fname) { //load components from referenced module
		String inFile = fname;
		Reader inStream;

		MainWindow.CENTRAL_PANEL.createGrid("");
		CentralPanel.ACTIVE_GRID = new Grid();

		try {
			MainWindow.CENTRAL_PANEL.createGrid("MODULE");
			MainWindow.CENTRAL_PANEL.setVisible(false);
			inStream = new BufferedReader(new FileReader(inFile));
			SaveLoadShortcut.GUI_FILE_LINK.loadMod(inStream, CentralPanel.ACTIVE_GRID);
			//loaded[next] = new loadedModule(fname,g,SaveLoadShortcut.GUI_FILE_LINK.getComp(inStream, CentralPanel.ACTIVE_GRID));
			inStream.close();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SimException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		//Get EnginePeers from file
		//insert into input EnginePeerList
		//connect relevant nodes

		Grid g = CentralPanel.ACTIVE_GRID;

		//*******LOAD COMPONENTS FROM FILE******
		int loop;

		int wires = g.getNumberOfWires();
		int junctions = g.getNumberOfJunctions();
		int splitters = g.getNumberOfSplitters();
		int components = g.getNumberOfComponents();
		int total;

		NodeList tempnl = new NodeList();
		EnginePeerList tempepl = new EnginePeerList();

		for (loop = 0; loop < junctions; loop++) {
			((NodeModule) g.getComponent(loop)).createNode(tempnl);
		}

		total = junctions + wires + splitters;
		for (loop = junctions + wires; loop < total; loop++) {
			((SplitterModule) g.getComponent(loop)).mergeNodes(tempnl);
		}

		total = total + components;
		//MANAGE MODULE ID
		for (loop = junctions + wires + splitters; loop < total; loop++) {
			if (g.getComponent(loop) instanceof sim.lib.others.ModuleID) {
				if (((sim.lib.others.ModuleID)g.getComponent(loop)).getModID() == 0) { //0 - use standard incremental id
					this.ModID = nextID;
					nextID++;
					((sim.lib.others.ModuleID)g.getComponent(loop)).setModID(this.ModID);
				}else if (((sim.lib.others.ModuleID)g.getComponent(loop)).getModID() < 0){ //custom incremental mod id
					if (CustomIDs.get(this.modpath) != null){
						this.ModID = CustomIDs.get(this.modpath) + 1;
						
					}else{
						this.ModID = -((sim.lib.others.ModuleID)g.getComponent(loop)).getModID();
					}
					((sim.lib.others.ModuleID)g.getComponent(loop)).setModID(this.ModID);
					CustomIDs.put(this.modpath, this.ModID);
				}else{ //custom Manual ID
					this.ModID = ((sim.lib.others.ModuleID)g.getComponent(loop)).getModID(); 
				}
				
				
			}
			((EngineModule) g.getComponent(loop)).createEnginePeer(tempepl);
		}

		Object[] out = new Object[2];

		out[0] = tempepl;
		out[1] = tempnl;

		return out;
	}

	public void createEnginePeer(EnginePeerList epl, NodeList nl) {
		//ENGINE PEER FOR MODULE
		this.busSize = 8;

		//this.ModID = nextID;
		//nextID++;

		Object[] tmp = loadModule(this.modpath); //load EPL and NL from file
		EnginePeerList tempepl = (EnginePeerList) tmp[0];
		NodeList tempnl = (NodeList) tmp[1];
		int[] pinpos = new int[this.busSizes.length]; //array to hold current bit position of each pin

		for (Object o : tempepl) {
			EnginePeer ept = (EnginePeer) o;
			if (!ept.getParent().getClass().toString().equals("class sim.lib.outputs.Pin")) {
				for (int k = 0; k < ept.getInputPins().getSize(); k++) {
					for (int i = 0; i < ept.getInputPins().getItemAt(k).getConnection().getSize(); i++) {
						EnginePeer eptt = ept.getInputPins().getItemAt(k).getConnection().getItemAt(i);
						if (eptt.getParent().getClass().toString().equals("class sim.lib.outputs.Pin")) { //component connected to a pin
							int n = ((sim.lib.outputs.Pin) eptt.getParent()).getNumber();
							if(pinpos[n-1] >= eptt.getInputPins().size()){
								pinpos[n-1] = 0;
							}
							if (!ept.getInputPins().getItemAt(k).equals(eptt.getInputPins().getItemAt(pinpos[n - 1]))) { //find correct bit position of pin
								pinpos[n - 1] = 0;
								while (!ept.getInputPins().getItemAt(k).equals(eptt.getInputPins().getItemAt(pinpos[n - 1]))) {
									pinpos[n - 1]++;
								}
							}

							switch (n) //connect pins from loaded file to ports on module component
							{
								case 1:
									ept.setInputPin(k, this.portA.getNodes().getItemAt(pinpos[n - 1]));
									pinpos[n - 1]++;
									break;
								case 2:
									ept.setInputPin(k, this.portB.getNodes().getItemAt(pinpos[n - 1]));
									pinpos[n - 1]++;
									break;
								case 3:
									ept.setInputPin(k, this.portC.getNodes().getItemAt(pinpos[n - 1]));
									pinpos[n - 1]++;
									break;
								case 4:
									ept.setInputPin(k, this.portD.getNodes().getItemAt(pinpos[n - 1]));
									pinpos[n - 1]++;
									break;
								case 99:
									ept.setInputPin(k, this.portF.getNodes().getItemAt(pinpos[n - 1]));
									pinpos[n - 1]++;
									break;
								default:

									int base = 0;
									//n = n - 1;
									for (int j = 4; j <= (n - 2); j++) { //get correct starting bit position for portE
										base = base + this.busSizes[j];
									}
									int a = base + pinpos[n - 1];
									System.out.println(k + "," + a);
									ept.setInputPin(k, this.portE.getNodes().getItemAt(base + pinpos[n - 1]));
									pinpos[n - 1]++;
							}

							break;
						}
					}
				}
				Arrays.fill(pinpos, 0); //reset array to hold current bit position of each pin
				if (ept.getOutputPins() != null) {
					for (int k = 0; k < ept.getOutputPins().getSize(); k++) {
						for (int i = 0; i < ept.getOutputPins().getItemAt(k).getConnection().getSize(); i++) {
							EnginePeer eptt = ept.getOutputPins().getItemAt(k).getConnection().getItemAt(i);
							if (eptt.getParent().getClass().toString().equals("class sim.lib.outputs.Pin")) {
								int n = ((sim.lib.outputs.Pin) eptt.getParent()).getNumber();
								if(pinpos[n-1] >= eptt.getInputPins().getSize()){
									pinpos[n-1] = 0;
								}
								if (!ept.getOutputPins().getItemAt(k).equals(eptt.getInputPins().getItemAt(pinpos[n - 1]))) { //find correct bit position of pin
									pinpos[n - 1] = 0;
									while (!ept.getOutputPins().getItemAt(k).equals(eptt.getInputPins().getItemAt(pinpos[n - 1]))) {
										pinpos[n - 1]++;
									}
								}
								switch (n) {
									case 1:
										ept.setOutputPin(k, this.portA.getNodes().getItemAt(pinpos[n - 1]));
										pinpos[n - 1]++;
										break;
									case 2:
										ept.setOutputPin(k, this.portB.getNodes().getItemAt(pinpos[n - 1]));
										pinpos[n - 1]++;
										break;
									case 3:
										ept.setOutputPin(k, this.portC.getNodes().getItemAt(pinpos[n - 1]));
										pinpos[n - 1]++;
										break;
									case 4:
										ept.setOutputPin(k, this.portD.getNodes().getItemAt(pinpos[n - 1]));
										pinpos[n - 1]++;
										break;
									case 99:
										ept.setOutputPin(k, this.portF.getNodes().getItemAt(pinpos[n - 1]));
										pinpos[n - 1]++;
										break;	
									default:
										int base = 0;
										for (int j = 4; j <= (n - 2); j++) { //get correct starting bit position for portE
											base = base + this.busSizes[j];
										}
										ept.setOutputPin(k, this.portE.getNodes().getItemAt(base + pinpos[n - 1]));
										pinpos[n - 1]++;
								}

								break;
							}
						}
					}
				}

				epl.insertItem(ept);

				if (ept.getParent() instanceof sim.lib.memory.Register) {
					if (((sim.lib.memory.Register) ept.getParent()).getRegName().equals(this.regName)) {
						//this.regout = ((sim.lib.memory.Register) ept.getParent());
						this.regOut = ((sim.lib.memory.Register) ept.getParent());
						//((sim.lib.memory.Register)ept.getParent()).setValue("07");
						//this.regList[z] = ((sim.lib.memory.Register) ept.getParent());
						//z++;
					}
					
					if (((sim.lib.memory.Register) ept.getParent()).getRegName().equals(this.initRegName)) {
						System.out.println("regval: " + this.initRegValue);
						((sim.lib.memory.Register)ept.getParent()).setValue(this.initRegValue); //set initial value
						int busSize = ((sim.lib.memory.Register)ept.getParent()).getBusSize();
						for(int i = 0; i < busSize;i++){
							ept.setOutputPinValue(busSize-i-1,(((sim.lib.memory.Register)ept.getParent()).getStore()[i]==1),0);
						}
					}
				}
				if (ept.getParent() instanceof sim.lib.memory.ShiftRegister) {
					if (((sim.lib.memory.ShiftRegister) ept.getParent()).getRegName().equals(this.regName)) {
						//this.regout = ((sim.lib.memory.Register) ept.getParent());
						this.regOut = ((sim.lib.memory.ShiftRegister) ept.getParent());
						//this.regList[z] = ((sim.lib.memory.Register) ept.getParent());
						//z++;
					}
					
					if (((sim.lib.memory.ShiftRegister) ept.getParent()).getRegName().equals(this.initRegName)) {
						System.out.println("regval: " + this.initRegValue);
						((sim.lib.memory.ShiftRegister)ept.getParent()).setValue(this.initRegValue); //set initial value
						int busSize = ((sim.lib.memory.ShiftRegister)ept.getParent()).getBusSize();
						for(int i = 0; i < busSize;i++){
							ept.setOutputPinValue(busSize-i-1,(((sim.lib.memory.ShiftRegister)ept.getParent()).getStore()[i]==1),0);
						}
					}
				}
			}

		}

		EnginePeer ep = new EnginePeer(0, 0, this);
		epl.insertItem(ep);

		for (Object n : tempnl) {
			for (Object j : ((Node) n).getJunctiions()) {
				//((Junction)j).setLocation(-100,-100);
				//((Junction)j).setEnabled(false);
			}
			for (Object w : ((Node) n).getWires()) {
				((Wire) w).setVisible(false);
			}
			EnginePeerList epltemp = ((Node) n).getConnection();
			for (Object c : epltemp) {
				((EnginePeer) c).getParent().getParentWrapper().setVisible(false);
			}
			nl.insertItem((Node) n);
		}


		//this.regOut = this.regList[regIndex];

	}

	public void reset() {
	}

	public Wrapper getParentWrapper() {
		return this;
	}

	/* ==================================================================
	 Storage Part
	 ================================================================= */
	public String getSpecificParameters() {
		return (this.modpath + Wrapper.SEPARATOR + this.regName + Wrapper.SEPARATOR + this.modLabel + Wrapper.SEPARATOR + this.colour + Wrapper.SEPARATOR + this.initRegName + Wrapper.SEPARATOR + this.initRegValue + Wrapper.SEPARATOR);
	}

	public void loadWrapper(String[] specificParameters) throws SimException {
		if (specificParameters.length == this.getNumberOfSpecificParameters()) {
			try {
				//this.setBusSize(Integer.valueOf(specificParameters[0]).intValue());
				this.setPath(specificParameters[0]);
				this.regName = specificParameters[1];
				this.modLabel = specificParameters[2];
				this.colour = specificParameters[3].equals("true");
				this.initRegName = specificParameters[4];
				this.initRegValue = specificParameters[5];
				if (specificParameters[5] == null) this.initRegValue = "";
				
				//TODO this.display = specificParamters[3];
			} catch (NumberFormatException e) {
				throw (new SimException("incorrect parameter type"));
			}
		} else {
			throw (new SimException("incorrect number of parameters"));
		}
	}

	public int getNumberOfSpecificParameters() {
		return 6;
	}

	/* ==================================================================
	 Rotation abd Flipping Part
	 ================================================================= */
	protected void adjustToChanges() {
	}
	/* ==================================================================
	 Popup Part
	 ================================================================= */
	private int oldBusSize = 0;

	public boolean hasProperties() {
		return true;
	}

	public Component getPropertyWindow() {
		return (new ModProperties(new String[5], this.regList, this.regName, this.modLabel, this.colour, this.initRegName, this.initRegValue));
	}

	public void respondToChanges(Component property) {
		CentralPanel.ACTIVE_GRID.eraseComponent(this, false);
		ModProperties mp = (ModProperties) property;
		this.regName = mp.getRegName();
		this.modLabel = mp.getLabel();
		this.colour = mp.getColour();
		this.initRegName = mp.getInitRegName();
		this.initRegValue = mp.getInitRegValue();
		CentralPanel.ACTIVE_GRID.paintComponent(this);
	}

	public void restoreOriginalProperties() {
		if (this.oldBusSize != 0) {
			this.setBusSize(this.oldBusSize);
			this.oldBusSize = 0;
		}
	}

	@Override
	public void writeVHDLEntity(String path) {
		//Nothing - components of module write vhdl themselves
		
	}

	@Override
	public String getVHDLName() {
		//nothing
		return null;
	}
	
	
}
