package de.tu_darmstadt.tk.SmartHomeNetworkSim.control;

import java.util.LinkedList;
import java.util.Observer;

import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.Link;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.Model;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.PacketCollectionManager;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.PacketCollector;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.PacketSniffer;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.SmartDevice;

/**
 * Controller which controls access to the {@link PacketCollector} and {@link PacketSniffer}
 *
 * @author Andreas T. Meyer-Berg
 */
public class PacketCaptureController {
	/**
	 * Main Controller
	 */
	@SuppressWarnings("unused")
	private Controller controller;
	
	/**
	 * Main model
	 */
	private Model model;
	
	/**
	 * PacketCollectionManager for access to the 
	 */
	private PacketCollectionManager packetCollectionManager;
	
	/**
	 * Creates a new PacketCaptureController
	 * @param controller Main Controller
	 */
	public PacketCaptureController(Model model, Controller controller){
		this.model = model;
		this.controller = controller;
		packetCollectionManager =this. model.getSim().getPacketCollectionManager();
	}
	
	/**
	 * Adds a new PacketController for the given PacketSniffingAlgorithm
	 * @param packetSniffer Packet Sniffer which can process the collected packets
	 * @return the created PacketCollector with PacketSniffer
	 */
	public PacketCollector addPacketCapturer(PacketSniffer packetSniffer){
		PacketCollector collector = new PacketCollector(packetSniffer);
		packetCollectionManager.addPacketCollector(collector);
		notifyObservers();
		return collector;
	}
	
	/**
	 * Returns the PacketCollector, which contains the given PacketSniffer.
	 * Returns null if no collector exists.
	 * @param packetSniffer PacketSniffer which PacketCollector should be returned
	 * @return PacketCollector, which contains the PacketSniffer, null if non was found
	 */
	public PacketCollector getPacketCapturer(PacketSniffer packetSniffer){
		if(packetSniffer == null)
			return null;
		for(PacketCollector collector:packetCollectionManager.getPacketCollectors()){
			if(packetSniffer.equals(collector.getPacketAlgorithm()))
				return collector;
		}
		return null;
	}
	
	/**
	 * Remove packetCollector of the given packetSniffer
	 * @param packetSniffer PacketSniffer to be removed
	 */
	public void removePacketCapturer(PacketSniffer packetSniffer){
		if(packetSniffer == null)
			return;
		PacketCollector packetCollector = null;
		for(PacketCollector collector:packetCollectionManager.getPacketCollectors()){
			if(packetSniffer.equals(collector.getPacketAlgorithm())){
				packetCollector = collector;
				break;	
			}
		}
		if(packetCollector!=null){
			removePacketCollector(packetCollector);
			notifyObservers();
		}
	}
	
	/**
	 * Returns all registered PacketCollectos
	 * @return
	 */
	public LinkedList<PacketCollector> getPacketCollectors(){
		return packetCollectionManager.getPacketCollectors();
	}
	
	/**
	 * Add a packetCollector to the simulation
	 * @param collector packetCollector which should collect packets
	 */
	public void addPacketCollector(PacketCollector collector){
		packetCollectionManager.addPacketCollector(collector);
		notifyObservers();
	}
	
	/**
	 * Removes the given packetCollector from the active Collectors
	 * @param collector collector to be removed
	 */
	public void removePacketCollector(PacketCollector collector){
		packetCollectionManager.removePacketCollector(collector);
		notifyObservers();
	}
	
	/**
	 * Adds a link to a collector, it will collect all packets send via this link
	 * @param collector Collector which should collect packet of the link
	 * @param link Link which should be captured
	 */
	public void addLinkToCollector(PacketCollector collector, Link link){
		if(collector!=null && link != null){
			collector.addLink(link);
			notifyObservers();
		}
	}
	
	/**
	 * Removes a link from a collector, it will no longer collect all packets send via this link
	 * @param collector Collector which should no longer collect the packets of the link
	 * @param link Link which should no longer be captured
	 */
	public void removeLinkFromCollector(PacketCollector collector, Link link){
		if(collector!=null && link != null){
			collector.removeLink(link);
			notifyObservers();
		}
	}
	
	/**
	 * Adds a SmartDevice to a collector, it will collect all packets send via this SmartDevice
	 * @param collector Collector which should collect packets of the Device
	 * @param device Device which packets should be captured
	 */
	public void addDeviceToCollector(PacketCollector collector, SmartDevice device){
		if(collector!=null && device != null){
			collector.addDevice(device);
			notifyObservers();
		}
	}
	
	/**
	 * Removes a link from a collector, it will no longer collect all packets send via this SmartDevice
	 * @param collector Collector which should no longer collect the packets of the Device
	 * @param device SmartDevice which should no longer be captured
	 */
	public void removeDeviceFromCollector(PacketCollector collector, SmartDevice device){
		if(collector!=null && device != null){
			collector.removeDevice(device);
			notifyObservers();
		}
	}
	/**
	 * Returns training or testing mode of the algorithm.
	 * @param collector Collector which is used
	 * @return true if testing or false if training the algorithm.
	 */
	public boolean getMode(PacketCollector collector) {
		if(collector == null) 
			return false;
		return collector.getMode();
	}

	/**
	 * Sets the training or testing mode
	 * @param collector Collector which is used
	 * @param mode true if testing or false if training the algorithm.
	 */
	public void setMode(PacketCollector collector, boolean mode) {
		if(collector == null) return;
		collector.setMode(mode);
		notifyObservers();
	}

	/**
	 * Whether the algorithm should run
	 * @param collector Collector which is used
	 * @return true if algorithm will be executed
	 */
	public boolean isActive(PacketCollector collector) {
		if(collector == null) 
			return false;
		return collector.isActive();
	}

	/**
	 * Set to true, if it should run
	 * @param collector Collector which is used
	 * @param active true if it should be active
	 */
	public void setActive(PacketCollector collector, boolean active) {
		if(collector == null)return;
		collector.setActive(active);
		notifyObservers();
	}
	/**
	 * Notify all observers of the packet collection managers
	 */
	public void notifyObservers(){
		packetCollectionManager.notifyObservers();
	}
	
	/**
	 * Add Observer, will be notified on updates
	 * @param o Observer which should be notified
	 */
	public void addObserver(Observer o){
		packetCollectionManager.addObserver(o);
	}
	
	/**
	 * Remove Observer, which will no longer be notified
	 * @param o Observer to be removed
	 */
	public void removeObserver(Observer o){
		packetCollectionManager.deleteObserver(o);
	}
}
