package org.kne.cloud.network.klalb;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.StreamCorruptedException;
import java.util.Objects;
import java.util.zip.CRC32;

import javax.sound.sampled.Port;

public class DATATPacket extends KLALBPacket implements Comparable<DATATPacket>,PortPacket{
	public static final ByteArrayRecycle arrayRecycle=new ByteArrayRecycle(5000,65535);
	@Override
	public long getLength() {
		return super.getLength()+19+size;
	}

	private int sport,dport;
	private long number;
	private int size;
	private byte[]data;
	private int sendcount;

	volatile long resendtimer=System.nanoTime();
	
	public DATATPacket(int sport,int dport,long number,byte[]data,int size) {
		super(DATAT);
		this.sport=sport;
		this.dport=dport;
		this.number=number;
		this.data=data;
		this.size=size;
	}

	public int getSendcount() {
		return sendcount;
	}

	public DATATPacket() {
		super(DATAT);
	}

	public int getSport() {
		return sport;
	}

	public int getDport() {
		return dport;
	}

	public long getNumber() {
		return number;
	}

	public byte[] getData() {
		return data;
	}

	@Override
	public String toString() {
		return "DATAT "+sport+"->"+dport+" "+number+"["+size+"]";
	}
	 private final byte[] writeBuffer = new byte[19];
	@Override
	protected void writeToStream(DataOutput dto) throws IOException {
		super.writeToStream(dto);
		/*dto.writeInt(sport);
		dto.writeInt(dport);
		dto.writeLong(number);
		dto.writeByte(getSendRecord().size());
		dto.writeChar(size);*/
		
		writeBuffer[0] = (byte)(sport >>> 24);
        writeBuffer[1] = (byte)(sport >>> 16);
        writeBuffer[2] = (byte)(sport >>>  8);
        writeBuffer[3] = (byte)(sport >>>  0);
        
    	writeBuffer[4] = (byte)(dport >>> 24);
        writeBuffer[5] = (byte)(dport >>> 16);
        writeBuffer[6] = (byte)(dport >>>  8);
        writeBuffer[7] = (byte)(dport >>>  0);

        writeBuffer[8] = (byte)(number >>> 56);
        writeBuffer[9] = (byte)(number >>> 48);
        writeBuffer[10] = (byte)(number >>> 40);
        writeBuffer[11] = (byte)(number >>> 32);
        writeBuffer[12] = (byte)(number >>> 24);
        writeBuffer[13] = (byte)(number >>> 16);
        writeBuffer[14] = (byte)(number >>>  8);
        writeBuffer[15] = (byte)(number >>>  0);
        
        writeBuffer[16]=(byte) getSendRecord().size();
        
        writeBuffer[17]=(byte) (size>>>8);
        writeBuffer[18]=(byte) (size>>>0);
		dto.write(writeBuffer);
        //CRC32 crc=new CRC32();
       // crc.update(data, 0, size);
		dto.write(data,0,size);
		//dto.writeLong(crc.getValue());
	}

	 private final byte[] readBuffer = new byte[19];
	@Override
	protected void readFromStream(DataInput din) throws IOException {
		super.readFromStream(din);
		/*sport=din.readInt();
		dport=din.readInt();
		number=din.readLong();
		sendcount=din.readUnsignedByte();
		size=din.readChar();*/
		
		din.readFully(readBuffer);
		sport=((readBuffer[0] << 24) + (readBuffer[1] << 16) + (readBuffer[2] << 8) + (readBuffer[3] << 0));
		dport=((readBuffer[4] << 24) + (readBuffer[5] << 16) + (readBuffer[6] << 8) + (readBuffer[7] << 0));
		number=(((long)readBuffer[8] << 56) +
                ((long)(readBuffer[9] & 255) << 48) +
                ((long)(readBuffer[10] & 255) << 40) +
                ((long)(readBuffer[11] & 255) << 32) +
                ((long)(readBuffer[12] & 255) << 24) +
                ((readBuffer[13] & 255) << 16) +
                ((readBuffer[14] & 255) <<  8) +
                ((readBuffer[15] & 255) <<  0));
		sendcount=readBuffer[16]&0xff;
		size=(((readBuffer[17]&0xff) << 8) + ((readBuffer[18]&0xff) << 0));
		
		data=arrayRecycle.create();
		din.readFully(data,0,size);
		/*CRC32 crc32=new CRC32();
		crc32.update(data, 0, size);
		if(din.readLong()!=crc32.getValue()) {
			throw new StreamCorruptedException("CRC32 error!");
		}*/
	}
	@Override
	public int hashCode() {
		return Objects.hash(number);
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		DATATPacket other = (DATATPacket) obj;
		return number == other.number;
	}

	public int getSize() {
		return size;
	}

	@Override
	public int compareTo(DATATPacket o) {
		if(number>o.number) {
			return 1;
		}else if(number<o.number){
			return -1;
		}else {
		return 0;
		}
	}
}
