package de.tu_darmstadt.tk.SmartHomeNetworkSim.view.popups;

import javax.swing.JDialog;
import javax.swing.JList;


import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;

import de.tu_darmstadt.tk.SmartHomeNetworkSim.control.Controller;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.control.SimulationController;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.NetworkManipulationAlgorithm;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.view.util.Utility;

import java.awt.Container;

import javax.swing.JButton;
import javax.swing.JLabel;


/**
 * PopUp for managing the NetworkManipulationAlgorithms
 *
 * @author Andreas T. Meyer-Berg
 */
public class EditAlgorithmsPopUp extends JDialog {
	/**
	 * serial
	 */
	private static final long serialVersionUID = 1L;
	
	/**
	 * Controller for manipulating the simulation and adding algorithms
	 */
	private Controller controller;
	
	/**
	 * Simulation controller for access to the algorithms
	 */
	private SimulationController sim;
	
	/**
	 * Jlist for listing the algorithms
	 */
	private JList<String> list;
	
	/**
	 * Scroll Pane for scrolling in the Algorithm list
	 */
	private JScrollPane scrollPanelList;
	
	/**
	 * Mutex, to disable listeners on update
	 */
	private boolean mutex = true;
	
	/**
	 * Creates and shows a new EditAlgorithmPopUp
	 * @param controller controller
	 * @param parent parent container the location should be set relative to
	 */
	public EditAlgorithmsPopUp(Controller controller, Container parent) {
		this.controller = controller;
		this.sim = this.controller.getSimulationController();
		this.setSize(400, 400);
		setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
		setTitle("Manage ManipulationAlgorithms");
		this.setIconImage(Utility.loadFile("images/smartHome_icon.png"));
		getContentPane().setLayout(null);
		/**
		 * Either Modal - or refresh other instances of this PopUp on refresh
		 */
		this.setModal(true);
		
		list = null;

		JButton btnImportAlgorithm = new JButton("Import Algorithm");
		btnImportAlgorithm.setToolTipText("Import new algorithm, which will be executed after each time step.");
		btnImportAlgorithm.setBounds(220, 130, 160, 25);
		getContentPane().add(btnImportAlgorithm);
		btnImportAlgorithm.addActionListener(a->{
			if(mutex)
				return;
			/**
			 * PopUp for importing NetworkManipulationAlgo
			 */
			ImportPopUp<NetworkManipulationAlgorithm> popUp = new ImportPopUp<NetworkManipulationAlgorithm>(this, NetworkManipulationAlgorithm.class);
			/**
			 * Imported Class
			 */
			Class<? extends NetworkManipulationAlgorithm> imported = null;
			/**
			 * Instance of imported Algorithm class
			 */
			NetworkManipulationAlgorithm importedAlgo = null;
			try {
				imported = popUp.showPopUp();
			} catch (Exception e1) {
				JOptionPane.showMessageDialog(this, "Import failed: " + e1.getMessage());
				return;
			}
			if (imported == null) {
				// Import cancelled
				return;
			}
			try {
				/**
				 * Create and add new instance
				 */
				importedAlgo = imported.newInstance();
				sim.addAlgorithm(importedAlgo, controller);
				//Refresh gui
				updateThis(null);
			} catch (Exception e) {
				JOptionPane.showMessageDialog(this, "Import failed: Missing empty constructor");
			}
		});
		
		JButton btnRemoveSelected = new JButton("Remove Selected");
		btnRemoveSelected.setToolTipText("Remove the selected algorithm");
		btnRemoveSelected.setBounds(220, 160, 160, 25);
		getContentPane().add(btnRemoveSelected);
		btnRemoveSelected.addActionListener(a->{
			if(mutex)
				return;
			/**
			 * Selected Index
			 */
			int index = list.getSelectedIndex();
			if(index<0||index>=sim.getAlgorithms().size())
				return;
			/**
			 * Algorithm which should be removed
			 */
			NetworkManipulationAlgorithm algo = sim.getAlgorithms().get(index);
			sim.removeAlgo(algo);
			
			updateThis(null);
		});
		

		JLabel lblMoveSelected = new JLabel("Move selected:");
		lblMoveSelected.setToolTipText("Algorithms will be executed from top to bottom after each simulation step");
		lblMoveSelected.setBounds(222, 10, 160, 20);
		getContentPane().add(lblMoveSelected);
		
		JButton btnUp = new JButton("Up");
		btnUp.setToolTipText("Move the selected algorithm up. Will be executed earlier.");
		btnUp.setBounds(220, 50, 75, 25);
		btnUp.addActionListener(a->{
			if(mutex)
				return;
			/**
			 * Selected Index
			 */
			int index = list.getSelectedIndex();
			if(index<=0||index>=sim.getAlgorithms().size())
				return;
			/**
			 * Algorithm which should be removed
			 */
			NetworkManipulationAlgorithm algo = sim.getAlgorithms().get(index);
			sim.removeAlgo(algo);
			sim.getAlgorithms().add(index-1, algo);
			list.setSelectedIndex(index-1);
			updateThis(null);
		});
		getContentPane().add(btnUp);
		
		JButton btnDown = new JButton("Down");
		btnDown.setToolTipText("Moves the selected algorithm down. Will execute later.");
		btnDown.addActionListener(a->{
			if(mutex)
				return;
			/**
			 * Selected Index
			 */
			int index = list.getSelectedIndex();
			if(index<0||index>=sim.getAlgorithms().size()-1)
				return;
			/**
			 * Algorithm which should be removed
			 */
			NetworkManipulationAlgorithm algo = sim.getAlgorithms().get(index);
			sim.removeAlgo(algo);
			sim.getAlgorithms().add(index+1, algo);
			list.setSelectedIndex(index+1);
			updateThis(null);
		});
		btnDown.setBounds(310, 50, 75, 25);
		getContentPane().add(btnDown);
		
		scrollPanelList = new JScrollPane();
		scrollPanelList.setBounds(0, 0, 205, 375);
		getContentPane().add(scrollPanelList);
		
		updateThis(null);
		this.setResizable(false);
		this.setLocationRelativeTo(parent);
		this.setEnabled(true);
		this.setVisible(true);
	}
	
	/**
	 * Update this panel
	 * @param o object (unused)
	 */
	public void updateThis(Object o){
		mutex = true;
		/**
		 * Update List
		 */
		/**
		 * Names of the algorithms
		 */
		String[] algoNames = new String[sim.getAlgorithms().size()];
		for(int i=0;i<sim.getAlgorithms().size();i++)
			algoNames[i] = sim.getAlgorithms().get(i).getClass().getSimpleName();
		/**
		 * New list
		 */
		JList<String> newList = new JList<String>(algoNames);
		newList.setToolTipText("List of all currently active ManipulationAlgorithms.");
		newList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		
		int pos = scrollPanelList.getVerticalScrollBar().getValue();

		if(list!=null){
			scrollPanelList.remove(list);
			newList.setSelectedIndex(list.getSelectedIndex());		
		}
		scrollPanelList.setViewportView(newList);
		scrollPanelList.getVerticalScrollBar().setValue(pos);
		list = newList;
		
		this.repaint();
		mutex = false;
		
	}
}
