package org.kne.cloud.network.srv6;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

import org.kne.cloud.network.NetworkPacket;

public abstract class KLALBRoutingProtocolPacket extends NetworkPacket {
	public static final int RINFO_REQ=0;
	public static final int RINFO=1;
	public static final int JSON_DATA=2;

	private static final int HEADER_CAPACITY = 32;
	
	
	//public static final ByteArrayPool dataarraypool=new ByteArrayPool(5000, 8192);
	
	protected volatile ByteBuffer header;

	
	
	protected KLALBRoutingProtocolPacket(ByteBuffer header) {
		super();
		this.header = header;
	}
	
	public KLALBRoutingProtocolPacket(int type) {
		super();
		header=NetworkPacket.bufferAllocator.allocate(40);
		header.put((byte) type);
	}
	@Override
	public String toString() {
		return "KLALBRoutingProtocolPacket [type=" + getType() + "]";
	}
	public int getType() {
		return header.get(0)&0xff;
	}
	
	private long sndtime,rcvtime;
	
	
	
	public void writeToChannel(WritableByteChannel dto) throws IOException {
		sndtime=System.nanoTime();
		dto.write(header.slice(0, (int) getHeaderSize()));
	}
	
	@Override
	protected boolean needEndPosition() {
		return false;
	}

	public void readFromChannel(ReadableByteChannel din,long length) throws IOException {
		rcvtime=System.nanoTime();
		//System.out.println(this+" "+getHeaderSize());
		header.limit((int) getHeaderSize());
		while(header.hasRemaining()){
		if(din.read(header)==-1) {
			throw new EOFException();
		}
		}
	}
	
	protected long getHeaderSize() {
		return 1;
	}
	public long getSndtime() {
		return sndtime;
	}
	public long getRcvtime() {
		return rcvtime;
	}
	public long getTotalLength() {
		return getHeaderSize();
	}

	

	protected ByteBuffer getHeader() {
		return header;
	}

	
	public static KLALBRoutingProtocolPacket readKLALBPacketFromStream(DataInputStream in) throws IOException {
		return readKLALBPacketFromChannel(Channels.newChannel(in));
	}
	
	public static KLALBRoutingProtocolPacket readKLALBPacketFromChannel(ReadableByteChannel in) throws IOException {
		while(true) {
		ByteBuffer bb=NetworkPacket.bufferAllocator.allocate(40);
		bb.limit(1);
		 while(bb.hasRemaining()){
		if(in.read(bb)==-1) {
			return null;
		}
		}
		int type=bb.get(0);
				bb.limit(bb.capacity());
				
				KLALBRoutingProtocolPacket klp;
				switch(type) {
				case RINFO_REQ:
					klp=new RouterInfoRequestPacket(bb);
					klp.readFromChannel(in);
					return klp;
				case RINFO:
					klp=new RouterInfoPacket(bb);
					klp.readFromChannel(in);
					return klp;
				case JSON_DATA:
					klp=new JsonDataPacket(bb);
					klp.readFromChannel(in);
					return klp;
				}
				//throw new StreamCorruptedException("unknown package type:"+type);
				System.err.println("ignore unknown KLALBRoutingProtocolPacket type:"+type);
		}
			}
	
	public static void writeKLALBPacketToStream(DataOutputStream out,KLALBRoutingProtocolPacket klb) throws IOException {
		writeKLALBPacketToChannel(Channels.newChannel(out),klb);
	}
	public static void writeKLALBPacketToChannel(WritableByteChannel writableByteChannel,KLALBRoutingProtocolPacket klb) throws IOException {
		klb.writeToChannel(writableByteChannel);
	}
}
