package ui.view;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.Scanner;
import java.util.stream.Collectors;

import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextPane;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;

import api.AddOn;
import ui.controller.Control;
import utility.ImageImport;

@SuppressWarnings("serial")
public class AddOnWindow extends JFrame{
	private AddOn actual;
	private Control control;
	private JPanel content = new JPanel();
	AddOnWindow(JFrame parentFrame, Control control){
		this.control = control;
		this.setTitle("Add-Ons");
		this.setVisible(true);
		this.setContentPane(content);
		this.setIconImage(ImageImport.loadImage("/Images/Holeg.png", 30, 30));
		initMenuBar();
		initDefaultContentPanel();
		this.pack();
		this.setLocationRelativeTo(parentFrame);
	}
	private void initMenuBar() {
		JMenuBar menuBar = new JMenuBar();
		JMenu menuSelect = new JMenu("File");
		JMenuItem menuItemAlgorithm= new JMenuItem("Open .java-File..");
		menuItemAlgorithm.addActionListener(actionEvent -> openJavaFile());
		menuSelect.add(menuItemAlgorithm);
		JMenuItem menuItemFolder= new JMenuItem("Open Folder..");
		menuItemFolder.addActionListener(actionEvent->openFolder(menuSelect));
		menuSelect.add(menuItemFolder);
		menuSelect.addSeparator();
		JMenu menuHelp = new JMenu("Help");
		menuBar.add(menuSelect);
		menuBar.add(menuHelp);
		this.setJMenuBar(menuBar);
	}
	
	private void initDefaultContentPanel() {
		content.setLayout(new BorderLayout());
		JTextPane textPane = new JTextPane();
		SimpleAttributeSet attribs = new SimpleAttributeSet();  
		StyleConstants.setAlignment(attribs , StyleConstants.ALIGN_JUSTIFIED);
		textPane.setParagraphAttributes(attribs, true);
		textPane.setText("No algorithm is loaded."
				+"\n OPTION[1]:"
				+"\n  Select '.java'-file via the file browser. (File\u2192Open .jave-File..)"
				+"\n"
				+"\n OPTION[2]:"
				+"\n First select the folder where the addon '.java'-file is located. (File\u2192Open Folder..)"
				+"\n Second load the algorithm. (File\u2192'YourAlgo')");
		textPane.setFont(new Font("Serif", Font.PLAIN, 16));
		
		
		content.add(textPane, BorderLayout.CENTER);
		content.setPreferredSize(new Dimension(500, 500));
	}
	
	/**
	 * 
	 */
	private void openJavaFile() {
		JFileChooser fileChooser = new JFileChooser();
		fileChooser.setCurrentDirectory(new File(System.getProperty("user.dir")+"/src/algorithm/"));
		fileChooser.setFileFilter(new FileNameExtensionFilter("JAVA Source Files", "java"));
		fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
		fileChooser.setAcceptAllFileFilterUsed(false);
		int result = fileChooser.showOpenDialog(this);
		if(result == JFileChooser.APPROVE_OPTION) {
			//Found a file
			loadAlgorithm(fileChooser.getSelectedFile());
		}
	}
	
	private void openFolder(JMenu menuSelect) {
		JFileChooser fileChooser = new JFileChooser();
		fileChooser.setCurrentDirectory(new File(System.getProperty("user.dir")+"/src/"));
		fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
		fileChooser.setAcceptAllFileFilterUsed(false);
		int result = fileChooser.showOpenDialog(this);
		if(result == JFileChooser.APPROVE_OPTION) {
			File[] files = fileChooser.getSelectedFile().listFiles(file -> file.getName().endsWith(".java"));
			
			//Remove all Index from old Folder
			for(int i= menuSelect.getItemCount()-1; i> 2; i--) {
				menuSelect.remove(i);
			}
			for(File file: files) {
				JMenuItem insertMenuItem = new JMenuItem(getNameWithoutExtension(file));
				insertMenuItem.addActionListener(actionEvent -> loadAlgorithm(file));
				menuSelect.add(insertMenuItem);
			}
		}
	}
	/**
	 * Compile and load a java File.
	 * @param javafile
	 */
	
	private void loadAlgorithm(File javafile) {
		//Get Class name:
		String name = getNameWithoutExtension(javafile);
		//get Package name
		String packageName = "";
		Scanner in = null;
		try {
			in = new Scanner(javafile);
		} catch (FileNotFoundException e) {
			generateErrorDialog("File not Found");
		}
		while(in.hasNext()) {
			String line = in.nextLine().trim();
			if(line.startsWith("package")) {
				packageName = line.substring(8, line.length()-1);
				break;
			}
		}
		//GetPathName
		//String path =  javafile.getParentFile().isDirectory() ? javafile.getParentFile().getAbsolutePath() : "";
		File folder = javafile.getParentFile();
		// Compile source file.
		JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
		if (ToolProvider.getSystemJavaCompiler() == null) {
			generateErrorDialog("Please install the JDK on your system.");
		}else {
			compiler.run(null, null, null, javafile.getAbsolutePath());					
		}
		try {
		URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { folder.toURI().toURL() });
		Class<?> cls = Class.forName(packageName.isEmpty()?name:packageName + "." +name, true, classLoader);
		Object object = cls.newInstance();
		if(!(object instanceof AddOn)) {
			generateErrorDialog("Class does not implement CpsAlgorithm!");
		}else {
			actual = (AddOn)object;
			actual.setController(control);
			this.setContentPane(actual.getPanel());
			this.pack();
		}
		} catch (MalformedURLException e) {
			generateErrorDialog("URLClassLoader error");
		} catch (ClassNotFoundException e) {
			generateErrorDialog("ClassNotFound error" + e.getMessage());
		} catch (InstantiationException e) {
			generateErrorDialog("Class does not implement a Constructor." + e.getMessage());
		} catch (IllegalAccessException e) {
			generateErrorDialog("Class set this method privat or protected needs to be public." + e.getMessage());
		}
	}
	/**
	 * Returns the Name of a file without Extension.
	 * @param file
	 * @return
	 */
	private String getNameWithoutExtension(File file) {
		return file.getName().substring(0, file.getName().lastIndexOf("."));
	}
	/**
	 * Generate a little Error Dialog to inform the User.
	 * @param message
	 */
	private void generateErrorDialog(String message) {
		System.out.println(message);
		JOptionPane.showConfirmDialog(this, message, "Error", JOptionPane.OK_OPTION, JOptionPane.ERROR_MESSAGE);
	}
}
