import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map.Entry;

import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.Link;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.Packet;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.PacketSniffer;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.SmartDevice;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.protocols.packets.MQTT_packet;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.protocols.packets.Ping_packet;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.simpleImplementation.SimplePacket;

/**
 * Metric which can be used as PacketSniffer. Will count the number of packets sent per Link. 
 * Furthermore statistics like number of packets sent between different devices, number of packets 
 * per type etc. will be printed to the console.
 *
 * @author Andreas T. Meyer-Berg
 */
public class CountingMetric implements PacketSniffer {

	@Override
	public void processPackets(HashMap<Link, LinkedList<Packet>> packets) {
		System.out.println("Counting Metric: ");
		if(packets==null)return;
		/**
		 * Print all links and their number of packets sent
		 */
		for(Entry<Link, LinkedList<Packet>> e:packets.entrySet()){
			if(e == null || e.getKey() == null || e.getValue() == null)continue;
			//System.out.println(e.getKey().getName()+": "+e.getValue().size()+" Packets");
			printStatistics(e.getValue());
		}
		System.out.println("");

	}
	/**
	 * Calculates and prints statistics for the given packets
	 * @param packets Packets which should be evaluated
	 */
	private void printStatistics(LinkedList<Packet> packets){
		//Calculate first and last packet time
		/**
		 * Timestep the first packet was sent
		 */
		long minTime = Long.MAX_VALUE;
		/**
		 * Timestep the last pacekt was sent
		 */
		long maxTime = Long.MIN_VALUE;
		/**
		 * Number of ping packets
		 */
		int pingPackets = 0;
		/**
		 * Number of ping packets
		 */
		int mqttPackets = 0;
		/**
		 * Number of MQTT packets
		 */
		int simplePackets = 0;
		/**
		 * Number of unknown packets
		 */
		int unknownPackets = 0;
		//HashMap for packets per collection
		HashMap<SmartDevice,HashMap<SmartDevice,Integer>> connections = new HashMap<SmartDevice, HashMap<SmartDevice, Integer>>();
		for(Packet p: packets){
			minTime = Math.min(minTime, p.getTimestamp());
			maxTime = Math.max(maxTime, p.getTimestamp());
			if(p instanceof MQTT_packet)
				mqttPackets++;
			else if(p instanceof Ping_packet)
				pingPackets++;
			else if(p instanceof SimplePacket)
				simplePackets++;
			else
				unknownPackets++;
			HashMap<SmartDevice,Integer> map = connections.get(p.getSource().getOwner());
			if(map == null)
				map = new HashMap<SmartDevice, Integer>();
			//Increment counter for each packet by on. Add HashMap/Numbers if number non existent
			Integer lastVal = map.get(p.getDestination().getOwner());
			int i = lastVal == null?0:lastVal;
			map.put(p.getDestination().getOwner(), i+1);
			connections.put(p.getSource().getOwner(), map);
		}
		// Print number of packets per Protocol Type
		System.out.println("In Total "+packets.size()+" Packets were sent.");
		if(mqttPackets != 0){
			if(mqttPackets==packets.size()){
				System.out.println("All of them were MQTT packets");
			}else{
				System.out.println(mqttPackets+ "("+Math.round(mqttPackets*100.0/packets.size())+"%) of them were MQTT packets");
			}
		}
		if(pingPackets != 0){
			if(pingPackets==packets.size()){
				System.out.println("All of them were ping packets");
			}else{
				System.out.println(pingPackets+ "("+Math.round(pingPackets*100.0/packets.size())+"%) of them were ping packets");
			}
		}
		if(simplePackets != 0){
			if(simplePackets==packets.size()){
				System.out.println("All of them were simple packets");
			}else{
				System.out.println(simplePackets+ "("+Math.round(simplePackets*100.0/packets.size())+"%) of them were simple packets");
			}
		}
		if(unknownPackets != 0){
			if(unknownPackets==packets.size()){
				System.out.println("All of them were unknown packets");
			}else{
				System.out.println(unknownPackets+ "("+Math.round(unknownPackets*100.0/packets.size())+"%) of them were unknwon packets");
			}
		}
		if(minTime<=maxTime)
			System.out.println("First packet was captured at "+minTime+" ms, and the last at "+maxTime+" ms.");
		else
			System.out.println("No packets were captured.");
		//Print the number of packets per connection
		for (Entry<SmartDevice, HashMap<SmartDevice, Integer>>  e: connections.entrySet()) {
			String src = e.getKey() == null || e.getKey().getName()==null ? "null":e.getKey().getName();
			System.out.println(src + " sent:");
			for (Entry<SmartDevice, Integer>  f: e.getValue().entrySet()) {
				String dest = f.getKey() == null || f.getKey().getName()==null ? "null":f.getKey().getName();
				System.out.println(f.getValue() + " packets to "+dest);
			}
		}
		
		
	}
}