package ui.view;

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.HashMap;

import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;

import api.CpsAlgorithm;
import ui.controller.Control;
import ui.model.Model;

/**
 * This Class represents the Menu, where you can select the Algorithms.
 * 
 * @author Gruppe14
 */
public class AlgorithmMenu extends JMenu {

	private static final long serialVersionUID = 1L;

	JMenuItem algoFolderButton = new JMenuItem("Select Algorithm Folder");
	private JMenu mnSelectAlgorithm = new JMenu("Select Algorithm");
	private HashMap<String, File> algosHash = new HashMap<>();
	private JMenuItem noneItem = new JMenuItem("none");

	// root Directory
	File root = null;

	Model model;
	Control controller;

	/**
	 * Constructor.
	 * 
	 * @param mod
	 *            the Model
	 * @param cont
	 *            the Controller
	 */
	public AlgorithmMenu(Model mod, Control cont) {
		super();
		// Init Stuff
		this.model = mod;
		this.controller = cont;
		this.setText("Algorithm");

		// algoFolderButton Action
		algoFolderButton.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				menuSetFolderActionPerformed(evt);
			}

			private void menuSetFolderActionPerformed(java.awt.event.ActionEvent evt) {
				JFileChooser fileChooser = new JFileChooser();
				JFrame test = new JFrame();
				fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
				fileChooser.setAcceptAllFileFilterUsed(false);

				if (fileChooser.showOpenDialog(test) == JFileChooser.APPROVE_OPTION) {
					// empty everything and reset the selected algorithm
					controller.setAlgorithm(null);
					mnSelectAlgorithm.removeAll();
					mnSelectAlgorithm.add(noneItem);
					noneItem.doClick();

					File[] files = fileChooser.getSelectedFile().listFiles();
					// Set Root Folder Path
					root = new File(fileChooser.getCurrentDirectory().getPath());

					for (int i = 0; i < files.length; i++) {
						if (files[i].toString()
								.endsWith(".java") /*
													 * || files[i].toString().
													 * endsWith(".class")
													 */) {
							String name = files[i].getName();
							int tmpB = name.lastIndexOf('.');
							name = name.substring(0, tmpB);
							algosHash.put(name, files[i]);
							JMenuItem tempItem = new JMenuItem(name);
							tempItem.addActionListener(new ActionListener() {

								@Override
								public void actionPerformed(ActionEvent e) {
									for (int i = 0; i < mnSelectAlgorithm.getItemCount(); i++) {
										mnSelectAlgorithm.getItem(i).setForeground(null);
									}
									tempItem.setForeground(Color.BLUE);
									setAlgorithm(algosHash.get(tempItem.getText()), tempItem.getText());
								}
							});
							mnSelectAlgorithm.add(tempItem);
						}
					}

				}
			}

		});

		// Add to Panel
		this.add(algoFolderButton);
		this.add(mnSelectAlgorithm);
		mnSelectAlgorithm.add(noneItem);
		noneItem.setForeground(Color.BLUE);
		noneItem.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				for (int i = 0; i < mnSelectAlgorithm.getItemCount(); i++) {
					mnSelectAlgorithm.getItem(i).setForeground(null);
				}
				noneItem.setForeground(Color.BLUE);
				controller.setAlgorithm(null);
			}
		});
	}

	public void setAlgorithm(File file, String name) {
		boolean missingCompiler = false;
		boolean instantiationError = false;
		try {
			BufferedReader br = new BufferedReader(new FileReader(file.getPath()));
			String line = br.readLine();
			// Package Name
			String packageName = "";

			while (line != null) {
				line = line.trim();
				if (!line.isEmpty()) {
					if (line.length() >= 7 && line.substring(0, 7).equals("package")) {
						packageName = line.substring(8, line.length() - 1);
					}
				}
				if (packageName.isEmpty()) {
					line = br.readLine();
				} else {
					line = null;
				}

			}

			// Compile source file.
			JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

			if (ToolProvider.getSystemJavaCompiler() == null) {
				missingCompiler = true;
			}

			compiler.run(null, null, null, file.getPath());

			// Load and instantiate compiled class.
			URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { root.toURI().toURL() });

			instantiationError = true;
			Class<?> cls;
			if (packageName.isEmpty()) {
				cls = Class.forName(name, true, classLoader);
			} else {
				cls = Class.forName(packageName + "." + name, true, classLoader);
			}

			Object t = cls.newInstance();
			if (t instanceof CpsAlgorithm) {
				controller.setAlgorithm(t);
			} else {
				JOptionPane.showMessageDialog(null, "Class does not implement CpsAlgorithm!", "Error!",
						JOptionPane.ERROR_MESSAGE);
				noneItem.doClick();
			}
		} catch (Exception e) {
			if (missingCompiler) {
				JOptionPane.showMessageDialog(null, "Missing Compiiler! Please install the JDK!", "Error!",
						JOptionPane.ERROR_MESSAGE);
			} else if (instantiationError) {
				JOptionPane.showMessageDialog(null, "Class does not implement CpsAlgorithm!", "Error!",
						JOptionPane.ERROR_MESSAGE);
				noneItem.doClick();
			} else {
				JOptionPane.showMessageDialog(null, e.toString(), "Error!", JOptionPane.ERROR_MESSAGE);
			}
		}
	}
}
