package de.tu_darmstadt.tk.SmartHomeNetworkSim.core;

import java.util.Collection;
import java.util.LinkedList;
import java.util.Observable;
import java.util.stream.Collectors;

/**
 * The PacketCollectionManager, which stores all the active {@link PacketCollector} and adds their packets after each {@link SimulationManager#simulateTimeIntervall(long, long)} step.
 * 
 *
 * @author Andreas T. Meyer-Berg
 */
public class PacketCollectionManager extends Observable {
	/**
	 * All collectors registered in the framework
	 */
	private LinkedList<PacketCollector> collectors = new LinkedList<PacketCollector>();
	
	/**
	 * Model used by the framework
	 */
	private Model model;
	
	/**
	 * Initializes a PacketCollectionManager for the framework
	 */
	public PacketCollectionManager(Model model) {
		this.model = model;
	}
	
	/**
	 * Let all packet collectors collect their packets
	 */
	public void collectPackets(){
		/**
		 * Let all collectors collect
		 */
		for(PacketCollector col: collectors){
			col.resetPackets();
			if(!col.isActive())continue;
			/**
			 * Add all links, which packets should be collected
			 */
			Collection<Link> links = col.getLinks();
			/**
			 * Devices which packets should be collected
			 */
			LinkedList<SmartDevice> devices = new LinkedList<SmartDevice>(col.getDevices());
			for(Link link: model.getConnectionNetworks()){
				/**
				 * Collect all packets of the links, which should be collected
				 */
				if(links.contains(link)){
					col.addPackets(link, link.getPackets());
				}else if(!devices.isEmpty()){
					/**
					 * Devices which are part of the link and should be collected by the PacketCollector
					 */
					LinkedList<SmartDevice> linkDevices = new LinkedList<SmartDevice>(link.getDevices());
					linkDevices.retainAll(devices);
					/**
					 * Check packets just if devices, which are part of the link, should be collected
					 */
					if(!linkDevices.isEmpty())
						col.addPackets(link, link.getPackets().stream().filter(col.getFilter()).collect(Collectors.toList()));
				}
			}
			
		}
	}
	
	/**
	 * Runs all registered PacketAlgorithms of the different collectors
	 */
	public void runPacketAlgorithms(){
		for(PacketCollector collector:collectors){
			if(collector.isActive() && collector.getPacketAlgorithm()!=null){
				collector.getPacketAlgorithm().processPackets(collector.getPackets());
			}
		}
	}
	
	/**
	 * Adds a packetCollector, which will collect packages from now on
	 * @param collector new package collector
	 */
	public void addPacketCollector(PacketCollector collector){
		if(!collectors.contains(collector))
			collectors.add(collector);
	}
	
	/**
	 * Returns the packet collectors, which are collecting packets
	 * @return active packet collectors
	 */
	public LinkedList<PacketCollector> getPacketCollectors(){
		return collectors;
	}
	
	/**
	 * Removes the given packet collector, it will no longer collect packets
	 * @param collector collector to be removed
	 */
	public void removePacketCollector(PacketCollector collector){
		collectors.remove(collector);
	}

	/**
	 * Notify all observers
	 */
	public void notifyObservers(){
		this.setChanged();
		this.notifyObservers(null);
	}
}
