package de.tu_darmstadt.tk.SmartHomeNetworkSim.core.protocols.packets;

import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.Packet;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.Port;

/**
 * Packet generated by the MQTT Protocol
 * 
 *
 * @author Andreas T. Meyer-Berg
 */
public class MQTT_packet extends Packet {

	/*
	 * List of the different MQTT packet types, which are the bits 7 to 4 of the
	 * first byte of the packet as specified in MQTT Specification 2.2.1 (MQTT
	 * Control Packet type)<br> The first 4 bits contain the values 0 to F.
	 */
	/*
	 * The second part of the first byte are the Flag Bits. In most control
	 * packets they are 0. The Publish Packet contains DUP, QoS, QoS, RETAIN
	 * bits. PUBREL, SUBSCRIBE and UNSUBSCRIBE contain 0x2 as lower nibble. See
	 * MQTT Section 2.2.2 for further infos.
	 */

	/**
	 * Reserved (forbidden)
	 */
	public static final byte RESERVED = (byte) 0x00;
	/**
	 * Client request to connect to Server (Client-{@literal >}Server)
	 */
	public static final byte CONNECT = (byte) 0x10;
	/**
	 * Connect acknowledgement (Client{@literal <}-Server)
	 */
	public static final byte CONNACK = (byte) 0x20;
	/**
	 * Publish message (Client{@literal <}-{@literal >}Server)
	 */
	public static final byte PUBLISH = (byte) 0x30;
	/**
	 * Publish acknowledgement (Client{@literal <}-{@literal >}Server)
	 */
	public static final byte PUBACK = (byte) 0x40;
	/**
	 * Publish received (assured delivery part 1) (Client{@literal <}-{@literal >}Server)
	 */
	public static final byte PUBREC = (byte) 0x50;
	/**
	 * Publish received (assured delivery part 2) (Client{@literal <}-{@literal >}Server)
	 */
	public static final byte PUBREL = (byte) 0x62;
	/**
	 * Publish received (assured delivery part 3) (Client{@literal <}-{@literal >}Server)
	 */
	public static final byte PUBCOMP = (byte) 0x70;
	/**
	 * Client subscribe request (Client-{@literal >}Server)
	 */
	public static final byte SUBSCRIBE = (byte) 0x82;
	/**
	 * Subscribe acknowledgement (Client{@literal <}-Server)
	 */
	public static final byte SUBACK = (byte) 0x90;
	/**
	 * Unsubscribe request (Client-{@literal >}Server)
	 */
	public static final byte UNSUBSCRIBE = (byte) 0xA2;
	/**
	 * Unsubscribe acknowledgement (Client{@literal <}-Server)
	 */
	public static final byte UNSUBACK = (byte) 0xB0;
	/**
	 * PING request (Client-{@literal >}Server)
	 */
	public static final byte PINGREQ = (byte) 0xC0;
	/**
	 * PING response (Client{@literal <}-Server)
	 */
	public static final byte PINGRESP = (byte) 0xD0;
	/**
	 * Client is disconnecting (Client-{@literal >}Server)
	 */
	public static final byte DISCONNECT = (byte) 0xE0;
	/**
	 * Reserved - forbidden
	 */
	public static final byte RESERVED2 = (byte) 0xF0;

	/*
	 * Packet Content
	 */
	/**
	 * First byte of the MQTT:Packet
	 */
	protected byte controlByte;

	/**
	 * Payload message
	 */
	protected String message = "";

	/**
	 * Creates a new MQTT Packet
	 * 
	 * @param controlType
	 *            specifies the packetType. one of CONNECT, CONNACK, ...
	 * @param timestamp
	 *            time the packet was sent
	 * @param source
	 *            source port of the package
	 * @param destination
	 *            destination port of the packet
	 */
	public MQTT_packet(byte controlType, long timestamp, Port source, Port destination) {
		super(timestamp, source, destination);
		controlByte = controlType;
	}
	
	/**
	 * Creates a new MQTT Packet
	 * 
	 * @param controlType
	 *            specifies the packetType. one of CONNECT, CONNACK, ...
	 * @param timestamp
	 *            time the packet was sent
	 * @param source
	 *            source port of the package
	 * @param destination
	 *            destination port of the packet
	 * @param msg Message of the packet
	 */
	public MQTT_packet(byte controlType, long timestamp, Port source, Port destination, String msg) {
		super(timestamp, source, destination);
		controlByte = controlType;
		message = msg;
	}

	@Override
	public byte[] dumpBytes() {
		return "not implemented".getBytes();
	}

	@Override
	public String getTextualRepresentation() {
		/**
		 * Control type of the MQTT Packet as String
		 */
		String packetType;
		switch (controlByte) {
		case CONNECT:
			packetType="CONNECT";
			break;
		case CONNACK:
			packetType="CONNACK";
			break;
		case PUBLISH:
			packetType="PUBLISH";
			break;
		case PUBACK:
			packetType="PUBACK";
			break;
		case PUBREC:
			packetType="PUBREC";
			break;
		case PUBREL:
			packetType="PUBREL";
			break;
		case PUBCOMP:
			packetType="PUBCOMP";
			break;
		case SUBSCRIBE:
			packetType="SUBSCRIBE";
			break;
		case SUBACK:
			packetType="SUBACK";
			break;
		case UNSUBSCRIBE:
			packetType="UNSUBSCRIBE";
			break;
		case UNSUBACK:
			packetType="UNSUBACK";
			break;
		case PINGREQ:
			packetType="PINGREQ";
			break;
		case PINGRESP:
			packetType="PINGRESP";
			break;
		case DISCONNECT:
			packetType="DISCONNECT";
			break;
		default:
			packetType="RESERVED";
			break;
		}
		return "[MQTT: "+packetType+"; time:"+timestamp+"; source:"+source.getOwner().getName()+"; destination:"+destination.getOwner().getName()+(message==""?"":"; "+message)+"]";
	}

	@Override
	public String getPayload() {
		return "null";
	}

	@Override
	public String getProtocolName() {
		return "MQTT";
	}
}
