package de.tu_darmstadt.tk.SmartHomeNetworkSim.core.simpleImplementation;

import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedList;

import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.Connection;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.Link;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.Packet;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.Port;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.Protocol;

@Deprecated
public class SimpleConnection implements Connection {

	/**
	 * SmartDevice(Port) which is the source of this connection
	 */
	private Port source;
	/**
	 * SmartDevice(Port) which is the destination of this connection
	 */
	private Port destination;
	/**
	 * Link which connects {@code source} and {@code destination}
	 */
	private Link link;
	/**
	 * Protocol, which specifies the packet generation
	 */
	private Protocol p;
	
	/**
	 * Name of the Connection
	 */
	private String name;
	// for Termination
	/**
	 * SmartDevice(Port) which started the termination process
	 */
	private Port srcOfTermination;
	/* *is connection uses
	 * SmartDevice which responds in the termination process
	 */
	// private SmartDevice other;

	/**
	 * Transmission status of the connection
	 */
	private byte status = Connection.ACTIVE;
	
	/**
	 * True if the status of the connection changed during the last simulation step
	 */
	private boolean statusChanged = false;
	
	
	/**
	 * Probability of packet loss. (default: 0.0 -> no packets are lost. 1.0 -> all packets are lost)
	 */
	private double packetLossProbability = 0.0;

	/**
	 * Default label assigned to packets
	 */
	protected short label = 0;
	
	/**
	 * Creates a new connection between two SmartDevice Ports on a given Link, which
	 * communicate with a protocol p
	 * 
	 * @param src
	 *            Port which is the source of this connection
	 * @param dest
	 *            Port which is the destination of this connection
	 * @param link
	 *            Link which connects is connection uses{@code src} and {@code dest}
	 * @param p
	 *            Protocol, which specifies the packet generation
	 */
	public SimpleConnection(Port src, Port dest, Link link, Protocol p) {
		source = src;
		destination = dest;
		this.link = link;
		this.p = p;
		this.name = "SimpleConnection";
	}

	@Override
	public Link getLink() {
		return link;
	}
	
	@Override
	public void setLink(Link link){
		this.link = link;
	}

	@Override
	public Collection<Packet> simulateTimeInterval(long startTime, long duration) {
		LinkedList<Packet> list = new LinkedList<Packet>();
		if(status != ACTIVE)return list;
		list.addAll(getTerminationPackages(startTime));
		if(list.isEmpty())
			statusChanged = true;
		else 
			statusChanged = false;
		//Generate packets by source
		if(source.getLastTrigger()+source.getTriggerInterval()<startTime && source.getStatus()==Port.SENDING){
			list.addAll(p.generateNextPackets(source, startTime,Math.random()<packetLossProbability));
		}
		while(source.getLastTrigger()+source.getTriggerInterval()<startTime+duration &&source.getStatus()==Port.SENDING)
			list.addAll(p.generateNextPackets(source, source.getLastTrigger()+source.getTriggerInterval(),Math.random()<packetLossProbability));
		
		if(destination.getLastTrigger()+destination.getTriggerInterval()<startTime && destination.getStatus()==Port.SENDING){
			list.addAll(p.generateNextPackets(destination, startTime,Math.random()<packetLossProbability));
		}
		while(destination.getLastTrigger()+destination.getTriggerInterval()<startTime+duration &&destination.getStatus()==Port.SENDING)
			list.addAll(p.generateNextPackets(destination, destination.getLastTrigger()+destination.getTriggerInterval(),Math.random()<packetLossProbability));

		list.sort((x,y) -> Long.compare(x.getTimestamp(),y.getTimestamp()));
		return list;
	}

	@Override
	public Collection<Packet> encapsulatePackages(Collection<Packet> packets) {
		return packets;
	}

	@Override
	public Collection<Port> getParticipants() {
		return new LinkedList<Port>(Arrays.asList(source, destination));
	}
	
	@Override
	public Collection<Port> getParticipantsAndRemoved() {
		return new LinkedList<Port>(Arrays.asList(source, destination));
	}

	@Override
	public boolean removeSmartDevice(Port sd) {
		if (sd == source || sd == destination) {
			// of source == null - connection was already terminated
			status = Connection.TERMINATED;
			srcOfTermination = sd;
			return true;
		} else
			return false;
	}

	@Override
	public Collection<Packet> getTerminationPackages(long startTime) {
		if(status!=TERMINATED&&status!=FINISHED)return new LinkedList<Packet>();
		status = DONE;
		return new LinkedList<Packet>(Arrays.asList((Packet) new SimplePacket(
				startTime, srcOfTermination,
				srcOfTermination == source ? destination : source, "Terminated", label)));
	}

	@Override
	public boolean addSmartDevice(Port sd) {
		// Not possible to add Devices
		return false;
	}

	@Override
	public Protocol getProtocol() {
		return p;
	}

	@Override
	public boolean setProtocol(Protocol protocol) {
		return false;

	}

	@Override
	public byte getStatus() {
		return status;
	}

	@Override
	public void setStatus(byte status) {
		this.status = status;
	}

	@Override
	public void setPacketLossProbability(double lossPercentage) {
		packetLossProbability = lossPercentage;
	}

	@Override
	public double getPacketLossProbability() {
		return packetLossProbability;
	}

	@Override
	public boolean getStatusChanged() {
		return statusChanged;
	}

	@Override
	public String getName() {
		return name;
	}

	@Override
	public void setName(String name) {
		this.name = name;
	}

	@Override
	public short getLabel() {
		return label;
	}

	@Override
	public void setLabel(short label) {
		this.label = label;
	}

}
