package sim;

import java.io.*;

import org.eclipse.swt.widgets.*;
import sim.GuiEngineLink;
import sim.engine.*;

import java.util.ArrayList;
import java.util.List;

public class VHDLExporter {
	
	public void Export() throws IOException {
		Display display = new Display();
		Shell shell = new Shell(display);
		//shell.open();
		DirectoryDialog dialog = new DirectoryDialog(shell);
		String path = dialog.open();
		shell.close();
		while (!shell.isDisposed()) {
	        if (!display.readAndDispatch())
	            display.sleep();
	    }
	    display.dispose();
		
		Writer writer = null;
		try {
			writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path+"\\main.vhd")));
			writer.write("library IEEE;\n");
			writer.write("use IEEE.STD_LOGIC_1164.ALL;\n\n");
			Writer writer_temp = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path+"\\gates.vhd")));
			writer_temp.write("");
			writer_temp.close();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
		GuiEngineLink link = new GuiEngineLink();
		SimulationEngine se = link.createPeer();
		EnginePeerList epl = se.getComponents();
		
		for (Object o : epl){
			EnginePeer ep = (EnginePeer)o;
			/*switch(ep.getParent().getClass().getName()) {
				case "sim.lib.gates.GateAND":
					writer.write("GateAND\n");
			}*/
			ep.getParent().writeVHDLEntity(path); //write the component entities
			
			//TODO setup connections
			//ep.getInputPins();
			//ep.getOutputPins();
			
		}
		
		int wires = CentralPanel.ACTIVE_GRID.getNumberOfWires();
		
		writer.write("entity main is\n");
		//write input/output ports for circuit (new component?)
		writer.write("end main;\n\n");
		
		writer.write("architecture struct of main is\n");
		//write signals(wires/buses)
		if (wires > 0){
			//writer.write("	signal temp0");
			List<Integer> ids = new ArrayList<Integer>();
			int id = 0;
			int size = 1;
			boolean found = false;
			for (Object o : epl){
				
				EnginePeer ep = (EnginePeer)o;
				for(int i = 0; i < ep.getInputPins().getSize();i++){
					found = false;
					//hash = ep.getInputPins().getItemAt(i).getConnection().hashCode();
					id = ep.getInputPins().getItemAt(i).getConnection().getId();
					for (int h : ids){
							if(h == id)
								found = true;
					}
					if (!found){
						size = ep.getInputPins().getItemAt(i).getConnection().getSize();
						//if (size == 1) { //size of wire
							writer.write("signal temp"+id+": std_logic;\n");
							ids.add(id);							
						/*}else{
							writer.write("signal temp"+id+": std_logic_vector("+(size-1)+" downto 0);\n");
						}(*/
					}
				}
				if(ep.getOutputPins() != null){
					for(int i = 0; i < ep.getOutputPins().getSize();i++){
						found = false;
						ep.getOutputPins().getItemAt(i).getConnection().getSize(); //size of wire
						//hash = ep.getOutputPins().getItemAt(i).getConnection().hashCode();
						id = ep.getOutputPins().getItemAt(i).getConnection().getId();
						for (int h : ids){
								if(h == id)
									found = true;
						}
						if (!found){
							//if (ep.getInputPins().getItemAt(i).getConnection().getSize() == 1) { //size of wire
								writer.write("signal temp"+id+": std_logic;\n");
								ids.add(id);							
							/*}else{
								writer.write("signal temp"+id+": std_logic_vector("+(size-1)+" downto 0);\n");
							}*/
						}
					}
				}
			}
			//writer.write(": std_logic;"); //TODO extend to vectors etc.
		}
		writer.write("\nbegin\n");
		//writer join all components
		int id = 0;
		int inputSize = 0;
		for (Object o : epl){
			EnginePeer ep = (EnginePeer)o;
			writer.write("	comp_" + id + " : entity work.");
			id++;
			writer.write(ep.getParent().getVHDLName()+ " port map (");
			inputSize = ep.getInputPins().getSize();
			if(ep.getParent() instanceof sim.lib.memory.Ram){
				for(int i = 0; i < 3;i++){
					ep.getInputPins().getItemAt(i).getConnection().getSize(); //size of wire
					writer.write("temp"+ep.getInputPins().getItemAt(i).getConnection().getId()+ ",");
				}
				//inputSize = inputSize - ((sim.lib.memory.Ram)ep.getParent()).getBusSize();
				for(int i = 3+((sim.lib.memory.Ram)ep.getParent()).getBusSize(); i < ep.getInputPins().getSize();i++){
					ep.getInputPins().getItemAt(i).getConnection().getSize(); //size of wire
					writer.write("temp"+ep.getInputPins().getItemAt(i).getConnection().getId()+ ",");
				}
			}else{
				for(int i = 0; i < inputSize;i++){
					ep.getInputPins().getItemAt(i).getConnection().getSize(); //size of wire
					writer.write("temp"+ep.getInputPins().getItemAt(i).getConnection().getId()+ ",");
				}
			}
			if (ep.getOutputPins() != null){
				for(int i = 0; i < ep.getOutputPins().getSize()-1;i++){
					ep.getOutputPins().getItemAt(i).getConnection().getSize(); //size of wire
					writer.write("temp"+ep.getOutputPins().getItemAt(i).getConnection().getId()+","); //add , here..
				}
				writer.write("temp"+ep.getOutputPins().getItemAt(ep.getOutputPins().getSize()-1).getConnection().getId()+");\n");
			}
			else{
				writer.write(");\n");
			}
			//writer.write(");\n");
		}
		writer.write("end struct;");
		
		writer.close();
	}
	
	public static void writeLib(String path){
		try{
			FileWriter gwriter = new FileWriter(path+"\\gates.vhd",true);
			gwriter.write("\nlibrary IEEE;\n");
			gwriter.write("use IEEE.STD_LOGIC_1164.ALL;\n");
			gwriter.close();
		} catch (Exception e){
			
		}
	}
}
