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

import java.awt.Dimension;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.util.Collection;
import java.util.LinkedList;

import javax.swing.JFrame;

import de.tu_darmstadt.tk.SmartHomeNetworkSim.control.Controller;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.control.ImportController;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.control.NetworkController;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.Link;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.Model;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.SmartDevice;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.simpleImplementation.SimpleLink;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.view.util.JavaFileFilter;

import javax.swing.JFileChooser;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.JComboBox;
import javax.swing.JButton;

/**
 * Link Creation Panels allows creation and editing of Links
 *
 * @author Andreas T. Meyer-Berg
 */
@SuppressWarnings("serial")
public class LinkCreationPanel extends JScrollPane{
	
	/**
	 * Content of the LinkCreation Panel, e.g. all cmbBoxes, Buttons and Textfields
	 */
	private JPanel content;
	/**
	 * Textfield for the name
	 */
	private JTextField tfName;
	/**
	 * Parent window, which is needed for closing operation etc.
	 */
	private Window frame;
	/**
	 * Link which is being created or edited
	 */
	private Link newLink;
	/**
	 * Array of devices which are edited
	 */
	private SmartDevice[] devices;
	/**
	 * True if an existing link is being edited
	 */
	private boolean edit;
	/**
	 * Last SelectedIndex of the LinkType ComboBox
	 */
	private int lastIndex = -1;
	/**
	 * Controller for manipulation of the model
	 */
	private Controller controller;
	/**
	 * Controller for manipulating the network model
	 */
	private NetworkController network;
	/**
	 * Creates a new LinkCreation Panel for editing existing links
	 * @param link link to be edited
	 * @param controller controller to manipulate the link
	 * @param frame parent frame
	 */
	public LinkCreationPanel(Link link, Controller controller, Window frame) {
		this.controller = controller;
		this.network = controller.getNetworkController();
		this.frame = frame;
		newLink = link;
		this.devices = new SmartDevice[link.getDevices().size()];
		int i=0;
		for(SmartDevice d: link.getDevices()){
			this.devices[i++] = d;
		}
		edit = true;
		initializePanel();
	}
	
	/**
	 * Create a new Link from the given Devices
	 * @param devices devices which should be combined to a link
	 * @param controller controller which should be used
	 * @param frame parent frame
	 */
	public LinkCreationPanel(Collection<SmartDevice> devices, Controller controller, Window frame) {
		this.controller = controller;
		this.network = controller.getNetworkController();
		this.frame = frame;
		newLink = new SimpleLink("LinkName");
		this.devices = new SmartDevice[devices.size()];
		int i=0;
		for(SmartDevice d: devices){
			network.addLinkToDevice(newLink, d);
			this.devices[i++] = d;
		}
		edit = false;
		initializePanel();
	}
	
	/**
	 * Initialize the Panel, add all components
	 */
	@SuppressWarnings("unchecked")
	private void initializePanel() {
		frame.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				if(!edit){
					/**
					 * Delete the link, if it is not being edited (And edit wasn't set to true by the createButton action
					 */
					network.deleteLink(newLink);
				}
			}
		});
		LinkedList<Class<? extends Link>> availableLinks = controller.getImportController().getLinks();
		
		setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
		this.setPreferredSize(new Dimension(600, 170 + devices.length*20));
		content = new JPanel();
		content.setPreferredSize(new Dimension(600, 150 + devices.length*20));
		this.setViewportView(content);
		content.setLayout(null);
		
		JLabel lblDescription = new JLabel("Create a new Link");
		lblDescription.setBounds(12, 13, 476, 16);
		content.add(lblDescription);
		
		JLabel lblName = new JLabel("Name:");
		lblName.setHorizontalAlignment(SwingConstants.RIGHT);
		lblName.setBounds(12, 42, 138, 16);
		content.add(lblName);
		
		tfName = new JTextField();
		tfName.setText(newLink.getName());
		tfName.setBounds(162, 39, 300, 22);
		content.add(tfName);
		tfName.setColumns(10);
		tfName.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				newLink.setName(tfName.getText());
			}
		});
		
		JLabel lblLinkType = new JLabel("Type:");
		lblLinkType.setHorizontalAlignment(SwingConstants.RIGHT);
		lblLinkType.setBounds(12, 71, 138, 16);
		content.add(lblLinkType);
		
		JComboBox<String> cmbLinkType = new JComboBox<String>();
		for(Class<? extends Link> linkClass:availableLinks){
			cmbLinkType.addItem(linkClass.getSimpleName());
		}
		int linkCounter = -1;
		for(Class<? extends Link> linkClass:availableLinks){
			linkCounter++;
			if(newLink.getClass().equals(linkClass)){
				cmbLinkType.setSelectedIndex(linkCounter);
				lastIndex = linkCounter;
			}
		}
		cmbLinkType.setBounds(162, 68, 216, 22);
		content.add(cmbLinkType);
		cmbLinkType.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				
				//Set Mutex to true, to disallow changes of roles during the editing
				/**
				 * Imported Link which should be created and configured
				 */
				Link importedLink = network.changeLinkType(newLink, availableLinks.get(
							cmbLinkType.getSelectedIndex()));
				if (importedLink == null) {
					System.out
					.println("WARNING: Invalid Protocol Selected or failure on initialization - restore last index");
					cmbLinkType.setSelectedIndex(lastIndex);
				}else {
					newLink = importedLink;
					lastIndex = cmbLinkType.getSelectedIndex();
				}
			}
		});
		
		JButton btnImportLink = new JButton("Import Link Type");
		btnImportLink.setBounds(390, 67, 144, 25);
		content.add(btnImportLink);
		btnImportLink.addActionListener(a->{
			
			//Filechooser starting in the base directory
			JFileChooser fc = new JFileChooser(new File(System.getProperty("user.dir")));
			fc.setFileFilter(new JavaFileFilter());
			int returnVal = fc.showOpenDialog(this);

	        if (returnVal == JFileChooser.APPROVE_OPTION) {
	        	/**
	        	 * selected File
	        	 */
	            File file = fc.getSelectedFile();
	            String[] parts = file.getName().split("[.]");
	            if(parts.length <= 1)
	            	return;
	            /**
	             * Check the file type
	             */
	            String ending = parts[parts.length-1].toLowerCase();
	            if(ending.equals("java")){
	            	
	            	// Compile source file.
	            	/**
	            	 * Imported Java Class
	            	 */
	            	Class<? extends Link> imported = null;
	            	try {
						imported = (Class<? extends Link>) ImportController.importJavaClass(file);
					} catch (Exception e) {
						e.printStackTrace();
					}
	            	if(imported==null){
	            		System.out.println("WARNING: Importing failed");
	            	}else{
	            		@SuppressWarnings("rawtypes")
						Class[] interfaces = imported.getInterfaces();
	            		boolean isLink = false;
	            		for(int i = 0; i<interfaces.length; i++){
	            			if(interfaces[i] == Link.class)
	            				isLink = true;
	            		}
	            		if(!isLink){
	            			System.out.println("WARNING: No valid Link");
	            			return;
	            		}
	            		//Add Link
	            		if(controller.getImportController().addLink(imported)){
	            			//Update GUI
	            			try {
								cmbLinkType.addItem(imported.getSimpleName());
								availableLinks.add(imported);
							} catch (Exception e1) {
								System.out.println("Adding Protocol to the Links failed");
							}
	            		}else{
	            			System.out.println("Importing into the model failed");
	            		}
	            	}
	            }else{
	            	System.out.println("WARNING: Invalid File Type");
	            	return;
	            }
	        } else {
	           //Importing Cancelled by user
	        }
		});
		
		JButton btnCreate = new JButton("Verify and Create");
		btnCreate.setBounds(121, 103, 206, 25);
		content.add(btnCreate);
		btnCreate.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				//network.addLink(newLink);
				newLink.setName(tfName.getText());
				network.addLink(newLink);
				edit = true;
				content.setVisible(false);
				setVisible(false);
				controller.notifyObservers();
				if(frame != null){
					frame.setVisible(false);
					frame.dispose();
				}
			}
		});
		
		int currentHeight = 150;
		for(int i = 0; i<devices.length;i++){
			int pos = i;
			JLabel lblDevice = new JLabel(devices[i].getName()+":");
			lblDevice.setHorizontalAlignment(SwingConstants.RIGHT);
			lblDevice.setBounds(10, currentHeight, 230, 18);
			content.add(lblDevice);
			
			JComboBox<String> cmbDev = new JComboBox<String>();
			cmbDev.addItem("Connected");
			cmbDev.addItem("Disconnected");
			cmbDev.setBounds(250, currentHeight, 240, 18);
			content.add(cmbDev);
			cmbDev.addActionListener(new ActionListener() {
				
				@Override
				public void actionPerformed(ActionEvent e) {
					if(cmbDev.getSelectedIndex()==0 && !newLink.getDevices().contains(devices[pos])){
						network.addLinkToDevice(newLink, devices[pos]);
					}else if(cmbDev.getSelectedIndex()==1&&newLink.getDevices().contains(devices[pos])){
						network.removeLinkFromDevice(newLink, devices[pos]);
					}
				}
			});
			currentHeight += 20;
		}
	}

	
	 /**
     * Test the Panel
     */
    private static void testGUI() {
        JFrame frame = new JFrame("LinkCreation Panel");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 
        LinkCreationPanel panel;
        
        LinkedList<SmartDevice> devicesOfLink = new LinkedList<SmartDevice>();
        for(int i = 0; i<5; i++)
        	devicesOfLink.add(new SmartDevice("Device" + i));
        panel = new LinkCreationPanel(devicesOfLink, new Controller(new Model()),frame);
        /*
        Link testNet = new SimpleLink("Test Network");
        for(int i = 0; i<5; i++)
        	testNet.addDevice(new SmartDevice("Device" + i));
        panel = new LinkCreationPanel(testNet);
        */
       
        frame.setContentPane(panel);
        frame.pack();
        frame.setVisible(true);
    }
    

 
    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                testGUI();
            }
        });
    }
}