package cn.net.cpzslibs.prot;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.SocketTimeoutException;
import java.util.Arrays;

import cn.net.test.CRC16Util;

/**
 * 通讯协议帮助类<br/>
 * 1.发送头文件<br/>
 * 2.发送验证信息<br/>
 * 
 * @author zwj
 * 
 *         2015-04-02
 * @version 1.1
 */
public class ProtBase {
	protected short iErrTaskCode = (short) 0xFFFF;// 错误码
	protected String charsetName = "UTF-8";// 
	/**
	 * 包的序列号
	 */
	protected int iSendTaskIndex = 1;
	/**
	 * debug日志信息是否开启
	 */
	private final static boolean isDebug = true;
	/**
	 * 信息日志是否开启
	 */
	private final static boolean isInfo = true;
	/**
	 * 错误日志是否开启
	 */
	private final static boolean isErr = true;
	/**
	 * 接收数据是否完成
	 */
	private boolean success;
	private final String strTag = "@JYMF";

	/**
	 * 任务序号，客户端决定，服务器不解释
	 */
	private int iRecTaskIndex;
	/**
	 * 任务子序号
	 */
	private short iRecTaskSubIndex;
	/**
	 * 任务代码
	 */
	private short iRecTaskCode;
	/**
	 * 包括包尾2字节长度
	 */
	private short iRecBodySize;
	/**
	 * 0：成功 1：失败
	 */
	private short iRecResult;
	/**
	 * 失败码，参考附录1错误代码表
	 */
	private short iRecErrcode;

	/** 工作模式 */
	public static final class WorkType {
		/** 追溯 */
		public static final int Default = 0;
		/** 工厂 */
		public static final int Factory = 1;
		/** 商城 */
		public static final int Mall = 2;
		/** 汽配 */
		public static final int Car = 3;
		/** 书 */
		public static final int Book = 4;
		/** 佛教 */
		public static final int Buddha = 5;
		/** 酒 */
		public static final int Wine = 6;
		/** 快消品 */
		public static final int FastCons = 7;

		/** 东北红酒模式 */
		public static final int RedWine = 10;
	}

	/**
	 * 获取头信息
	 * 
	 * @param dos
	 *            DataOutputStream
	 * @param iTaskCode
	 *            任务代码
	 * @param iBodySize
	 *            包括包尾2字节长度
	 * @throws IOException
	 *             2014-10-22下午1:54:34
	 */
	protected void sendHeader(DataOutputStream dos, short iTaskCode,
			short iBodySize) throws IOException, SocketTimeoutException {
		dos.write(strTag.getBytes("UTF-8"));// sTag
		dos.writeInt(iSendTaskIndex);// iTaskIndex
		dos.writeShort(0);// iTaskSubIndex
		dos.writeShort(iTaskCode);// iTaskCode任务号
		dos.writeShort(iBodySize);// iBodySize
	}

	/**
	 * 发送标签 <br/>
	 * 2015-4-1下午4:20:27
	 * 
	 * @param dos
	 * @param iLabel
	 *            16位追溯码
	 * @throws IOException
	 */
	protected void sendiLabel(DataOutputStream dos, long iLabel)
			throws IOException {
		dos.writeLong(iLabel);
	}

	/**
	 * 发送公司id
	 * 
	 * @param dos
	 * @param iCompanyId
	 *            公司id
	 * @throws IOException
	 */
	protected void sendiCompanyId(DataOutputStream dos, int iCompanyId)
			throws IOException {
		dos.writeInt(iCompanyId);
	}

	/**
	 * 产品id
	 * 
	 * @param dos
	 * @param iProductId
	 *            产品id
	 * @throws IOException
	 */
	protected void sendiProductId(DataOutputStream dos, long iProductId)
			throws IOException {
		dos.writeLong(iProductId);
	}

	/**
	 * 发送地区号
	 * 
	 * @param dos
	 * @param iAreaCode
	 *            地区号
	 * @throws IOException
	 */
	protected void sendiAreaCode(DataOutputStream dos, int iAreaCode)
			throws IOException {
		dos.writeInt(iAreaCode);
	}

	/**
	 * 接收数据
	 * <p>
	 * 2014-12-24上午10:00:30
	 * </p>
	 * 
	 * @param dis
	 * @throws IOException
	 */
	protected void recHeader(DataInputStream dis) throws IOException {
		byte[] sTag = new byte[5];
		int sTagLength = sTag.length;
		for (int i = 0; i < sTagLength; i++) {
			sTag[i] = dis.readByte();
		}
		if (!Arrays.equals(sTag, strTag.getBytes("UTF-8"))) {
			errLog("recHeader", "recHeader-->" + Arrays.toString(sTag));
		}

		this.iRecTaskIndex = dis.readInt();
		this.iRecTaskSubIndex = dis.readShort();
		this.iRecTaskCode = dis.readShort();
		this.iRecBodySize = dis.readShort();
//		System.err.println(" iRecTaskIndex:" + iRecTaskIndex +"   iRecTaskSubIndex:" + iRecTaskSubIndex + "   iRecTaskCode:" + iRecTaskCode +"  iRecBodySize:" + iRecBodySize);
	}

	/**
	 * 获取销售地区的code <br/>
	 * 2015-4-1下午4:33:14
	 * 
	 * @param dis
	 * @return
	 * @throws IOException
	 */
	protected int reciAreadCode(DataInputStream dis) throws IOException {
		return dis.readInt();
	}

	/**
	 * 读取产品Id <br/>
	 * 2015-4-1下午4:34:37
	 * 
	 * @param dis
	 * @return
	 * @throws IOException
	 */
	protected long reciProductId(DataInputStream dis) throws IOException {
		return dis.readLong();
	}

	/**
	 * 接收公司id <br/>
	 * 2015-4-2下午4:50:40
	 * 
	 * @param dis
	 * @return
	 * @throws IOException
	 */
	protected int reciCompanyId(DataInputStream dis) throws IOException {
		return dis.readInt();
	}

	/**
	 * 接收公司id <br/>
	 * 2015-4-2下午4:50:40
	 * 
	 * @param dis
	 * @return
	 * @throws IOException
	 */
	protected long reciLabel(DataInputStream dis) throws IOException {
		return dis.readLong();
	}

	/**
	 * 一个字节一个字节读取
	 * 
	 * @param dis
	 * @param length
	 *            数据的长度
	 * @return
	 * @throws IOException
	 */
	protected byte[] recString(DataInputStream dis, int length)
			throws IOException {
		byte[] bs = new byte[length];
		for (int i = 0; i < length; i++) {
			bs[i] = dis.readByte();
		}
		return bs;
	}

	/**
	 * 一个字节一个字节读取，转换成utf-8形式的String <br/>
	 * 2015-7-15下午4:07:50
	 * 
	 * @param dis
	 * @param length
	 *            数据的长度
	 * @return
	 * @throws IOException
	 */
	protected String getUTF8(DataInputStream dis, int length)
			throws IOException {
		return new String(recString(dis, length), charsetName);
	}

	/**
	 * 打印打印的header信息
	 * <p>
	 * 2014-12-24上午10:18:53
	 * </p>
	 * 
	 * @return
	 */
	protected String toStringRecHeader() {
		return "[iRecTaskIndex=" + iRecTaskIndex + ", iRecTaskSubIndex="
				+ iRecTaskSubIndex + ", iRecTaskCode=" + iRecTaskCode
				+ ", iRecBodySize=" + iRecBodySize + "]";
	}

	/**
	 * 判断接受和发送的iTaskCode是否一致
	 * <p>
	 * 2014-12-24上午10:38:44
	 * </p>
	 * 
	 * @param iSendTaskCode
	 *            发送的协议号
	 * @return
	 */
	protected boolean isTaskCode(short iSendTaskCode) {
		return getiRecTaskCode() == iSendTaskCode;
	}

	/**
	 * 判断是否为通用错误包,是不是等于0xFFFF<br/>
	 * 2014-12-24上午10:37:06
	 * 
	 * @return
	 */
	protected boolean isFFFF() {
		return getiRecTaskCode() == iErrTaskCode;
	}

	/**
	 * 错误包处理 <br/>
	 * 2015-4-2上午10:26:59
	 * 
	 * @param dis
	 * @return
	 * @throws IOException
	 */
	protected boolean recFFFF(DataInputStream dis, short iTaskCode)
			throws IOException {
		if (getiRecTaskCode() == iErrTaskCode) {
			// -1错误包
			iRecResult = dis.readShort();
			iRecErrcode = dis.readShort();
			recCheckCode(dis);
			if (this.iRecResult == 0) {
				// 成功
				this.success = true;
			} else if (this.iRecResult == 1) {
				// 错误
				this.success = false;
				errLog(iTaskCode, "iRecResult:" + iRecResult
						+ " ; iRecErrcode:" + iRecErrcode);
				// TODO 根据错误码来返回错误信息
				switchErrCode(iTaskCode, this.iRecErrcode);
			} else {
				this.success = false;
				// 未知的错误
				errLog(iTaskCode, "iRecResult err :" + iRecResult);
			}
		} else {
			// 未知错误包
			this.success = false;
			errLog(iTaskCode, "unknow err");
		}
		return this.success;
	}

	/**
	 * 错误码返回机制 <br/>
	 * 2015-4-2下午4:21:12
	 * 
	 * @param iTaskCode
	 * @param iErrCode
	 */
	public void switchErrCode(short iTaskCode, short iErrCode) {
		int key = getUnsignedByte(iErrCode);
		// switch (key) {
		// case value:
		//
		// break;
		//
		// default:
		// break;
		// }
	}

	/**
	 * 发送验证码
	 * 
	 * @param dos
	 * @throws IOException
	 */
	protected void sendCheckCode(DataOutputStream dos, Object... objs)
			throws IOException {
		dos.writeShort(0);
	}
	/**
	 * 发送验证码
	 * 
	 * @param dos
	 * @throws IOException
	 */
	protected void sendCheckCoded(DataOutputStream dos, Object... objs)
			throws IOException {
		dos.writeShort(CRC16Util.CRC16((byte[])objs[0]));
//		System.err.println("--crc--:" + CRC16Util.CRC16((byte[])objs[0]));
	}
	/**
	 * 读取iCheckCode
	 * 
	 * @param dis
	 * @return
	 * @throws IOException
	 */
	protected boolean recCheckCode(DataInputStream dis, Object... objs)
			throws IOException {
		dis.readShort();
		return true;
	}

	/**
	 * 统计bodySize 2014-6-24上午10:22:59
	 * 
	 * @param objs
	 * @return
	 */
	protected short countBodySize(Object... objs) {
		int checkCodeSize = 2;// 验证码的2位
		int size = checkCodeSize;
		for (int i = 0; i < objs.length; i++) {
			if (objs[i] instanceof Integer) {
				size = size + 4;
			} else if (objs[i] instanceof Short) {
				size = size + 2;
			} else if (objs[i] instanceof Long) {
				size = size + 8;
			} else if (objs[i] instanceof byte[]) {
				size = size + ((byte[]) objs[i]).length;
			} else if (objs[i] instanceof long[]) {
				size = size + ((long[]) objs[i]).length * 8;// 手持终端用到了这个
			} else if (objs[i] instanceof String) {
				// 适配String类型
				try {
					size = size + String.valueOf(objs[i]).getBytes("UTF-8").length;
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
				}
			}
		}
		return (short) size;
	}

	/**
	 * 将data字节型数据转换为0~65535 (0xFFFF 即 WORD)。
	 * 
	 * @param data
	 * @return
	 */
	protected int getUnsignedByte(short data) {
		return data & 0x0FFFF;
	}

	/**
	 * 展示log
	 * 
	 * @param taskCode
	 *            任务号，或者是位置信息
	 * @param obj
	 *            2014-10-22上午9:23:22
	 */
	protected void debugLog(Object taskCode, Object obj) {
		if (isDebug) {
			System.out
					.println(">" + taskCode.toString() + "<" + obj.toString());
		}
	}

	/**
	 * 临时展示
	 * 
	 * @param obj
	 *            2014-10-22上午9:24:59
	 */
	public static void infoLog(Object obj) {
		if (isInfo) {
			System.out.println(obj.toString());
		}
	}

	/**
	 * 错误信息
	 * 
	 * @param obj
	 *            2014-10-22上午9:24:59
	 */
	protected void errLog(Object iTaskCode, Object obj) {
		if (isErr) {
			System.err.println(">" + iTaskCode.toString() + "<"
					+ obj.toString());
		}
	}

	// ---------------------------------
	protected int getiRecTaskIndex() {
		return iRecTaskIndex;
	}

	/**
	 * 字需要 <br/>
	 * 2015-4-2上午11:06:26
	 * 
	 * @return
	 */
	protected short getiRecTaskSubIndex() {
		return iRecTaskSubIndex;
	}

	/**
	 * 任务号 <br/>
	 * 2015-4-2上午11:06:40
	 * 
	 * @return
	 */
	protected short getiRecTaskCode() {
		return iRecTaskCode;
	}

	/**
	 * 包体size <br/>
	 * 2015-4-2上午11:06:47
	 * 
	 * @return
	 */
	protected int getiRecBodySize() {
		return getUnsignedByte(iRecBodySize);
	}

	// ----------------------
	/**
	 * 0:成功 1:失败
	 */
	protected short getiRecResult() {
		return iRecResult;
	}

	/**
	 * 0:成功 1:失败
	 * 
	 * @return
	 */
	protected boolean isResult() {
		return this.iRecResult == 0;
	}

	/**
	 * 返回错误码 <br/>
	 * 2015-4-1下午4:45:12
	 * 
	 * @return
	 */
	public int getiRecErrcode() {
		return getUnsignedByte(iRecErrcode);
	}

	protected String toStringFFFF() {
		return "[iRecResult=" + iRecResult + ", iRecErrcode=" + iRecErrcode
				+ "]";
	}

	/**
	 * 是否成功 <br/>
	 * 2015-4-1下午5:15:42
	 * 
	 * @return
	 */
	public boolean isSuccess() {
		return success;
	}

	/**
	 * 设置是否成功 <br/>
	 * 2015-4-1下午5:16:02
	 * 
	 * @param isSuccess
	 */
	public void setSuccess(boolean isSuccess) {
		this.success = isSuccess;
	}

	/**
	 * 包的序列号
	 * 
	 * @return
	 */
	public int getiSendTaskIndex() {
		return iSendTaskIndex;
	}
	
	protected byte[] string2bytes(String src) throws UnsupportedEncodingException{
		return src.getBytes("UTF-8");
	}
	/**
	 * 后面补零，返回数组
	 * <br/>2015-9-9下午2:42:13
	 * @param src 
	 * @param iSendBytesSize 发送的数据大小
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	protected byte[] getSendBytes(String src,int iSendBytesSize) throws UnsupportedEncodingException{
		byte[] srcs = string2bytes(src);// 源
		int srcsSize = srcs.length;
		if(iSendBytesSize<srcsSize){
			errLog(0, "iSendBytesSize<srcsSize:"+iSendBytesSize+"<"+srcsSize);
			return null;
		}
		byte[] sendBytes = new byte[iSendBytesSize];// 发送数据
		System.arraycopy(srcs, 0, sendBytes, 0, srcsSize);
		return sendBytes;
	}
}
