package com.backfire.socket;

import java.util.ArrayList;

import com.backfire.doudizhu.common.DdzApplication;
import com.backfire.utils.Log;

public class DataPacket {
	
	public static final int HEADER_SIZE 		= 10;
	public static final int FOOT_SIZE 			= 2;
	public static final int MAX_BODY_LENGTH 	= 16 * 1024;
	public static final int MAX_STRING_LENGTH 	= 8 * 1024;
	public static final int PACKET_INIT_SIZE 	= 1 * 1024;
	public static final int PACKET_EXTEND_SIZE 	= 1 * 1024;
	public static final String EMPTY_STRING = "";
	
	public byte[] bytep1;
	public short s1;
	public int i1;
	public long n1;

	public short cmd;
	public int checksum;
	public byte[] buffer = new byte[PACKET_INIT_SIZE];
	public int position;
	public int readLength;
	public boolean inUse;
	
	public DataEncodeConverter tc = new DataEncodeConverter();
	
	private static ArrayList<DataPacket> list = new ArrayList<DataPacket>();
	private static byte[] sync = new byte[0];
	
	public static DataPacket allocPacket() {
		synchronized (sync) {
			DataPacket packet;
			for (int i = 0; i < list.size(); i++) {
				packet = list.get(i);
				if (!packet.inUse) {
					packet.inUse = true;
					return packet;
				}
			}
			packet = new DataPacket();
			packet.reset();
			list.add(packet);
			packet.inUse = true;
			return packet;
		}
	}
	
	public void recycle() {
		synchronized (sync) {
			reset();
		}
	}
	
	private DataPacket() {
		recycle();
	}
	
	private void reset() {
		position = 0;
		readLength = 0;
		inUse = false;
	}
	public int getLength() {
		return position;
	}
	
	private void realloc(int min) {
		i1 = PACKET_EXTEND_SIZE;
		while (i1 < min) {
			i1 += PACKET_EXTEND_SIZE;
		}
		
		bytep1 = new byte[buffer.length + i1];
		System.arraycopy(buffer, 0, bytep1, 0, position);
		buffer = bytep1;
		bytep1 = null;
	}
	public static DataPacket createMsg(short cmd,byte[] data){
		DataPacket packet = DataPacket.allocPacket();
		
		packet.writeBegin(cmd);
		packet.writeBody(data);
		packet.writeEnd();
		
		return packet;
	}
	public void writeBody(byte[] data) {
		if ((position + data.length) > buffer.length) {
			realloc(data.length);
		}
		System.arraycopy(data, 0, buffer, position, data.length);
		position = position + data.length;
	}
	public void writeBegin(short cmd) {
		this.cmd = cmd;
		position = HEADER_SIZE;
		//首部标识
		buffer[0] = 'B';
		buffer[1] = 'F';
		
		// cmd 2、3
		tc.short2byte(cmd, buffer, 4);

		// checksum 4、5、6、7
		buffer[6]='Q';
		buffer[7]='Q';
		buffer[9]='Q';
		buffer[9]='Q';
		
		Log.i(this, "send cmd:"+SocketCommand.toString(cmd));
	}

	public void writeEnd() {
		//尾部标识
		if ((position + 2) > buffer.length) {
			realloc(2);
		}
		buffer[position] = 'I';
		buffer[position+1] = 'T';
		position +=2;
		// alllen 2、3
		tc.short2byte(position, buffer, 2);
	}
	public byte[] getBuffer() {
		return buffer;
	}

	public void setReadData(short cmd, int checksum,int readLength) {
		this.cmd = cmd;
		this.checksum = checksum;
		this.readLength = readLength;
	}

	public int getCmd() {
		return this.cmd;
	}

	public int getReadLength() {
		return this.readLength;
	}
	
	public byte[] readBody(){
		byte[] tmpbuffer = new byte[readLength-HEADER_SIZE-FOOT_SIZE];
		System.arraycopy(buffer, HEADER_SIZE, tmpbuffer, 0, readLength-HEADER_SIZE-FOOT_SIZE);
		return tmpbuffer;
	}
	
	// for debug
	public void logWrite() {
		if (DdzApplication.getApplication().isDebug()) {
			Log.v(this,
					"send cmd=0x" + Integer.toHexString(cmd) + " seq="
							+ Integer.toString(checksum) + " length="
							+ Integer.toString(position));
			Log.v(this, "send" + tc.toHexString(buffer, 0, position));
		}
	}

	public void logRead() {
		if (DdzApplication.getApplication().isDebug()) {
			Log.v(this,
					"recv cmd=0x" + Integer.toHexString(cmd) + " seq="
							+ Integer.toString(checksum) + " length="
							+ Integer.toString(readLength));
			Log.v(this, "recv"+tc.toHexString(buffer,0,readLength));
		}
	}
}

