/*
	Copyright 2011 Daniel Pletea

	This file is part of T-Nano.

	T-Nano is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	T-Nano is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with T-Nano.  If not, see <http://www.gnu.org/licenses/>.
 */

import java.awt.AlphaComposite;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.event.MouseInputListener;
import javax.swing.filechooser.FileFilter;

/**
 * This class is the gui for creating a circuit with tiles
 * 
 * @author Daniel Pletea
 * 
 */
public class GuiCircuit extends Gui {

	private static final long serialVersionUID = 1L;

	// the matrix of the circuit
	private Integer circuit[][];

	// the labels which are used to put tiles in the circuit
	private JLabel circuitLabels[][];

	// a vecotr with the images sized at the proper dim
	private List<Image> sizedImages;
	private List<Image> sizedInputs;
	private List<Image> sizedOutputs;

	// values for status:
	// 0 - new document
	// 1 - document modified which resides in the memory
	// 2 - document which resides in the memory and is not modified currently
	private int status;

	// the name of the circuit
	private String name;

	// the maximum of dim is 200
	// the minimum is 10
	private int dim;

	// indicates the starting position for drawing the circuit
	private int startColumn, startLine;

	// these coordinates indicates the tile that is red
	// because the mouse is above it
	private int iRed, jRed;

	// indicates the crtTile used for creating the circuit
	private int crtTile = 0;

	private int relativeLine;
	private int relativeColumn;

	// this component is used for insertin an entire circuit
	// specified in .tnn file
	private int component[][];

	// this boolean tell if the gui is in click mode for true
	// or tile mode for false
	private boolean clickMode;

	// some variables for selecting
	private int startSelectX, stopSelectX, startSelectY, stopSelectY;

	// this list has the rectangles that have to be blue because they are
	// selected
	private List<Rectangle> rs;

	// these lists indicate the indexes for the rectangles before
	// these indexes represent the position in the circuit
	private List<Integer> is, js;

	//
	private RightClickMenu rightClickMenu;
	private boolean pasteMode;

	// the input and output images and their names
	private List<BufferedImage> inputs;
	private List<BufferedImage> outputs;
	private List<String> inputNames;
	private List<String> outputNames;

	// this list has circuits
	private List<Object> changes;
	private int crtChange;

	// this indicates if the last action was an undo
	private boolean undo;

	// analyze file created
	private boolean analyzeFileCreated;

	// ID for different analyze and simulations
	int simCount;
	int anlzCount;
	
	// an object for the class created at the end of this soruce
	private MyMouseListener myMouseListener;

	/**
	 * constructor for creating a new Circuit
	 * 
	 * @param circuitWidth
	 * @param circuitHeight
	 */
	public GuiCircuit(int circuitWidth, int circuitHeight) {
		// calling the constructor of class from whic
		// this class was extended
		super();

		// initiating the circuit
		initCircuit(circuitWidth, circuitHeight, "Untitled"
				+ Singleton.getInstance().getNrUntitled(), NEW);

		// fill it with values
		for (int i = 0; i < circuitHeight; i++)
			for (int j = 0; j < circuitWidth; j++) {
				circuit[i][j] = -1;
			}

		// resizing the images
		resizeImages();

	}

	/**
	 * constructor which opens a circuit which is saved in file
	 * 
	 * @param file
	 */
	public GuiCircuit(String file) {
		super();

		int circuitWidth, circuitHeight;
		Scanner scanner;

		try {

			// read the file
			BufferedReader in = new BufferedReader(new FileReader(file));

			scanner = new Scanner(in);

			// get the width and the height
			circuitHeight = scanner.nextInt();
			circuitWidth = scanner.nextInt();

			int nrInputs;
			int nrOutputs;
			nrInputs = scanner.nextInt();
			nrOutputs = scanner.nextInt();

			// initiate the circuit
			initCircuit(circuitWidth, circuitHeight, file, SAVED);

			// read the values of circuit
			for (int i = 0; i < circuitHeight; i++)
				for (int j = 0; j < circuitWidth; j++)
					circuit[i][j] = scanner.nextInt();

			for (int i = 0; i < nrInputs; i++) {
				String str = scanner.next();
				addInput(str);
			}
			for (int i = 0; i < nrOutputs; i++) {
				String str = scanner.next();
				addOutput(str);
			}

			// resizing images
			resizeImages();

		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}

	/**
	 * add an Input
	 */
	private void addInput(String str)
	{
		inputs.add(Singleton.getInstance().createTextImage(str));
		inputNames.add(str);
	}
	
	/**
	 * 
	 */
	private void addOutput(String str)
	{
		outputs.add(Singleton.getInstance().createTextImage(str));
		outputNames.add(str);
	}
	
	/**
	 * initiating of the circuit
	 */
	private void initCircuit(int circuitWidth, int circuitHeight, String name,
			int status) {

		System.out.println("Initiate circuit");

		if (name != null) {

			// creating the myMouseListener and make this object listen to it
			myMouseListener = new MyMouseListener(this);
			addMouseListener(myMouseListener);
			addMouseMotionListener(myMouseListener);

			// give a name
			this.name = name;

			// the buttons as Save, Zoom or Move are enabled
			enableButtons();

			// pasteMode
			pasteMode = false;

			inputs = new ArrayList<BufferedImage>();
			inputNames = new ArrayList<String>();
			outputs = new ArrayList<BufferedImage>();
			outputNames = new ArrayList<String>();

			undo = false;
			analyzeFileCreated = false;
			changes = new ArrayList<Object>();
			crtChange = -1;

			anlzCount = 0;
			simCount = 0;
			
		}

		// seting the dimension of the tiles of the circuit
		dim = (Main.width - 250) / circuitWidth;
		if (dim > (Main.height - 260) / circuitHeight)
			dim = (Main.height - 260) / circuitHeight;
		if (dim < 10)
			dim = 10;
		if (dim > 200)
			dim = 200;

		// setting the position from which to print the circuit as 0 and 0
		// this indicate the first tile in the circuit
		startColumn = 0;
		startLine = 0;

		//
		circuit = new Integer[circuitHeight][circuitWidth];
		paint = true;

		// setting no red tile
		iRed = -1;
		jRed = -1;

		component = null;
		clickMode = false;

		rs = new ArrayList<Rectangle>();
		is = new ArrayList<Integer>();
		js = new ArrayList<Integer>();
		rightClickMenu = new RightClickMenu(this);

		// create labels for the circuit
		createCircuitLabels(false);

		// setting status of the circuit
		this.status = status;

	}

	/**
	 * this functions changes the colors for the gui
	 */
	public void changeTheme() {
		// removing the actual images
		inputs.clear();
		outputs.clear();

		// create new ones with the color wanted
		for (int i = 0; i < inputNames.size(); i++) {
			String str = inputNames.get(i);
			inputs.add(Singleton.getInstance().createTextImage(str));
		}
		for (int i = 0; i < outputNames.size(); i++) {
			String str = outputNames.get(i);
			outputs.add(Singleton.getInstance().createTextImage(str));
		}

		// in the end resizing the images
		resizeImages();
	}

	/**
	 * function which enables the options of Save, Zoom or Move
	 */
	private void enableButtons() {

		// just enabling items which are used only by the circuit gui
		saveItem.setEnabled(true);
		saveAsItem.setEnabled(true);
		exportItem.setEnabled(true);
		zoomInItem.setEnabled(true);
		zoomOutItem.setEnabled(true);
		moveLeft.setEnabled(true);
		moveRight.setEnabled(true);
		moveUp.setEnabled(true);
		moveDown.setEnabled(true);
		undoItem.setEnabled(true);
		redoItem.setEnabled(true);
		selectModeItem.setEnabled(true);
		insertCompItem.setEnabled(true);
		for (int i = 0; i < methodItems.size(); i++) {
			methodItems.get(i).setEnabled(true);
		}
		runItem.setEnabled(true);
		theme1.setEnabled(true);
		theme2.setEnabled(true);
		closeTaskItem.setEnabled(true);

	}

	/**
	 * here are created the labels which helps the GUI to listen to the actions
	 * of the user in order to see where is the mouse
	 */
	private void createCircuitLabels(boolean resize) {

		// removing the old labels for replacing them with new ones
		if (circuitLabels != null)
			for (int i = 0; i < circuitLabels.length; i++)
				for (int j = 0; j < circuitLabels[0].length; j++)
					if (circuitLabels[i][j] != null)
						this.remove(circuitLabels[i][j]);

		int printWidth = (Main.width - 250) / dim;
		int printHeight = (Main.height - 260) / dim;

		// setting the dimensions of the printing area
		if (printWidth > circuit[0].length)
			printWidth = circuit[0].length;
		if (printHeight > circuit.length)
			printHeight = circuit.length;

		// creating the labels
		circuitLabels = new JLabel[printHeight][printWidth];
		for (int i = 0; i < printHeight; i++)
			for (int j = 0; j < printWidth; j++) {
				int x = 150 + j * dim;
				int y = 130 + i * dim;

				circuitLabels[i][j] = new JLabel();
				circuitLabels[i][j].setBounds(x, y, dim, dim);
				circuitLabels[i][j].addMouseListener(myMouseListener);
				circuitLabels[i][j].addMouseMotionListener(myMouseListener);
				this.add(circuitLabels[i][j]);
			}

		resetCircuit();
		if (resize)
			resizeImages();

	}

	/**
	 * this function
	 */
	private void resetCircuit() {
		iRed = -1;
		paint = true;
	}

	/**
	 * this function is called when the circuit is changed by change I mean: -
	 * inserting tiles - deleting tile
	 */
	private void change() {

		// feedback
		System.out.println("Change action ");

		// remove the changes that would be accesible just with a redo action
		int size = changes.size();
		for (int i = crtChange + 1; i < size; i++) {
			changes.remove(crtChange + 1);
		}
		changes.add(copyCircuit(circuit));
		crtChange++;

		// set last action as not being undo
		undo = false;
	}

	/**
	 * this functions sets the circuit as being a previous one
	 */
	private void undo() {
		System.out.println("Undo action");

		// if the last action is not undo
		if (!undo) {
			changes.add(copyCircuit(circuit));
			undo = true;
		}

		// if undo can be done do it
		if (crtChange >= 0) {
			int circuitHeight = ((Integer[][]) changes.get(crtChange)).length;
			int circuitWidth = ((Integer[][]) changes.get(crtChange))[0].length;

			initCircuit(circuitWidth, circuitHeight, null, 1);
			circuit = copyCircuit((Integer[][]) changes.get(crtChange));

			paint = true;

			// decresing the crtChange
			crtChange--;
		}
	}

	/**
	 * this functions is the opposit of undo
	 */
	private void redo() {

		// log
		System.out.println("Redo action");

		// if redo is possible
		if (crtChange < changes.size() - 2) {
			int circuitHeight = ((Integer[][]) changes.get(crtChange + 2)).length;
			int circuitWidth = ((Integer[][]) changes.get(crtChange + 2))[0].length;

			// setting the circuit
			initCircuit(circuitWidth, circuitHeight, null, 1);
			circuit = copyCircuit((Integer[][]) changes.get(crtChange + 2));

			paint = true;

			crtChange++;
		}
	}

	/**
	 * this functions returns a copy of the parameter
	 * 
	 * @param circuit
	 * @return
	 */
	private Integer[][] copyCircuit(Integer[][] circuit) {
		Integer[][] copy = new Integer[circuit.length][circuit[0].length];

		for (int i = 0; i < circuit.length; i++)
			for (int j = 0; j < circuit[0].length; j++)
				copy[i][j] = circuit[i][j];

		return copy;
	}

	/**
	 * this functions resizes the images at the dimension dim
	 */
	private void resizeImages() {
		sizedImages = null;
		sizedImages = new ArrayList<Image>();
		for (int i = 0; i < NR_TILES; i++)
			sizedImages.add(resizeImage(tiles.get(i)));

		sizedInputs = null;
		sizedInputs = new ArrayList<Image>();
		for (int i = 0; i < inputs.size(); i++)
			sizedInputs.add(resizeImage(inputs.get(i)));

		sizedOutputs = null;
		sizedOutputs = new ArrayList<Image>();
		for (int i = 0; i < outputs.size(); i++)
			sizedOutputs.add(resizeImage(outputs.get(i)));

	}

	/**
	 * 
	 * @param bi
	 * @return
	 */
	private Image resizeImage(BufferedImage bi) {
		return bi.getScaledInstance(dim, dim, BufferedImage.SCALE_DEFAULT);
	}

	/**
	 * here are all the actions
	 */
	@Override
	public void actionPerformed(ActionEvent e) {

		super.actionPerformed(e);
		JComponent source = (JComponent) e.getSource();

		Scanner scanner;

		// if a tool is selected than the crtTile is set with that index
		if (tools.contains(source) || toolsMenuItems.contains(source)) {
			int index = tools.indexOf(source);
			if (index == -1)
				index = toolsMenuItems.indexOf(source);

			// if is not click mode button pressed
			if (index != NR_TILES - 2) {
				crtTile = index;
				clickMode = false;
				destroySelection();
				
				// else switch to click mode
			} else {
				// if is the clickMode tile than clickMode true and now the user
				// is in sleection mode
				clickMode = true;
			}

			// the Save As button is pressed
		} else if (source.equals(saveAsItem)) {
			System.out.println("Save As ... ");
			saveAs();

			// the Save button is pressed
		} else if (source.equals(saveItem)) {
			System.out.println("Save" + status);
			if (status == MODIFIED) {
				save();
			} else if (status == NEW) {
				saveAs();
			} else
				;

			// the Zoom In button is pressed
		} else if (source.equals(zoomInItem)) {
			System.out.println("Zoom in");

			// zooming in by modifying the dimension
			if (dim < MAX_TILE_DIM)
				dim += DELTA;

			// and creating the labels
			createCircuitLabels(true);

			// the Zoom Out button is pressed
		} else if (source.equals(zoomOutItem)) {
			System.out.println("Zoom out");

			if (dim > MIN_TILE_DIM)
				dim -= DELTA;

			createCircuitLabels(true);

			// the Move Left button is pressed
		} else if (source.equals(moveLeft)) {
			if (startColumn > 0)
				startColumn--;
			resetCircuit();

			// the Move RIght button is pressed
		} else if (source.equals(moveRight)) {
			if (startColumn < circuit[0].length - circuitLabels[0].length)
				startColumn++;
			resetCircuit();

			// the Move Up button is pressed
		} else if (source.equals(moveUp)) {
			if (startLine > 0)
				startLine--;
			resetCircuit();

			// the Move Down button is pressed
		} else if (source.equals(moveDown)) {
			if (startLine < circuit.length - circuitLabels.length)
				startLine++;
			resetCircuit();

			// switch to click mode ( select mode )
		} else if (source.equals(selectModeItem)) {
			System.out.println("Switch mode to click mode");
			clickMode = true;

			// insert a component from file
		} else if (source.equals(insertCompItem)) {

			// logs
			System.out.println("User wants to insert a new component");
			Singleton.getInstance().insertSoundPlay();

			// getting a component from file
			String file = openPopupWindow();
			int componentHeight, componentWidth;

			// read the file
			BufferedReader in;
			try {

				in = new BufferedReader(new FileReader(file));

				if (in != null) {

					change();

					scanner = new Scanner(in.readLine());

					// get the width and the height
					componentHeight = scanner.nextInt();
					componentWidth = scanner.nextInt();

					// initiate the circuit
					component = new int[componentHeight][componentWidth];

					// read the values of circuit
					for (int i = 0; i < componentHeight; i++) {
						scanner = new Scanner(in.readLine());
						for (int j = 0; j < componentWidth; j++)
							component[i][j] = scanner.nextInt();
					}

					in.close();
				}

			} catch (FileNotFoundException e1) {
				e1.printStackTrace();
			} catch (IOException e2) {
				e2.printStackTrace();
			}

			// the Copy button from right click menu is pressed
		} else if (source.equals(rightClickMenu.getCopyItem())) {
			// write in the log the action is happening
			System.out.println("Copy action");

			// create a component based on the selection
			createSelectionComponent();

			// here the selection is deselected
			destroySelection();

			// the Cut button from right click menu is pressed
		} else if (source.equals(rightClickMenu.getCutItem())) {
			// write in the log the acion is happening
			System.out.println("Cut action");

			// create a component based on the selection
			createSelectionComponent();

			// clear the selection ( the difference between cut and copy )
			for (int i = 0; i < is.size(); i++)
				circuit[startLine + is.get(i)][startColumn + js.get(i)] = -1;

			// here the selection is deselected
			destroySelection();

			// the Paste button from right click menu is pressed
		} else if (source.equals(rightClickMenu.getPasteItem())) {
			// update the log
			System.out.println("Paste action");

			// setting the component as the one from Main
			component = null;
			component = Main.pasteComponent;
			if (component.length == 1 && component[0].length == 1)
				circuit[iRed][jRed] = component[0][0];
			else
				pasteMode = true;

			// insert Rows above
		} else if (source.equals(rightClickMenu.getInsertRowsAbove())) {

			// create am insertDialog for interogating the user about the number
			// of rows
			InsertDialog insertDialog = new InsertDialog();
			insertDialog.setVisible(true);
			if (insertDialog.hasData())
				insertRows(insertDialog.getData());
			insertDialog = null;

			// insert Rows below
		} else if (source.equals(rightClickMenu.getInsertRowsBelow())) {

			InsertDialog insertDialog = new InsertDialog();
			insertDialog.setVisible(true);
			if (insertDialog.hasData()) {
				relativeLine++;
				insertRows(insertDialog.getData());
			}
			insertDialog = null;

			// rmove the current row
		} else if (source.equals(rightClickMenu.getRemoveRowItem())) {
			Singleton.getInstance().deleteSoundPlay();
			change();
			insertRows(-1);

			// delete the current row
		} else if (source.equals(rightClickMenu.getDeleteRowItem())) {
			Singleton.getInstance().deleteSoundPlay();
			change();
			for (int j = 0; j < circuit[0].length; j++)
				circuit[relativeLine][j] = -1;

			// insert columns left
		} else if (source.equals(rightClickMenu.getInsertColumnsLeft())) {

			InsertDialog insertDialog = new InsertDialog();
			insertDialog.setVisible(true);
			if (insertDialog.hasData())
				insertColumns(insertDialog.getData());
			insertDialog = null;

			// insert columns right
		} else if (source.equals(rightClickMenu.getInsertColumnsRight())) {

			InsertDialog insertDialog = new InsertDialog();
			insertDialog.setVisible(true);
			if (insertDialog.hasData()) {
				relativeColumn++;
				insertColumns(insertDialog.getData());
			}
			insertDialog = null;

			// remove the current column
		} else if (source.equals(rightClickMenu.getRemoveColumnItem())) {
			Singleton.getInstance().deleteSoundPlay();
			change();
			insertColumns(-1);

			// delete the current column
		} else if (source.equals(rightClickMenu.getDeleteColumnItem())) {
			Singleton.getInstance().deleteSoundPlay();
			change();
			for (int i = 0; i < circuit.length; i++)
				circuit[i][relativeColumn] = -1;

			// delete the selected item
		} else if (source.equals(rightClickMenu.getDeleteItem())) {

			Singleton.getInstance().deleteSoundPlay();
			change();

			if (rs.size() > 0) {

				deleteSelectionComponent();
				destroySelection();
			} else
				circuit[iRed][jRed] = -1;

			// a method item is pressed
		} else if (methodItems.contains(source)) {

			int index = methodItems.indexOf(source);

			System.out.println(execNamePerMethod.get(index) + " action ");

			// create the analyze files
			if (!analyzeFileCreated || status != SAVED)
				createAnalyzeFile();

			AnalyzeDialog analyzeDialog = new AnalyzeDialog(
					nrParamPerMethod.get(index));
			analyzeDialog.setVisible(true);
			if (analyzeDialog.hasData()) {
				String parameters = analyzeDialog.getData();
				createAnalyze(name, execNamePerMethod.get(index), parameters);
			}

			// undo
		} else if (source.equals(undoItem)) {
			System.out.println("Undo action");
			undo();

			// redo
		} else if (source.equals(redoItem)) {
			System.out.println("Redo action");
			redo();

			// export to pdf
		} else if (source.equals(exportItem)) {

			String file = null;

			// set the name of the file
			JFileChooser chooser = new JFileChooser();
			chooser.setCurrentDirectory(new File("."));
			chooser.setFileFilter(new FileFilter() {
				public boolean accept(File f) {
					return f.getName().toLowerCase().endsWith(".pdf")
							|| f.isDirectory();
				}

				public String getDescription() {
					return "TNN Files";
				}
			});
			int r = chooser.showSaveDialog(this);
			if (r == JFileChooser.APPROVE_OPTION) {

				file = chooser.getSelectedFile().getPath();
				if (!file.substring(file.length() - 4, file.length()).equals(
						".pdf"))
					file = file + ".pdf";
			}

			// create the image that will be print in the pdf file
			int height, width;
			height = circuitLabels.length * dim;
			width = circuitLabels[0].length * dim;

			Image image = new BufferedImage(width, height,
					BufferedImage.TYPE_INT_RGB);
			Graphics g = image.getGraphics();
			int x, y;

			for (int i = startLine; i < startLine + circuitLabels.length; i++)
				for (int j = startColumn; j < startColumn + circuit[0].length; j++) {
					x = (j - startColumn) * dim;
					y = (i - startLine) * dim;
					if (circuit[i][j] < 0) {
						g.drawImage(sizedImages.get(NR_TILES - 1), x, y, null);
					} else {
						int c = circuit[i][j];
						if (c < INPUT_TILE)
							g.drawImage(sizedImages.get(c), x, y, null);
						else if (c % 2 == 1) {
							int index = (c - INPUT_TILE) / 2;
							g.drawImage(sizedInputs.get(index), x, y, null);
						} else {
							int index = (c - OUTPUT_TILE) / 2;
							g.drawImage(sizedOutputs.get(index), x, y, null);

						}
					}
				}

			// effectively write in the pdf file the image
			if (file != null)
				Singleton.getInstance().export(file, image, height, width);

			// do a simulation for all the input scenarios
		} else if (source.equals(runItem)) {
			System.out.println("runTime");

			if (!analyzeFileCreated || status != SAVED)
				createAnalyzeFile();

			createSimulation(name);

			// switch to theme1
		} else if (source.equals(theme1)) {
			if (Singleton.getInstance().getCrtThemeIndex() != 0) {
				Singleton.getInstance().setCrtThemeIndex(0);
				Singleton.getInstance().changeTheme();
			}

			// switch to theme2
		} else if (source.equals(theme2)) {
			if (Singleton.getInstance().getCrtThemeIndex() != 1) {
				Singleton.getInstance().setCrtThemeIndex(1);
				Singleton.getInstance().changeTheme();
			}
		}

		// if save set this circuit as modified
		if (status == SAVED)
			status = MODIFIED;
		paint = true;
	}

	/**
	 * this function creates the analyze file which is used by other programs that
	 * analyse the circuit
	 */
	private void createAnalyzeFile() {
		String file;
		
		// here I create the anlz file in the main folder. By main folder
		//I refer to the folder that has the execution part of this program
		file = Singleton.getInstance().tranformName(name);
		file = file.substring(0, file.length() - 3);
		file = file + ANALYZE_FILE;

		// creating the file for analyzing
		try {

			// open the file for writing
			PrintWriter out = new PrintWriter(file);

			// write the height and the width of the circuit
			out.print(circuit.length + " ");
			out.print(circuit[0].length + " ");

			// count the inputs and the outputs in the circuit
			int nrOutputs = 0, nrInputs = 0;
			for (int i = 0; i < circuit.length; i++)
				for (int j = 0; j < circuit[0].length; j++)
					if (circuit[i][j] >= INPUT_TILE)
						if (circuit[i][j] % 2 == 0)
							nrOutputs++;
						else
							nrInputs++;

			// lists that will contain the identifiers for the groups of IOs
			List<Integer> OutputGroups = new ArrayList<Integer>();
			List<Integer> InputGroups = new ArrayList<Integer>();

			// lists that will contain the number of IOs in each group
			List<Integer> inputs = new ArrayList<Integer>();
			List<Integer> outputs = new ArrayList<Integer>();

			// lists that will contain the currentOutput in the group
			List<Integer> crtOutput;
			List<Integer> crtInput;

			crtOutput = getCrtIO(OUTPUT_TILE, OutputGroups, outputs,
					NR_BASIC_TILES);
			crtInput = getCrtIO(INPUT_TILE, InputGroups, inputs, NR_BASIC_TILES
					+ nrOutputs);

			// write the number of Vdds, Vccs, Ps and Ns
			// first count them
			int nrVdd, nrVcc, nrP, nrN;
			nrVdd = countTiles(VDD_TILE);
			nrVcc = countTiles(VCC_TILE);
			nrP = countTiles(P_TILE);
			nrN = countTiles(N_TILE);

			out.print(nrOutputs + " ");
			out.print(nrInputs + " ");
			out.print(nrVdd + " ");
			out.print(nrVcc + " ");
			out.print(nrP + " ");
			out.println(nrN);

			// setting the current identifier for Vdds, Vccs and transistors
			int crtVdd, crtVcc, crtP, crtN;
			crtVdd = NR_BASIC_TILES + nrOutputs + nrInputs;
			crtVcc = crtVdd + nrVdd;
			crtP = crtVcc + nrVcc;
			crtN = crtP + nrP;

			// writing the matrix that represents the circuit
			for (int i = 0; i < circuit.length; i++) {
				for (int j = 0; j < circuit[0].length; j++) {
					int c = circuit[i][j];
					if (c == P_TILE) {
						out.print(crtP + " ");
						crtP++;
					} else if (c == N_TILE) {
						out.print(crtN + " ");
						crtN++;
					} else if (c == VDD_TILE) {
						out.print(crtVdd + " ");
						crtVdd++;
					} else if (c == VCC_TILE) {
						out.print(crtVcc + " ");
						crtVcc++;
					} else if (c >= OUTPUT_TILE && c % 2 == 0) {
						int index = OutputGroups.indexOf(c);
						int crt = crtOutput.get(index);
						out.print(crt + " ");
						crt++;
						crtOutput.set(index, crt);
					} else if (c >= INPUT_TILE && c % 2 == 1) {
						int index = InputGroups.indexOf(c);
						int crt = crtInput.get(index);
						out.print(crt + " ");
						crt++;
						crtInput.set(index, crt);
					} else {
						if (c < 0)
							c = 0;
						out.print(c + " ");
					}
				}
				out.println();
			}

			// in the end writing the groups of the outputs
			out.println(crtOutput.size() + " ");
			for (int i = 0; i < OutputGroups.size(); i++) {
				int size = outputs.get(i);

				out.print(size + " ");
				for (int j = 0; j < size; j++) {
					out.print((crtOutput.get(i) - size + j) + " ");
				}
				out.println();
			}

			// in the end writing the groups of the inputs
			out.println(crtInput.size() + " ");
			for (int i = 0; i < InputGroups.size(); i++) {
				int size = inputs.get(i);

				out.print(size + " ");
				for (int j = 0; j < size; j++) {
					out.print((crtInput.get(i) - size + j) + " ");
				}
				out.println();
			}

			out.close();

		} catch (FileNotFoundException e1) {
			e1.printStackTrace();
		}

		// the file is created now
		analyzeFileCreated = true;
	}

	/**
	 * this function creates an analyze task
	 * 
	 * @param file
	 * @param exec
	 * @param parameters
	 */
	private void createAnalyze(String file, String exec, String parameters) {
		System.out.println("Create analyze file");
		
		Main.guiList.add(new GuiAnalyze(file, anlzCount, exec, parameters));
		
		anlzCount++;
		file = file.substring(0, file.length() - 3);
		file = file + ANALYZE_FILE + " - " + (anlzCount - 1);

		updateMain(Singleton.getInstance().tranformName(file));
	}

	/**
	 * this function creates a task with the simulation of this circuit
	 * 
	 * @param file
	 */
	private void createSimulation(String file) {

		System.out.println("Create simulation action");

		// counting the outputs
		int nrOutputs = 0;
		for (int i = 0; i < circuit.length; i++)
			for (int j = 0; j < circuit[0].length; j++)
				if (circuit[i][j] >= INPUT_TILE)
					if (circuit[i][j] % 2 == 0)
						nrOutputs++;

		// creating the gro
		List<Integer> OutputGroups = new ArrayList<Integer>();
		List<Integer> InputGroups = new ArrayList<Integer>();
		List<Integer> inputs = new ArrayList<Integer>();
		List<Integer> outputs = new ArrayList<Integer>();
		getCrtIO(OUTPUT_TILE, OutputGroups, outputs, NR_BASIC_TILES);
		getCrtIO(INPUT_TILE, InputGroups, inputs, NR_BASIC_TILES + nrOutputs);

		// lists that contains the name of the outputs and the inputs in the
		// circuit
		List<String> out = new ArrayList<String>();
		List<String> in = new ArrayList<String>();

		for (int i = 0; i < OutputGroups.size(); i++)
			for (int j = 0; j < outputs.get(i); j++)
				out.add(outputNames.get((OutputGroups.get(i) - OUTPUT_TILE) / 2));

		for (int i = 0; i < InputGroups.size(); i++)
			in.add(inputNames.get((InputGroups.get(i) - INPUT_TILE) / 2));

		// add a simulation to the guiList
		Main.guiList.add(new GuiSimulation(file, simCount, out, in));

		simCount++;
		file = file.substring(0, file.length() - 3);
		file = file + SIMULATION_FILE + " - " + (simCount - 1);

		// update the Main
		updateMain(Singleton.getInstance().tranformName(file));
	}

	/**
	 * function that makes the switch to the taskName specified as parameter
	 * 
	 * @param taskName
	 */
	private void updateMain(String taskName) {
		Main.crt = Main.guiList.size() - 1;
		Main.x = true;

		taskComboBox.addItem(taskName);
		taskComboBox.setSelectedIndex(taskComboBox.getItemCount() - 1);

		// feedback
		System.out.println("Main updated");
	}

	/**
	 * this function populates IOGroups and IOs and return a list with the
	 * current IO in every group
	 * 
	 * @param tileId
	 * @param IOGroups
	 * @param IOs
	 * @param startPosition
	 * @return
	 */
	private List<Integer> getCrtIO(int tileId, List<Integer> IOGroups,
			List<Integer> IOs, int startPosition) {

		// here the groups are searched and added to the the list IOGroups
		// if the groups was already found than the IO is counted in the
		// list IOs
		for (int i = 0; i < circuit.length; i++)
			for (int j = 0; j < circuit[0].length; j++) {
				int c = circuit[i][j];
				if (c >= tileId && c % 2 == tileId % 2) {
					int index = IOGroups.indexOf(c);
					if (index == -1) {
						IOGroups.add(c);
						IOs.add(1);
					} else {
						int nr;
						nr = IOs.get(index);
						nr++;
						IOs.set(index, nr);
					}

				}
			}

		List<Integer> crtIO = new ArrayList<Integer>();

		// here is populated the list crtIO
		// with the first IO in the every group
		crtIO.add(startPosition);
		int start = startPosition;

		for (int i = 0; i < IOs.size() - 1; i++) {
			start += IOs.get(i);
			crtIO.add(start);
		}

		return crtIO;
	}

	/**
	 * function that counts the tileID tiles in the matrix circuit
	 * 
	 * @param tileId
	 * @return
	 */
	private int countTiles(int tileId) {
		int nr;

		nr = 0;
		for (int i = 0; i < circuit.length; i++)
			for (int j = 0; j < circuit[0].length; j++)
				if (circuit[i][j] == tileId)
					nr++;

		return nr;
	}

	/**
	 * the function which inserts Rows above the relativeLine
	 * 
	 * @param nr
	 */
	private void insertRows(int nr) {
		int newCircuit[][];
		int newHeight = circuit.length + nr;
		int newWidth = circuit[0].length;

		Singleton.getInstance().insertSoundPlay();
		change();

		// creating the newCircuit from the old one
		newCircuit = new int[newHeight][newWidth];
		for (int i = 0; i < newHeight; i++)
			for (int j = 0; j < newWidth; j++) {
				if (i < relativeLine)
					newCircuit[i][j] = circuit[i][j];
				else if (i < relativeLine + nr)
					newCircuit[i][j] = -1;
				else
					newCircuit[i][j] = circuit[i - nr][j];
			}

		// creating the new circuit with the newWidth and newHeight
		initCircuit(newWidth, newHeight, null, 1);

		// populate the circuit with tiles
		for (int i = 0; i < newHeight; i++)
			for (int j = 0; j < newWidth; j++)
				circuit[i][j] = newCircuit[i][j];

		resizeImages();
	}

	/**
	 * the function which inserts Columns above the relativeColumn
	 * 
	 * @param nr
	 */
	private void insertColumns(int nr) {
		int newCircuit[][];
		int newHeight = circuit.length;
		int newWidth = circuit[0].length + nr;

		Singleton.getInstance().insertSoundPlay();
		change();

		// creating the newCircuit from the old one
		newCircuit = new int[newHeight][newWidth];
		for (int i = 0; i < newHeight; i++)
			for (int j = 0; j < newWidth; j++) {
				if (j < relativeColumn)
					newCircuit[i][j] = circuit[i][j];
				else if (j < relativeColumn + nr)
					newCircuit[i][j] = -1;
				else
					newCircuit[i][j] = circuit[i][j - nr];
			}

		// creating the new circuit with the newWidth and newHeight
		initCircuit(newWidth, newHeight, null, 1);

		for (int i = 0; i < newHeight; i++)
			for (int j = 0; j < newWidth; j++)
				circuit[i][j] = newCircuit[i][j];

		// populate the circuit with tiles
		resizeImages();
	}

	/**
	 * this function creates a copy of the selection
	 */
	private void createSelectionComponent() {

		if (is.size() > 0) {

			// find the imin, imax, jmin and jmax
			int imin, imax, jmin, jmax, x;
			imin = is.get(0);
			imax = imin;
			jmin = js.get(0);
			jmax = jmin;

			for (int i = 1; i < is.size(); i++) {
				x = is.get(i);
				if (x < imin)
					imin = x;
				else if (x > imax)
					imax = x;

				x = js.get(i);
				if (x < jmin)
					jmin = x;
				else if (x > jmax)
					jmax = x;
			}

			// copy the selection to the Main.pasteComponent
			Main.pasteComponent = new int[imax - imin + 1][jmax - jmin + 1];
			Main.pasteInputs.clear();
			Main.pasteOutputs.clear();
			for (int i = 0; i < is.size(); i++) {
				int c = circuit[startLine + is.get(i)][startColumn + js.get(i)];
				
				Main.pasteComponent[is.get(i) - imin][js.get(i) - jmin] = c;

				if (c >= INPUT_TILE)
					if(c % 2 == 1){
						if(!Main.pasteInputs.contains(c))
						{
							Main.pasteInputs.add(inputNames.get( (c - INPUT_TILE ) / 2));
							Main.pasteInputs.add(c);
						}
					}
					else if(!Main.pasteOutputs.contains(c))
					{
						Main.pasteOutputs.add(outputNames.get( (c - OUTPUT_TILE ) / 2) );
						Main.pasteOutputs.add(c);
					}
			}
			
		} else {
			Main.pasteComponent = new int[1][1];
			Main.pasteInputs.clear();
			Main.pasteOutputs.clear();
			
			int c = circuit[iRed][jRed];
			
			Main.pasteComponent[0][0] = c;
			if (c > INPUT_TILE)
				if(c % 2 == 1){
					Main.pasteInputs.add(inputNames.get( (c - INPUT_TILE ) / 2));
					Main.pasteInputs.add(c);
				}
				else
				{
					Main.pasteOutputs.add(outputNames.get( (c - OUTPUT_TILE ) / 2) );
					Main.pasteOutputs.add(c);
				}
		}

	}

	/**
	 * deleting the selection
	 */
	private void deleteSelectionComponent() {

		int imin, imax, jmin, jmax, x;

		imin = is.get(0);
		imax = imin;
		jmin = js.get(0);
		jmax = jmin;

		for (int i = 1; i < is.size(); i++) {
			x = is.get(i);
			if (x < imin)
				imin = x;
			else if (x > imax)
				imax = x;

			x = js.get(i);
			if (x < jmin)
				jmin = x;
			else if (x > jmax)
				jmax = x;
		}

		for (int i = 0; i < is.size(); i++)
			circuit[startLine + is.get(i)][startColumn + js.get(i)] = -1;
	}

	/**
	 * the selection is destroyed
	 */
	private void destroySelection() {
		rs.clear();
		is.clear();
		js.clear();
	}

	/**
	 * functions that that is used to return an AlphaComposite in order to make
	 * the transparency
	 * 
	 * @param alpha
	 *            is a float for the transparency
	 * @return
	 */
	private AlphaComposite makeComposite(float alpha) {
		int type = AlphaComposite.SRC_OVER;
		return (AlphaComposite.getInstance(type, alpha));
	}

	@Override
	public void paint(Graphics g) {
		int x, y;

		super.paint(g);

		// here is painted the circuit constructed till now
		Graphics2D g2d = (Graphics2D) g;
		for (int i = startLine; i < startLine + circuitLabels.length; i++)
			for (int j = startColumn; j < startColumn + circuitLabels[0].length; j++) {
				x = 150 + (j - startColumn) * dim;
				y = 130 + (i - startLine) * dim;
				if (circuit[i][j] < 0) {
					g.drawImage(sizedImages.get(NR_TILES - 1), x, y, null);
				} else {
					int c = circuit[i][j];
					if (c < INPUT_TILE)
						g.drawImage(sizedImages.get(c), x, y, null);
					else if (c % 2 == 1) {
						int index = (c - INPUT_TILE) / 2;
						g.drawImage(sizedInputs.get(index), x, y, null);
					} else {
						int index = (c - OUTPUT_TILE) / 2;
						g.drawImage(sizedOutputs.get(index), x, y, null);

					}
				}
			}

		// paint some red over the curent tile
		// or over the tile where a component will go
		if (iRed >= 0 && (!clickMode || pasteMode)) {
			g2d.setComposite(makeComposite(0.5f));
			if (component == null) {
				x = 150 + (jRed - startColumn) * dim;
				y = 130 + (iRed - startLine) * dim;

				g2d.setColor(OVER_TILE_COLOR);
				g2d.fillRect(x, y, dim, dim);

			} else if (iRed + component.length <= circuit.length
					&& jRed + component[0].length <= circuit[0].length) {
				for (int k = 0; k < component.length; k++)
					for (int m = 0; m < component[0].length; m++) {
						x = 150 + (jRed + m - startColumn) * dim;
						y = 130 + (iRed + k - startLine) * dim;

						// g2d.setComposite(makeComposite(0.5f));
						g2d.setColor(OVER_TILE_COLOR);
						g2d.fillRect(x, y, dim, dim);
					}
			}
			g2d.setComposite(makeComposite(1.0f));
		}

		Image im = tiles.get(crtTile).getScaledInstance(30, 30,
				BufferedImage.SCALE_DEFAULT);
		g.drawImage(im, (Main.width - 50) / 2 - dim / 2, 30, null);

		// the arroyws for telling if something something
		g.setColor(ARROW_COLOR);
		if (startColumn > 0)
			g.fillOval(70, Main.fullSizeHeight / 2, 20, 20);
		if (startLine > 0)
			g.fillOval(Main.fullSizeWidth / 2, 80, 20, 20);
		if (circuitLabels.length < circuit.length)
			g.fillOval(Main.fullSizeWidth / 2, Main.fullSizeHeight - 80, 20, 20);
		if (circuitLabels[0].length < circuit[0].length)
			g.fillOval(Main.fullSizeWidth - 70, Main.fullSizeHeight / 2, 20, 20);

		// if is in click mode and the user began to select something
		// than a rectangle will be used for showing the portion selected
		if (clickMode && startSelectX != -1) {
			boolean xInterchanged = false, yInterchanged = false;
			if (startSelectX > stopSelectX) {
				interchange(X);
				xInterchanged = true;
			}
			if (startSelectY > stopSelectY) {
				interchange(Y);
				yInterchanged = true;
			}

			g2d.setComposite(makeComposite(0.5f));
			g2d.setColor(SELECT_COLOR);
			g2d.fillRect(startSelectX, startSelectY,
					stopSelectX - startSelectX, stopSelectY - startSelectY);

			if (xInterchanged)
				interchange(X);
			if (yInterchanged)
				interchange(Y);

		}

		// here is drawn the current selection
		for (int i = 0; i < rs.size(); i++) {
			Rectangle r = rs.get(i);

			g2d.setComposite(makeComposite(0.5f));
			g2d.setColor(SELECT_COLOR);
			g2d.fillRect(r.x, r.y, r.width, r.height);
		}

	}

	/**
	 * the functions that saves a circuit
	 */
	protected void save() {
		writeToFile(name);
	}

	/**
	 * function that save a new circuit
	 */
	protected void saveAs() {

		// getting the name with which the circuit will be saved
		JFileChooser chooser = new JFileChooser();
		chooser.setCurrentDirectory(new File("."));
		chooser.setFileFilter(new FileFilter() {
			public boolean accept(File f) {
				return f.getName().toLowerCase().endsWith(".tnn")
						|| f.isDirectory();
			}

			public String getDescription() {
				return "TNN Files";
			}
		});
		int r = chooser.showSaveDialog(this);
		if (r == JFileChooser.APPROVE_OPTION) {

			String file = chooser.getSelectedFile().getPath();
			if (!file.substring(file.length() - 4, file.length())
					.equals(".tnn"))
				file = file + ".tnn";

			// writing to the file the circuit
			writeToFile(file);

			// update the combobox with the new name
			String string = Singleton.getInstance().tranformName(name);
			int index;
			for (index = 0; index < taskComboBox.getItemCount(); index++)
				if (taskComboBox.getItemAt(index).equals(string))
					break;

			name = file;

			string = Singleton.getInstance().tranformName(name);
			taskComboBox.insertItemAt(string, index);
			taskComboBox.removeItemAt(index + 1);
		}
	}

	/**
	 * this function writes in a file.tnn this circuit
	 * 
	 * @param file
	 */
	private void writeToFile(String file) {
		try {
			PrintWriter out = new PrintWriter(file);

			// first is writen the height and the weight
			out.println(this.circuit.length + " " + this.circuit[0].length
					+ " " + inputs.size() + " " + outputs.size());

			// than is writen the circuit
			for (int i = 0; i < this.circuit.length; i++) {
				for (int j = 0; j < this.circuit[0].length; j++)
					out.print(circuit[i][j] + " ");
				out.println();
			}

			// here are writen the names of the inputs and of the outputs
			for (int i = 0; i < inputNames.size(); i++)
				out.println(inputNames.get(i));
			for (int i = 0; i < outputNames.size(); i++)
				out.println(outputNames.get(i));

			out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}

		status = SAVED;
		
		// now another anlz file should be created
		analyzeFileCreated = false;
	}

	/**
	 * a function that interchanges the variables startSelectX and stopSelectX
	 */
	private void interchange(char XorY) {
		int aux;

		if (XorY == X) {
			aux = startSelectX;
			startSelectX = stopSelectX;
			stopSelectX = aux;
		} else {
			aux = startSelectY;
			startSelectY = stopSelectY;
			stopSelectY = aux;
		}
	}

	/**
	 * this is a class which implements the interfaces: MouseListener and
	 * MouseInputListener I made this one for making this source more modular
	 * 
	 * @author Daniel
	 * 
	 */
	class MyMouseListener implements MouseListener, MouseInputListener {

		private GuiCircuit parent;

		public MyMouseListener(GuiCircuit parent) {
			this.parent = parent;
		}

		@Override
		public void mouseClicked(MouseEvent arg0) {

			// get the source
			Object src = arg0.getSource();

			// if left click pressed
			if (arg0.getButton() == LEFT_CLICK) {

				// if the source is a JLabel
				if (src instanceof JLabel) {

					// casting the source to JLabel
					JLabel source = (JLabel) arg0.getSource();

					// if is not click Mode or is Paste Mode
					if (!clickMode || pasteMode) {
						for (int i = startLine; i < startLine
								+ circuitLabels.length; i++)
							for (int j = startColumn; j < startColumn
									+ circuitLabels[0].length; j++)
								if (source
										.equals(circuitLabels[i - startLine][j
												- startColumn])) {

									Singleton.getInstance().insertSoundPlay();
									change();

									// if Paste Mode set the pasteMode as false
									if (pasteMode) {	
										
										// first insert the new inputs and outputs
										for(int k = 0; k < Main.pasteInputs.size(); k += 2)
										{
											String inputName = (String) Main.pasteInputs.get(k);
											
											// if the input doesn't exist add it
											if(!inputNames.contains(inputName))
												addInput(inputName);
										}
										
										for(int k = 0; k < Main.pasteOutputs.size(); k += 2)
										{
											String outputName = (String) Main.pasteOutputs.get(k);
											
											// if the output doesn't exist add it
											if(!outputNames.contains(outputName))
												addOutput(outputName);
										}	
										
										// resize the new inputs and outputs
										resizeImages();
										
										// modify the component with the new idetifiers
										// for the inputs and the outputs
										for (int k = 0; k < component.length; k++)
											for (int m = 0; m < component[0].length; m++)
											{
												int c = component[k][m];
												if(c >= INPUT_TILE)
													if(c % 2 == 1)
													{
														int q = Main.pasteInputs.indexOf(c);
														String name = (String) Main.pasteInputs.get(q - 1);
														component[k][m] = INPUT_TILE + 2 * inputNames.indexOf(name);
													}
													else
													{
														int q = Main.pasteOutputs.indexOf(c);
														String name = (String) Main.pasteOutputs.get(q - 1);
														component[k][m] = OUTPUT_TILE + 2 * outputNames.indexOf(name);
													}
											}

										pasteMode = false;
										
										// this is done in order not any tile to
										// be red anymore
										iRed = -1;
									}
									
									// if component is null means that the user
									// wants to introduce just a tile
									if (component == null) {

										iRed = i;
										jRed = j;

										// if is an Input or an Output
										if (crtTile == INPUT_TILE
												|| crtTile == OUTPUT_TILE) {
											insertIOTile();
										} else {
											circuit[i][j] = crtTile;
										}

									}
									// else insert verify first if the component
									// fits in
									// the circuit and than isert it
									else if (i + component.length <= circuit.length
											&& j + component[0].length <= circuit[0].length) {

										for (int k = 0; k < component.length; k++)
											for (int m = 0; m < component[0].length; m++)
												circuit[i + k][j + m] = component[k][m];
										component = null;
									}

									

								}

						// modify the status to modified if the circuit in in
						// the status saved
						if (status == SAVED)
							status = MODIFIED;
						paint = true;
					}
				}
			} else {

				// if right click and the source is instance of JLabel
				if (src instanceof JLabel) {
					setCurrentTile(src);

					// show the rightClickMenu
					Rectangle r = ((JLabel) src).getBounds();
					rightClickMenu.show(parent, r.x + arg0.getX(),
							r.y + arg0.getY());
					relativeLine = iRed;
					relativeColumn = jRed;
				}
			}
		}

		/**
		 * this function inserts a IO tile in the cirucit
		 */
		private void insertIOTile() {
			relativeLine = iRed;
			relativeColumn = jRed;

			// create a Dialog Window to ask about the name of the input
			IODialog ioDialog;
			if (crtTile == INPUT_TILE)
				ioDialog = new IODialog("input", inputNames);
			else
				ioDialog = new IODialog("output", outputNames);
			ioDialog.setVisible(true);

			// if has data
			if (ioDialog.hasData()) {

				// get the data
				List<Object> list = ioDialog.getData();

				// the first object in the list is an integer which represents
				// the type of the IO ( created or new )
				int type = (Integer) list.get(0);

				// if created
				if (type == CREATED_IO) {

					// set the name of the IO as the one already created
					int k = (Integer) list.get(1);
					circuit[relativeLine][relativeColumn] = crtTile + k * 2;
				} else {

					// get the new name
					String str = (String) list.get(1);

					int k;
					if (crtTile == INPUT_TILE)
						k = inputNames.indexOf(str);
					else
						k = outputNames.indexOf(str);

					// if the name doesn't exist insert the name in the combobx
					// and create a new imagine for the new input
					if (k == -1) {
						if (crtTile == INPUT_TILE)
							k = inputNames.size();
						else
							k = outputNames.size();

						BufferedImage bi = Singleton.getInstance()
								.createTextImage(str);

						if (crtTile == INPUT_TILE) {
							inputs.add(bi);
							inputNames.add(str);
							sizedInputs.add(resizeImage(bi));
						} else {
							outputs.add(bi);
							outputNames.add(str);
							sizedOutputs.add(resizeImage(bi));
						}
					}
					circuit[relativeLine][relativeColumn] = crtTile + k * 2;
				}
			}
		}

		@Override
		public void mouseEntered(MouseEvent arg0) {

			// here are set iRed and jRed
			Object src = arg0.getSource();
			if (src instanceof JLabel && !rightClickMenu.isVisible())
				setCurrentTile(src);
		}

		/**
		 * the functions that searches for the label where the mouse entered
		 * 
		 * @param source
		 */
		private void setCurrentTile(Object source) {

			// JLabel source = (JLabel) src;
			for (int i = startLine; i < startLine + circuitLabels.length; i++)
				for (int j = startColumn; j < startColumn
						+ circuitLabels[0].length; j++)
					if (source.equals(circuitLabels[i - startLine][j
							- startColumn])) {

						iRed = i;
						jRed = j;
						break;
					}

			paint = true;
		}

		@Override
		public void mouseExited(MouseEvent arg0) {

			// if the mouse exeted from a JLabel
			// than no Label is red now
			if (!clickMode && !rightClickMenu.isVisible()) {
				iRed = -1;
				jRed = -1;
				paint = true;
			}
		}

		@Override
		public void mousePressed(MouseEvent arg0) {

			// if in click mode modify the slection coordinates
			if (clickMode) {
				if (arg0.getButton() == LEFT_CLICK) {
					System.out.println("Begin selection " + arg0.getX() + " "
							+ arg0.getY());

					int x = 0, y = 0;
					if (arg0.getSource() instanceof JLabel) {
						x = ((JLabel) arg0.getSource()).getX();
						y = ((JLabel) arg0.getSource()).getY();
					}

					startSelectX = x + arg0.getX();
					startSelectY = y + arg0.getY();
					stopSelectX = x + arg0.getX();
					stopSelectY = y + arg0.getY();

					paint = true;
				}
			}
		}

		@Override
		public void mouseReleased(MouseEvent arg0) {

			Object src = arg0.getSource();

			// if left click
			if (arg0.getButton() == LEFT_CLICK) {
				
				// if in select mode set the selection
				if (clickMode) {
					System.out.println("End selection " + startSelectX + " "
							+ startSelectY + " " + stopSelectX + " "
							+ stopSelectY);

					if (startSelectX > stopSelectX)
						interchange(X);
					if (startSelectY > stopSelectY)
						interchange(Y);

					// set the big rectangle drawn by the user
					Rectangle r = new Rectangle(startSelectX, startSelectY,
							stopSelectX - startSelectX, stopSelectY
									- startSelectY);

					// destroy the old selection
					destroySelection();
					
					// set the labels that are included in the big rectangle
					// r previously created
					for (int i = 0; i < circuitLabels.length; i++)
						for (int j = 0; j < circuitLabels[0].length; j++) {
							Rectangle l = circuitLabels[i][j].getBounds();
							if (r.contains(l)) {
								rs.add(l);
								is.add(i);
								js.add(j);
							}
						}
					// repaint
					paint = true;
					startSelectX = -1;
				}
			}
			
			// right mouse button pressed
			else {
				if (src instanceof JLabel) {
					boolean insideSelectedZone = false;
					Rectangle r = ((JLabel) src).getBounds();

					// see if the click is inside the selection
					for (int i = 0; i < rs.size(); i++) {
						if (rs.get(i).contains(r)) {
							insideSelectedZone = true;
							break;
						}
					}

					// if inside selected zone show the right click menu
					if (insideSelectedZone) {
						rightClickMenu.show(parent, r.x + arg0.getX(), r.y
								+ arg0.getY());
						relativeLine = iRed;
						relativeColumn = jRed;
					} 
					// otherwise destroy the selection
					else
						destroySelection();

				} else
					destroySelection();

				paint = true;

			}
		}

		@Override
		public void mouseDragged(MouseEvent arg0) {

			// if in select mode modify the selection coordinates
			if (clickMode) {
				int x = 0, y = 0;
				if (arg0.getSource() instanceof JLabel) {
					x = ((JLabel) arg0.getSource()).getX();
					y = ((JLabel) arg0.getSource()).getY();
				}

				stopSelectX = x + arg0.getX();
				stopSelectY = y + arg0.getY();
				paint = true;
			}

		}

		@Override
		public void mouseMoved(MouseEvent arg0) {
		}
	}
}
