package org.kne.cloud.network.ipv6;

import java.io.EOFException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;

import org.kne.cloud.network.NetworkPacket;

public class TLV  extends NetworkPacket{
	
private int headerLength=2;

public static final int PAD1=0;
	public TLV(ByteBuffer header, boolean isDefault) {
		this.header=header;
		this.isDefault=isDefault;
		if(getType()==PAD1)
			setHeaderLength(1);
		if(isDefault&&(getHeaderLength()>1)) {
			data=NetworkPacket.bufferAllocator.allocate(256);
		}
}

	public TLV(int type, boolean isDefault) {
		if(type==PAD1) {
			setHeaderLength(1);
		}
		this.header=NetworkPacket.bufferAllocator.allocate(getHeaderLength());
		this.isDefault=isDefault;
		header.put((byte) type);
		header.put((byte) 0);
		header.flip();
		if(isDefault&&(getHeaderLength()>1)) {
			data=NetworkPacket.bufferAllocator.allocate(256);
		}
	}

	public int getHeaderLength() {
		return headerLength;
	}

	private boolean isDefault;
	
	protected ByteBuffer header;
	
	private ByteBuffer data;
	
	
	
	public ByteBuffer getData() {
		return data;
	}
	
	@Override
	public long getTotalLength() {
		return getHeaderLength()+(isDefault?data.limit():0);
	}
	@Override
	public void writeToChannel(WritableByteChannel dto) throws IOException {
		if(isDefault&&(getHeaderLength()>1)) {
			setDataLength(data.limit());
			}
			header.limit(getHeaderLength());
			dto.write(header.slice(0,header.limit()));
			if(isDefault&&(getHeaderLength()>1)) {
				dto.write(data.slice(0, data.limit()));
			}
	}

	@Override
	public void readFromChannel(ReadableByteChannel din, long length) throws IOException {
		
		header.limit(1);
		while (header.hasRemaining()) {
			if (din.read(header) == -1) {
				throw new EOFException();
			}
		}
		if(getHeaderLength()>1) {
			header.limit(2);
			while (header.hasRemaining()) {
				if (din.read(header) == -1) {
					throw new EOFException();
				}
			}
		}
		header.flip();
		
		if(isDefault&&(getHeaderLength()>1)) {
		data.clear();
		data.limit(getDataLength());
		 while(data.hasRemaining()){
				if(din.read(data)==-1) {
					throw new EOFException();
				}
				}
		 data.flip();
		}
	}

	@Override
	protected boolean needEndPosition() {
		return false;
	}

	public int getType() {
		return header.get(0)&0xff;
	}
	public void setType(int type) {
		header.put(0,(byte) type);
	}
	
	public int getDataLength() {
		return header.get(1)&0xff;
	}
	
	public void setDataLength(int dataLength) {
		header.put(1,(byte) dataLength);
	}

	public void setHeaderLength(int headerLength) {
		this.headerLength = headerLength;
	}

	@Override
	public String toString() {
		return "TLV [getType()=" + getType() + ", getDataLength()=" + getDataLength() + "]";
	}
	
}
