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.ClassImportException;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.control.Controller;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.control.PacketCaptureController;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.control.SimulationController;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.Link;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.PacketCollector;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.PacketSniffer;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.SmartDevice;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.view.util.Utility;
import weka.classifiers.functions.supportVector.RBFKernel;

import java.awt.Container;

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

import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Iterator;
import java.util.Observable;
import java.util.Observer;
import java.awt.event.ActionEvent;
import javax.swing.JRadioButton;
import javax.swing.JCheckBox;


/**
 * PopUp for creation or editing of packet Sniffers
 *
 * @author Andreas T. Meyer-Berg
 */
public class EditPacketSniffer extends JDialog implements Observer {
	/**
	 * 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;
	
	/**
	 * Controller for capturing packets
	 */
	private PacketCaptureController captureController;
	
	/**
	 *	PacketCollector which is being edited 
	 */
	private PacketCollector collector;
	/**
	 * Label to show the algorithm name
	 */
	private JLabel lblAlgorithm;
	/**
	 * Reference to this for inner classes
	 */
	private EditPacketSniffer that = this;
	/**
	 * Mutex to disable listeners, which GUI Refresh is active
	 */
	private boolean mutex = false;
	/**
	 * ScrollPane which contains a List of all registered Links
	 */
	private JScrollPane scrollPaneLinks;
	/**
	 * List for the links
	 */
	private JList<String> listLinks;
	
	/**
	 * ScrollPane which contains a List of all registered Links
	 */
	private JScrollPane scrollPaneDevices;
	/**
	 * List for the links
	 */
	private JList<String> listDevices;
	/**
	 * True if the collector is being edited
	 */
	private boolean edit;
	/**
	 * RadioButton marked, if in testing mode
	 */
	private JRadioButton rdbtnTesting;
	/**
	 * RadioButton for training mode
	 */
	private JRadioButton rdbtnTraining;
	/**
	 * Checkbox, which is checked if enabled
	 */
	private JCheckBox chckbxEnabled;
	
	/**
	 * Creates and shows a new EditAlgorithmPopUp
	 * @param controller controller
	 * @param parent parent container the location should be set relative to
	 * @param edit true, if an sniffer is being edited
	 */
	public EditPacketSniffer(Controller controller, Container parent, PacketCollector collector, boolean edit) {
		mutex = true;
		this.edit = edit;
		this.controller = controller;
		sim = this.controller.getSimulationController();
		captureController = sim.getPacketCaptureController();
		captureController.addObserver(this);
		this.collector = collector;
		this.setSize(400, 400);
		this.setResizable(false);
		setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
		setTitle((this.edit?"Edit":"Create")+" PacketCollector");
		this.setIconImage(Utility.loadFile("images/smartHome_icon.png"));
		getContentPane().setLayout(null);
		
		JButton btnImportPacketcapturealgorithm = new JButton("Import PacketAlgorithm");
		btnImportPacketcapturealgorithm.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if(mutex)return;
				/**
				 * PopUp for Importing 
				 */
				ImportPopUp<PacketSniffer> importPopUp = new ImportPopUp<PacketSniffer>(that, PacketSniffer.class);
				/**
				 * Imported PacketSniffer Class
				 */
				Class<? extends PacketSniffer> imported = null;
				try {
					 imported = importPopUp.showPopUp();
				} catch (ClassImportException e1) {
					/**
					 * Warning if Importing failed
					 */
					JOptionPane.showMessageDialog(that, "Import failed: " + e1.getMessage());
					return;
				}
				if(imported!=null){
					try {
						/**
						 * Instance of the PacketSniffer
						 */
						PacketSniffer p = imported.newInstance();
						/**
						 * Set as new PacketAlgorithm
						 */
						that.collector.setPacketAlgorithm(p);
						update(null,null);
					} catch (InstantiationException | IllegalAccessException e1) {
						JOptionPane.showMessageDialog(that, "Instance creation failed: " + e1.getMessage());
					}
				}else{
					System.out.println("Imported null");
				}
				//Else import aborted 
			}
		});
		btnImportPacketcapturealgorithm.setBounds(180, 10, 210, 30);
		getContentPane().add(btnImportPacketcapturealgorithm);
		
		lblAlgorithm = new JLabel();
		lblAlgorithm.setBounds(10, 10, 165, 30);
		getContentPane().add(lblAlgorithm);
		
		scrollPaneLinks = new JScrollPane();
		scrollPaneLinks.setBounds(12, 46, 165, 132);
		getContentPane().add(scrollPaneLinks);
		
		scrollPaneDevices = new JScrollPane();
		scrollPaneDevices.setBounds(12, 208, 165, 132);
		getContentPane().add(scrollPaneDevices);
		
		JButton btnStopCapturingLink = new JButton("Stop Capturing Link");
		btnStopCapturingLink.addActionListener(a->{
			if(mutex)
				return;
			int selectedIndex = listLinks.getSelectedIndex();
			if(selectedIndex!=-1 && selectedIndex<collector.getLinks().size()){
				Iterator<Link> it = collector.getLinks().iterator();
				for(int i=0; i<selectedIndex;i++){
					it.next();
				}
				if(it.hasNext()){
					Link linkToBeRemoved = it.next();
					captureController.removeLinkFromCollector(collector, linkToBeRemoved);
					update(null,null);
				}
			}
		});
		
		btnStopCapturingLink.setBounds(180, 150, 210, 30);
		getContentPane().add(btnStopCapturingLink);
		
		JButton btnStopCapturingDevice = new JButton("Stop Capturing Device");
		btnStopCapturingDevice.setBounds(180, 200, 210, 30);
		getContentPane().add(btnStopCapturingDevice);
		
		btnStopCapturingDevice.addActionListener(a->{
			if(mutex)
				return;
			int selectedIndex = listDevices.getSelectedIndex();
			if(selectedIndex!=-1 && selectedIndex<collector.getDevices().size()){
				Iterator<SmartDevice> it = collector.getDevices().iterator();
				for(int i=0; i<selectedIndex;i++){
					it.next();
				}
				if(it.hasNext()){
					SmartDevice deviceToBeRemoved = it.next();
					captureController.removeDeviceFromCollector(collector, deviceToBeRemoved);
					update(null,null);
				}
			}
		});
		
		JButton btnCreatePacketCollector = new JButton("Validate Collector");
		btnCreatePacketCollector.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if(mutex)return;
				if(!captureController.getPacketCollectors().contains(collector)){
					captureController.addPacketCollector(collector);
				}
				captureController.removeObserver(that);
				that.setVisible(false);
				that.setEnabled(false);
				that.dispose();
			}
		});
		
		btnCreatePacketCollector.setBounds(180, 310, 210, 30);
		getContentPane().add(btnCreatePacketCollector);
		
		chckbxEnabled = new JCheckBox("Enabled");
		chckbxEnabled.setBounds(190, 50, 113, 25);
		getContentPane().add(chckbxEnabled);
		chckbxEnabled.addActionListener(a->{
			if(mutex)return;
			boolean active = chckbxEnabled.isSelected();
			captureController.setActive(collector, active);
		});
		

		rdbtnTraining = new JRadioButton("Training");
		rdbtnTraining.setBounds(185, 82, 127, 25);
		getContentPane().add(rdbtnTraining);
		rdbtnTraining.addActionListener(a->{
			if(mutex)return;
			captureController.setMode(collector, !rdbtnTraining.isSelected());
		});
		
		rdbtnTesting = new JRadioButton("Testing");
		rdbtnTesting.setBounds(185, 112, 127, 25);
		getContentPane().add(rdbtnTesting);
		rdbtnTesting.addActionListener(a->{
			if(mutex)return;
			captureController.setMode(collector, rdbtnTesting.isSelected());
		});
		

		this.addWindowListener(new WindowAdapter() {
			//Remove Observer, if window is closing
			@Override
			public void windowClosing(WindowEvent e) {
				captureController.removeObserver(that);
				super.windowClosing(e);
			}
		});
		update(null, null);
		this.setLocationRelativeTo(parent);
		
		ButtonGroup group = new ButtonGroup();
		group.add(rdbtnTesting);
		group.add(rdbtnTraining);
	}
	
	@Override
	public void update(Observable o, Object arg) {
		mutex = true;
		/**
		 * Update algorithm name
		 */
		if(collector.getPacketAlgorithm()==null)
			lblAlgorithm.setText("Algorithm: null");
		else
			lblAlgorithm.setText("<html>Algorithm:<br> "+collector.getPacketAlgorithm().getClass().getSimpleName()+"</html>");
		
		/**
		 * Update List of Links
		 */
		/**
		 * Names of the Links
		 */
		String[] linkNames = new String[collector.getLinks().size()];
		if(collector.getLinks().size()!=0){
			Iterator<Link> it = collector.getLinks().iterator();
			for(int i=0;i<collector.getLinks().size();i++){
				if(it.hasNext()){
					Link l = it.next();
					if(l!=null && l.getName()!=null)
						linkNames[i] = l.getName();
					else
						linkNames[i] = "null";
				}else{
					linkNames[i] = "invalid Size";
				}
			}
		}
		/**
		 * New list for the Links
		 */
		JList<String> newList = new JList<String>(linkNames);
		newList.setToolTipText("List of all links, which packets are currently being captured.");
		newList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		/**
		 * ScrollPosition of the ScrollPaneLink
		 */
		int pos = scrollPaneLinks.getVerticalScrollBar().getValue();

		if(listLinks!=null){
			scrollPaneLinks.remove(listLinks);
			newList.setSelectedIndex(listLinks.getSelectedIndex());		
		}
		scrollPaneLinks.setViewportView(newList);
		scrollPaneLinks.getVerticalScrollBar().setValue(pos);
		listLinks = newList;
		
		/**
		 * Update List of Devices
		 */
		/**
		 * Names of the Devices
		 */
		String[] deviceNames = new String[collector.getDevices().size()];
		if(collector.getDevices().size()!=0){
			Iterator<SmartDevice> itD = collector.getDevices().iterator();
			for(int i=0;i<collector.getDevices().size();i++){
				if(itD.hasNext()){
					deviceNames[i] = itD.next().getName();
				}else{
					deviceNames[i] = "invalid Size";
				}
			}
		}
		/**
		 * New list for the Devices
		 */
		newList = new JList<String>(deviceNames);
		newList.setToolTipText("List of all SmartDevices, which packets are currently being captured.");
		newList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		/**
		 * ScrollPosition of the ScrollPaneLink
		 */
		pos = scrollPaneDevices.getVerticalScrollBar().getValue();

		if(listDevices!=null){
			scrollPaneDevices.remove(listDevices);
			newList.setSelectedIndex(listDevices.getSelectedIndex());		
		}
		scrollPaneDevices.setViewportView(newList);
		scrollPaneDevices.getVerticalScrollBar().setValue(pos);
		listDevices = newList;
		
		/**
		 * Manage checkboxes
		 */
		chckbxEnabled.setSelected(collector.isActive());
		rdbtnTesting.setEnabled(collector.isActive());
		rdbtnTesting.setSelected(collector.getMode());
		rdbtnTraining.setEnabled(collector.isActive());
		rdbtnTraining.setSelected(!collector.getMode());		
		
		if(this.edit&&!captureController.getPacketCollectors().contains(collector)){
			/**
			 * If Collector was removed -> Close PopUp
			 */
			this.setEnabled(false);
			this.setVisible(false);
			this.dispose();
			return;
		}
		this.repaint();
		mutex = false;
	}
}
