package cz.vutbr.feec.packets.ttp;

import cz.vutbr.feec.packets.PacketGenerateException;
import cz.vutbr.feec.packets.PacketParseException;
import cz.vutbr.feec.packets.PacketUtils;
import org.apache.commons.lang.builder.ToStringBuilder;

public class FTDPacket extends GeneralTTPHeader {

	private long feedbackGroupSize;
	private int height;
	private int status;
	private int parameters;
	private int reserved;
//	private long sessionInformationIP;
	private long FTPort;
	private long reservedEnd;

	public FTDPacket() {
		super(1);
	}
	
	/**
	 * @param version definuje verzi paketu
	 * @param packetType definuje typ paketu FTD=1
	 * @param fbTreeID definuje ID stromu zpětné vazby
	 * @param length definuje délku celého paketu
	 * @param FTport definuje port nadřazeného FT
	 * @param height definuje vrstvu v které FT pracuje
	 * @param status definuje stav práce FT
	 * @param reserved 
	 * @param fbGroupSize velikost skupiny kterou bude FT spravovat
	 * @param reserved2
	 */
	public FTDPacket(int version, int packetType, long fbTreeID, int length, long FTport, 
			int height, int status, int reserved, long fbGroupSize, long reserved2 ) {
		
		setVersion(version);
		setPacketType(packetType);
		setFeedbackTreeId(fbTreeID);
		setLength(length);
		setFTPort(FTport);
		setHeight(height);
		setStatus(status);
		setReserved(reserved);
		setFeedbackGroupSize(fbGroupSize);
		setReservedEnd(reserved2);
		
	}

	/**
	 * Generate buffer of values in FTA header. <i>This method generates
	 * specific size of bytes into the buffer.</i>
	 * 
	 * @param resultArray -
	 *            memory bytes for generating buffer
	 * @param startPos -
	 *            starting position in the resultArray
	 */
	@Override
	public int generate(byte[] resultArray, int startPos)
			throws PacketGenerateException {
		int length = super.generate(resultArray, startPos);
		length += generateRestFTD(resultArray, startPos + length);
		return length;
	}

	private int generateRestFTD(byte[] buffer, int offset) {
		assert PacketUtils.checkSize(this.getFeedbackGroupSize(), 16);
		assert PacketUtils.checkSize(this.getHeight(), 3);
		assert PacketUtils.checkSize(this.getStatus(), 5);
		assert PacketUtils.checkSize(this.getParameters(), 4);
		assert PacketUtils.checkSize(this.getReserved(), 4);
//		assert PacketUtils.checkSize(this.getSessionInformationIP(), 32);
		assert PacketUtils.checkSize(this.getFTPort(), 16);
		assert PacketUtils.checkSize(this.getReservedEnd(), 16);

		// adding Feedback group size to buffer

		PacketUtils.setOctet2(buffer, offset, this.getFeedbackGroupSize());
		// adding Priority and Feedback size
		byte Pri_Fsize = (byte) (((this.getHeight() << 5) & 0xE0) | (this
				.getStatus() & 0x1F));

		buffer[offset + 2] = Pri_Fsize;

		// adding Priority and Feedback size
		byte Par_Res = (byte) (((this.getParameters() << 4) & 0xF0) | (this
				.getReserved() & 0x0F));

		buffer[offset + 3] = Par_Res;

/*		PacketUtils.setOctet4(buffer, offset + 4, this
				.getSessionInformationIP());
*/
		PacketUtils.setOctet2(buffer, offset + 4, this.getFTPort());

		PacketUtils.setOctet2(buffer, offset + 6, this.getReservedEnd());
		
		// zbytek hlavicky zabere celkem 64 bitu
		// rest of the header takes 64 bits
		return 2 * 4;
	}

	/**
	 * Parsing FTA header values from buffer. <i>This method takes specific
	 * number of bytes from buffer and parse them into FTA header values. </i>
	 * 
	 * @param resultArray -
	 *            memory bytes for parsing the values
	 * @param startPos -
	 *            starting position in resultArray
	 * @param length -
	 *            length of header
	 */
	@Override
	public int parse(byte[] resultArray, int startPos, int length)
			throws PacketParseException {
		int len = super.parse(resultArray, startPos, length);
		len += this.parseRestFTD(resultArray, startPos, length);
		return len;
	}

	private int parseRestFTD(byte[] resultArray, int startPos, int length)
			throws PacketParseException {

		this.setFeedbackGroupSize(PacketUtils.getOctet2(resultArray,
				4 + startPos));
		int second = PacketUtils.getOctet1(resultArray, 6 + startPos);
		this.setHeight((second & 0xE0) >> 5);
		this.setStatus(second & 0x1F);
		second = PacketUtils.getOctet1(resultArray, 7 + startPos);
		this.setParameters((second & 0xF0) >> 4);
		this.setReserved(second & 0x0F);
/*
		this.setSessionInformationIP(PacketUtils.getOctet4(resultArray,
				8 + startPos));
*/
		this.setFTPort(PacketUtils.getOctet2(resultArray, 8 + startPos));
		this.setReservedEnd(PacketUtils.getOctet2(resultArray, 10 + startPos));

		return 2 * 4;
	}

	public void setFeedbackGroupSize(long fbgs) {
		this.feedbackGroupSize = fbgs;
	}

	public long getFeedbackGroupSize() {
		return this.feedbackGroupSize;
	}

	public void setHeight(int height) {
		this.height = height;
	}

	public int getHeight() {
		return this.height;
	}

	public void setStatus(int stat) {
		this.status = stat;
	}

	public int getStatus() {
		return this.status;
	}

	public void setParameters(int param) {
		this.parameters = param;
	}

	public int getParameters() {
		return this.parameters;
	}

	public void setReserved(int rsrvd) {
		this.reserved = rsrvd;
	}

	public int getReserved() {
		return this.reserved;
	}

/*	public void setSessionInformationIP(long siip) {
		this.sessionInformationIP = siip;
	}

	public long getSessionInformationIP() {
		return this.sessionInformationIP;
	}
*/
	public void setFTPort(long sprt) {
		this.FTPort = sprt;
	}

	public long getFTPort() {
		return this.FTPort;
	}

	public void setReservedEnd(long rsrvdend) {
		this.reservedEnd = rsrvdend;
	}

	public long getReservedEnd() {
		return this.reservedEnd;
	}

	/**
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return new ToStringBuilder(this).append("reservedEnd", this.reservedEnd).append("sessionPort",
						this.FTPort).append("feedbackTreeId",
						this.getFeedbackTreeId()).append("parameters",
						this.parameters).append("feedBackSize",
						this.getStatus()).append("version",
						this.getVersion()).append("priority", this.height)
				.append("reserved", this.reserved).append("packetType",
						this.getPacketType())
				.append("length", this.getLength()).append("feedbackGroupSize",
						this.feedbackGroupSize).toString();
	}

}
