package de.tu_darmstadt.tk.SmartHomeNetworkSim.core;

import java.util.Collection;

/**
 * Connection between two or more SmartDevices, which sends packages according
 * to a specified protocol
 * 
 * @author Andreas T. Meyer-Berg
 */
public interface Connection {

	// States of the Connection
	/**
	 * Connection won't sent more packets, can be removed from the model
	 */
	public final byte DONE = 0b0;
	/**
	 * Connection active, still sending packets
	 */
	public final byte ACTIVE = 0b1;
	/**
	 * Connection finished by the Protocol as planned
	 */
	public final byte FINISHED = 0b10;
	/**
	 * Connection was terminated not as planned
	 */
	public final byte TERMINATED = 0b11;
	/**
	 * Connection is halted, not sending packets at the moment, but might later
	 */
	public final byte HALTED = 0b100;

	/**
	 * Returns the Link, which the connection uses
	 * 
	 * @return link this connection uses
	 */
	public Link getLink();

	/**
	 * Sets the Link, which the connection uses
	 * 
	 * @param link the link of this connection
	 */
	public void setLink(Link link);

	/**
	 * Returns the SmartDevices that are part of this connection
	 * 
	 * @return SmartDevices participating in this connection
	 */
	public Collection<Port> getParticipants();

	/**
	 * Returns the SmartDevices that are part of this connection, and the removed ones, which did not sent their last packages yet
	 * 
	 * @return SmartDevices participating in this connection, and the removed ones, which haven't sent their terminating packages
	 */
	public Collection<Port> getParticipantsAndRemoved();
	
	/**
	 * Removes the SmartDevice from the Connection. Should create terminating
	 * packages, that are returned on the next call of simulateTimeIntervall.<br> If
	 * the Connection will be fully closed, status should be changed to
	 * FINISHED or TERMINATED and
	 * getTerminationPackages should return the lastPackages that were sent to
	 * terminate the connection. If the connection still continues and the
	 * source was removed, a new Device should become the source. The Calling
	 * Method should remove the Connection in the SmartDevice and add the
	 * Connection to Model.terminatedConnections(), if status changed.
	 * 
	 * @param sd
	 *            SmartDevice to be removed
	 * @return true if the device was removed
	 */
	public boolean removeSmartDevice(Port sd);

	/**
	 * Adds new SmartDevice(Port) to the connection, Caller also has to add it to the protocol.
	 * @param sd Device to be added
	 * @return true if it was added
	 */
	public boolean addSmartDevice(Port sd);

	/**
	 * Simulates the next Simulation interval and returns the packets that were
	 * sent during this interval.
	 * 
	 * @param startTime
	 *            Time the simulation interval starts in
	 *            System.currentTimeMillis() time
	 * @param duration
	 *            Duration of the simulation interval in milliseconds
	 * @return packets that were sent in this interval
	 */
	@Deprecated
	public Collection<Packet> simulateTimeInterval(long startTime, long duration);

	/**
	 * Returns the Packets, created to terminate the connection
	 * 
	 * @param startTime
	 *            Time the simulation interval starts in
	 *            System.currentTimeMillis() time
	 * @return packets that were sent
	 */
	public Collection<Packet> getTerminationPackages(long startTime);

	/**
	 * Encapsulates the given Packets
	 * @param packets Packets which should be encapsulated
	 * @return Encapsulated Packets
	 */
	public Collection<Packet> encapsulatePackages(Collection<Packet> packets);
	
	/**
	 * Returns the Protocol which is used on this Connection
	 * 
	 * @return used Protocol instance
	 */
	public Protocol getProtocol();

	/**
	 * Set the Protocol which is used. Participants have to be updated
	 * 
	 * @param protocol
	 *            new Protocol that shall be used
	 * @return true if it was set
	 */
	public boolean setProtocol(Protocol protocol);

	/**
	 * Returns the current transmission status of the connection.
	 * (FINISHED, ACTIVE, TERMINATED, HALTED)
	 * 
	 * @return transmission status
	 */
	public byte getStatus();

	/**
	 * Set the transmission status of the connection
	 * to FINISHED, ACTIVE, TERMINATED or HALTED
	 * 
	 * @param status
	 *            transmission status
	 */
	public void setStatus(byte status);
	
	/**
	 * Set probability of packet loss. Should be between 0.0 (No packets are lost) and 1.0 (All packets are dropped)
	 * 
	 * @param lossPercentage Probability that packets are lost
	 */
	public void setPacketLossProbability(double lossPercentage);
	
	/**
	 * Returns the probability that packets are lost 
	 * 
	 * @return probability of packet loss (between 0.0 and 1.0
	 */
	public double getPacketLossProbability();
	
	/**
	 * Returns true if the status, or participants changed during the last simulation time step
	 * 
	 * @return true, if status changed
	 */
	public boolean getStatusChanged();
	
	/**
	 * Returns the Name of the connection if set
	 * @return name of the connection
	 */
	public String getName();
	
	/**
	 * Sets the name of the connection
	 * @param name new name of the connection
	 */
	public void setName(String name);
	
	/**
	 * Returns a String representation of the different status values
	 * @param status status to be converted
	 * @return String representation of the status
	 */
	public static String getStatusName(byte status){
		switch (status) {
		case DONE:
			return "DONE";
		case ACTIVE:
			return "ACTIVE";
		case FINISHED:
			return "FINISHED";
		case TERMINATED:
			return "TERMINATED";
		case HALTED:
			return "HALTED";
		default:
			return "unknown";
		}
	}
	
	/**
	 * Returns the default label for packets of this connection represented as a short
	 * @return default label value
	 */
	public short getLabel();
	
	/**
	 * Set the default label value for packets of this connection
	 * @param label new default label value
	 */
	public void setLabel(short label);
}
