package com.mq.mylibrary.rfid.io.cmd;

import com.fntech.RInt;
import com.mq.mylibrary.rfid.io.service.Tools;
import com.mq.mylibrary.rfid.io.translate.Apdu;
import com.mq.mylibrary.rfid.io.translate.Fmcos;
import com.mq.mylibrary.rfid.io.translate.ISO1443Constant;
import com.mq.mylibrary.rfid.io.translate.TxApdu;
import com.mq.mylibrary.rfid.io.util.ByteUtils;

import java.io.IOException;

public class _14443ACommApi {

	static byte ISO14443A_BASE_ERROR = -5;
	static byte ISO14443A_NOTOPEN_ERROR = (byte) (TXFRAME.TX_END_ERROR + ISO14443A_BASE_ERROR - 1);
	static byte ISO14443A_INIT_LOAD_ERROR = (byte) (ISO14443A_NOTOPEN_ERROR - 1);
	static byte ISO14443A_CREDIT_LOAD_ERROR = (byte) (ISO14443A_INIT_LOAD_ERROR - 1);
	static byte ISO14443A_INIT_VALUE_ERROR = (byte) (ISO14443A_INIT_LOAD_ERROR - 2);
	/*************************************************************************/
	static byte ISO14443A_USEUSBHID = 0;
	static byte ISO14443A_USECOMM = 1;

	static byte ISO14443A_CHALLENGE_LONG = 0x08;
	// /卡类型ATQ
	static byte ISO14443A_MIFARE_ULTRALIGHT = 0x0044;
	// /卡类型ATQ
	byte ISO14443A_MIFARE_S50 = 0x0004;
	// 长字节UID
	static byte ISO14443A_LONG_UID_LEN = 7;

	static int TX_BUF_LEN = 256 * 2;

	/**
	 * 读版本
	 * @return
	 */
	public static String ISO14443A_ReadVersion() {
		TXFRAME frame = new TXFRAME();
		int nResult = -1;
		String ver = null;

		TXFRAME.tx_make_version(frame);

		try {
			nResult = _14443AComm.ISO14443A_Comm(frame, 0);
			if (nResult == 0) {
				byte[] tmp = new byte[frame.rx_len];
				System.arraycopy(frame.rx_data, 0, tmp, 0, tmp.length);
				ver = new String(tmp);
			} else {
				ver = null;
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return ver;
	}

	/**
	 * 初始化M1卡  读UID
	 * @param card_type
	 * @param uid
	 * @param len
	 * @return
	 */
	public static int ISO14443A_InitMifare(RInt card_type, byte[] uid, RInt len) {
		int nResult = -1;
		byte[] buf = new byte[256];

		// nResult = ISO14443A_Request();
		nResult = ISO14443A_RequestEx(card_type);
		// Log.i("ISO14443A_RequestEx", nResult+"");
		if (nResult != 0)
			return nResult;

		nResult = ISO14443A_GetUID(buf);
		// Log.i("ISO14443A_GetUID", nResult+"");
		if (nResult != 0)
			return nResult;

		nResult = ISO14443A_SelectTag(buf);
		// Log.i("ISO14443A_SelectTag", nResult+"");
		if (nResult != 0)
			return nResult;

		// M0卡
		if ((byte) card_type.value == ISO14443A_MIFARE_ULTRALIGHT) {
			System.arraycopy(buf, 1, uid, 0, 3);

			nResult = ISO14443A_GetUID2(buf);
			if (nResult != 0)
				return nResult;

			nResult = ISO14443A_SelectTag2(buf);
			if (nResult != 0)
				return nResult;

			System.arraycopy(buf, 0, uid, 3, 4);
			len.value = ISO14443A_LONG_UID_LEN;
		} else {
			len.value = TXFRAME.ISO14443A_UID_LEN;
			System.arraycopy(buf, 0, uid, 0, TXFRAME.ISO14443A_UID_LEN);
		}

		return 0;
	}

	/**
	 * 认证M1卡
	 * @param aorb
	 * @param block
	 * @param uid
	 * @param key
	 * @return
	 */
	public static int ISO14443A_Authentication(byte aorb, byte block, byte[] uid, byte[] key) {
		int nResult = -1;

		nResult = ISO14443A_LoadKey(key);
		if (nResult != 0)
			return nResult;

		nResult = ISO14443A_Authentication1(aorb, block, uid);
		if (nResult != 0)
			return nResult;

		nResult = ISO14443A_Authentication2();
		if (nResult != 0)
			return nResult;

		return 0;
	}

	/**
	 * 读单块
	 * @param block
	 * @param buf
	 * @param card_type
	 * @return
	 */
	public static int ISO14443A_ReadBlock(byte block, byte[] buf, int card_type) {
		int nResult = -1;
		TXFRAME frame = new TXFRAME();

		TXFRAME.tx_make_read_block(frame, block);

		nResult = ISO14443A_WriteReadAPDUFrame(frame);
		if (nResult == 0) {
			if (card_type == 0x0044) {
				System.arraycopy(frame.rx_data, 0, buf, 0, buf.length);
			} else {
				System.arraycopy(frame.rx_data, 0, buf, 0, frame.rx_len);
			}
		}

		return nResult;
	}

	/**
	 * 写M1卡
	 * @param block
	 * @param buf
	 * @param card_type
	 * @return
	 */
	public static int ISO14443A_WriteBlock(byte block, byte[] buf, int card_type) {
		int nResult = -1;

		nResult = ISO14443A_WriteBlock1(block);
		if (nResult != 0)
			return nResult;

		nResult = ISO14443A_WriteBlock2(buf, card_type);
		if (nResult != 0)
			return nResult;

		return 0;
	}

	/**
	 * 读多块
	 * @param uid
	 * @param block
	 * @param num
	 * @param aorb
	 * @param key
	 * @param buf
	 * @return
	 */
	public static int ISO14443A_ReadMultiBlock(byte[] uid, byte block,
			byte num, byte aorb, byte[] key, byte[] buf) {
		byte NUM = 0x10;
		byte byNum = 0;
		byte byLastNum = 0;
		byte byNextBlock = block;
		byte[] byBufTmp = new byte[TX_BUF_LEN];
		int nTotal = 0;
		int nResult = 0;

		nResult = ISO14443A_LoadKey(key);
		if(nResult != 0){
			System.out.println("出现错误");
		}
		if (nResult != 0)
			return nResult;

		while (byLastNum < num) {
			if (num - byLastNum > NUM) {
				byNum = NUM;
			} else
				byNum = (byte) (num - byLastNum);

			nResult = ISO14443A_ReadMultiBlockBase(uid, byNextBlock, byNum,
					aorb, byBufTmp);
			if(nResult != 0){
				System.out.println("出现错误");
			}
			if (nResult != 0)
				return nResult;

			byNextBlock = (byte) ISO14443A_CalcNextBlock(byNextBlock, byNum);

			System.arraycopy(byBufTmp, 0, buf, nTotal, byNum
					* TXFRAME.ISO14443A_BLOCK_LEN);
			nTotal += byNum * TXFRAME.ISO14443A_BLOCK_LEN;

			byLastNum += byNum;
		}

		return 0;
	}

	public static int ISO14443NFC_ReadMultiBlock(byte[] byBuf, int card_type,
			StringBuffer sbBuffer) {
		int nResult = -1;
		TXFRAME frame = new TXFRAME();

		for (int i = 0; i < 16; i++) {
			TXFRAME.tx_make_read_block(frame, (byte) i);
			nResult = ISO14443A_WriteReadAPDUFrame(frame);

			System.arraycopy(frame.rx_data, 0, byBuf, 0, 4);

			sbBuffer.append("Page" + i + ":" + Tools.bytesToHexString(byBuf));
			sbBuffer.append("\n");
		}
		return nResult;
	}

	/**
	 * 写入NFC卡网址
	 * 
	 * @param totalBuf
	 * @param card_type
	 * @return
	 */
	public static int ISO14443NFC_WriteMultiBlock(byte[] totalBuf, int card_type) {

		byte block = 5;
		int nResult = -1;
		byte[] buf = new byte[16];
		int n = 0;
		for (int i = 0; i < totalBuf.length; i++) {
			buf[n] = totalBuf[i];
			if (((i + 1) % 4) == 0 && i != 0) {
				nResult = ISO14443A_WriteBlock1(block);
				if (nResult != 0)
					return nResult;
				nResult = ISO14443A_WriteBlock2(buf, card_type);
				n = 0;
				block++;
			} else if (i == totalBuf.length && ((i + 1) % 4) != 0) {
				nResult = ISO14443A_WriteBlock1(block);
				if (nResult != 0)
					return nResult;
				nResult = ISO14443A_WriteBlock2(buf, card_type);
				if (nResult != 0)
					return nResult;
				n = 0;
			} else {
				n++;
			}
		}

		return 0;
	}

	/**
	 * 写多块
	 * @param uid
	 * @param block
	 * @param num
	 * @param aorb
	 * @param key
	 * @param buf
	 * @return
	 */
	public static int ISO14443A_WriteMultiBlock(byte[] uid, byte block,
			byte num, byte aorb, byte[] key, byte[] buf) {
		byte NUM = 0x10;
		byte byNum = 0;
		byte byLastNum = 0;
		byte byNextBlock = block;
		int nResult = 0;

		nResult = ISO14443A_LoadKey(key);
		if (nResult != 0)
			return nResult;

		byte[] tmpBuf = null;

		while (byLastNum < num) {
			if (num - byLastNum > NUM) {
				byNum = NUM;
			} else
				byNum = (byte) (num - byLastNum);

			tmpBuf = new byte[buf.length - byLastNum
					* TXFRAME.ISO14443A_BLOCK_LEN];
			System.arraycopy(buf, byLastNum * TXFRAME.ISO14443A_BLOCK_LEN,
					tmpBuf, 0, tmpBuf.length);

			nResult = ISO14443A_WriteMultiBlockBase(uid, byNextBlock, byNum,
					aorb, tmpBuf);
			if (nResult != 0)
				return nResult;

			byNextBlock = (byte) ISO14443A_CalcNextBlock(byNextBlock, byNum);

			byLastNum += byNum;
		}

		return 0;
	}

	public static int ISO14443A_LoadKey(byte[] key) {
		TXFRAME frame = new TXFRAME();

		TXFRAME.tx_make_load_key(frame, key);

		return ISO14443A_WriteReadAPDUFrame(frame);
	}

	public static int ISO14443A_Authentication1(byte aorb, byte block,
			byte[] uid) {
		TXFRAME frame = new TXFRAME();

		TXFRAME.tx_make_authentication(frame, aorb, block, uid);

		return ISO14443A_WriteReadAPDUFrame(frame);
	}

	public static int ISO14443A_Authentication2() {
		TXFRAME frame = new TXFRAME();

		TXFRAME.tx_make_authentication2(frame);

		return ISO14443A_WriteReadAPDUFrame(frame);
	}

	/**
	 * 初始化CPU卡
	 * @param uid
	 * @param reset_info
	 * @return
	 */
	public static int ISO14443A_Init_Cpu(byte[] uid, byte[] reset_info) {
		int nResult = -1;

		nResult = ISO14443A_Request();
		if (nResult != 0)
			return nResult;

		nResult = ISO14443A_GetUID(uid);
		if (nResult != 0)
			return nResult;

		nResult = ISO14443A_SelectTag(uid);
		if (nResult != 0)
			return nResult;

		nResult = ISO14443A_RATS(reset_info);
		if (nResult != 0)
			return nResult;

		return 0;
	}

	static int ISO14443A_WriteRegister(byte reg, byte val) {
		TXFRAME frame = new TXFRAME();

		TXFRAME.tx_make_register(frame, reg, val);

		return _14443AComm.ISO14443A_WriteReadFrame(frame);
	}

	static int ISO14443A_WriteReadAPDUFrame(TXFRAME frame) {
		try {
			return _14443AComm.ISO14443A_Comm(frame, TXFRAME.TX_APDU_FRAME);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return -1;
	}

	static int ISO14443A_WTX(TXFRAME frame) {
		TXFRAME wtx_frame = new TXFRAME();
		int nResult = -1;

		nResult = ISO14443A_WriteReadAPDUFrame(frame);
		if (nResult != ISO14443A_BASE_ERROR + TXFRAME.TX_WTX_ERROR)
			return nResult;

		System.arraycopy(frame.rx_data, 0, wtx_frame.rx_data, 0,
				TXFRAME.WTX_ERROR_LEN);

		while (nResult == ISO14443A_BASE_ERROR + TXFRAME.TX_WTX_ERROR) {
			TXFRAME.tx_make_wtx(wtx_frame, wtx_frame.rx_data);
			nResult = ISO14443A_WriteReadAPDUFrame(wtx_frame);
		}

		frame.rx_len = wtx_frame.rx_len;
		System.arraycopy(wtx_frame.rx_data, 0, frame.rx_data, 0,
				wtx_frame.rx_len);

		return nResult;
	}

	static int ISO14443A_RequestBaseEx(RInt card_type) {
		TXFRAME frame = new TXFRAME();
		int nResult = -1;

		TXFRAME.tx_make_request(frame);

		nResult = ISO14443A_WTX(frame);
		if (nResult == 0) {
			if (frame.rx_len == 2) {
				card_type.value = frame.rx_data[0];
				card_type.value |= ((int) frame.rx_data[1]) << 8;
			}
		}

		return nResult;
	}

	static int ISO14443A_RequestEx(RInt card_type) {
		int nResult = -1;

		nResult = ISO14443A_WriteRegister((byte) 0x09, (byte) 0);
		// Log.i("ISO14443A_WriteRegister", nResult+"");
		if (nResult != 0)
			return nResult;

		nResult = ISO14443A_RequestBaseEx(card_type);
		// Log.i("ISO14443A_RequestBaseEx", nResult+"");
		if (nResult != 0) {
			nResult = ISO14443A_RequestBaseEx(card_type);
			// Log.i("ISO14443A_RequestBaseEx2", nResult+"");
		}

		return nResult;
	}

	static int ISO14443A_GetUIDBase(byte[] uid, int level) {
		TXFRAME frame = new TXFRAME();
		int nResult = -1;

		TXFRAME.tx_make_get_uid(frame, level);

		nResult = ISO14443A_WTX(frame);
		if (nResult == 0) {
			System.arraycopy(frame.rx_data, 0, uid, 0, frame.rx_len);
		}

		return nResult;
	}

	public static int ISO14443A_GetUID(byte[] uid) {
		return ISO14443A_GetUIDBase(uid, 0);
	}

	public static int ISO14443A_GetUID2(byte[] uid) {
		return ISO14443A_GetUIDBase(uid, 1);
	}

	static int ISO14443A_SelectTagBase(byte[] uid, int level) {
		TXFRAME frame = new TXFRAME();

		TXFRAME.tx_make_select_tag(frame, uid, level);

		return ISO14443A_WTX(frame);
	}

	static int ISO14443A_SelectTag(byte[] uid) {
		return ISO14443A_SelectTagBase(uid, 0);
	}

	static int ISO14443A_SelectTag2(byte[] uid) {
		return ISO14443A_SelectTagBase(uid, 1);
	}

	static int ISO14443A_WriteBlock1(byte block) {
		TXFRAME frame = new TXFRAME();

		TXFRAME.tx_make_write_block(frame, block);

		return ISO14443A_WriteReadAPDUFrame(frame);
	}

	static int ISO14443A_WriteBlock2(byte[] buf, int card_type) {
		TXFRAME frame = new TXFRAME();

		TXFRAME.tx_make_write_block2(frame, buf, card_type);

		return ISO14443A_WriteReadAPDUFrame(frame);
	}

	public static int ISO14443A_CalcNextBlock(byte block, byte num) {
		byte num1 = 0;
		byte num2 = 0;
		byte num3 = 0;
		byte next_block = 0;

		num1 = (byte) (TXFRAME.ISO14443A_BLOCKSPERSECTOR - 1 - block
				% TXFRAME.ISO14443A_BLOCKSPERSECTOR);
		if (num >= num1) {
			num2 = (byte) ((num - num1)
					/ (TXFRAME.ISO14443A_BLOCKSPERSECTOR - 1) * TXFRAME.ISO14443A_BLOCKSPERSECTOR);
			num3 = (byte) ((num - num1) % (TXFRAME.ISO14443A_BLOCKSPERSECTOR - 1));

			next_block = (byte) (block + num1 + 1);
			next_block += num2;
			next_block += num3;
		} else
			next_block = (byte) (block + num);

		return next_block;
	}

	static int ISO14443A_ReadMultiBlockBase(byte[] uid, byte block,
			byte num, byte aorb, byte[] buf) {
		TXFRAME frame = new TXFRAME();
		int nResult = 0;

		TXFRAME.tx_make_read_multi_block(frame, uid, block, num, aorb);

		nResult = _14443AComm.ISO14443A_WriteReadFrame(frame);
		if(nResult != 0){
			System.out.println("出现错误");
		}
		if (nResult == 0) {
			System.arraycopy(frame.rx_data, 0, buf, 0, frame.rx_len);
		}

		return nResult;
	}

	static int ISO14443A_WriteReadFrame(TXFRAME frame) {
		try {
			return _14443AComm.ISO14443A_Comm(frame, TXFRAME.TX_GENERAL_FRAME);
		} catch (IOException e) {
			e.printStackTrace();
		}

		return -1;
	}

	static int ISO14443A_WriteMultiBlockBase(byte[] uid, byte block,
			byte num, byte aorb, byte[] buf) {
		TXFRAME frame = new TXFRAME();

		TXFRAME.tx_make_write_multi_block(frame, uid, block, num, aorb, buf);

		return ISO14443A_WriteReadFrame(frame);
	}

	public static int ISO14443A_Request() {
		RInt nCardType = new RInt(0);

		return ISO14443A_RequestEx(nCardType);
	}

	static int ISO14443A_RATS(byte[] reset_info) {
		TXFRAME frame = new TXFRAME();
		int nResult = -1;

		TXFRAME.tx_make_rats(frame);

		nResult = ISO14443A_WTX(frame);
		if (nResult == 0) {
			System.arraycopy(frame.rx_data, 0, reset_info, 0, frame.rx_len);
		}

		return nResult;
	}

	// 外部认证
	public static int ISO14443A_ExtAuthenticate(byte keyId, byte[] key, byte len) {

		TXFRAME frame = new TXFRAME();
		int nResult = 0;
		byte byChallenge[] = new byte[ISO14443A_CHALLENGE_LONG];
		byte byLen = ISO14443A_CHALLENGE_LONG;

		nResult = ISO14443A_GetChallenge(byChallenge, byLen);
		if (nResult != 0)
			return nResult;

		Fmcos.fm_make_ext_authenticate(frame, keyId, key, len, byChallenge);

		nResult = ISO14443A_WTX(frame);
		if (nResult == 0) {
			return TxApdu.tx_apdu_parse_frame_status(frame);
		}

		return keyId;
	}

	static int ISO14443A_GetChallenge(byte[] buf, byte len) {
		TXFRAME frame = new TXFRAME();
		int ret = 0;

		Fmcos.fm_make_get_challenge(frame, len);

		ret = ISO14443A_WTX(frame);
		if (ret == 0) {
			return tx_apdu_parse_frame(frame, buf, len);
		}

		return ret;
	}

	static int tx_apdu_parse_frame(TXFRAME frame, byte[] buf, byte len) {
		int result = -1;

		result = Apdu.apdu_parse_status2(frame.rx_data, frame.rx_len);
		if (result == 0) {
			len = (byte) (frame.rx_len - 2);
			// memcpy(buf, frame.rx_data, len);
			System.arraycopy(frame.rx_data, 0, buf, 0, len);//选择文件或目录名称时会报错
			return 0;
		}

		return result;
	}

	public static int ISO14443A_Select(boolean fileType, byte[] file,
			byte file_len, byte[] buf, byte len) {
		TXFRAME frame = new TXFRAME();
		int nResult = 0;
		Fmcos.fm_make_select(frame, fileType, file, file_len);
		nResult = ISO14443A_WTX(frame);
		if (nResult == 0) {
			return tx_apdu_parse_frame(frame, buf, len);
		}
		return nResult;
	}

	public static int ISO14443A_EraseDf() {
		TXFRAME frame = new TXFRAME();
		int nResult = 0;

		Fmcos.fm_make_erase_df(frame);

		nResult = ISO14443A_WTX(frame);
		if (nResult == 0) {
			return TxApdu.tx_apdu_parse_frame_status(frame);
		}

		return nResult;
	}

	public static int ISO14443A_CreateFile(byte[] file_id, byte[] buf, byte len) {
		TXFRAME frame = new TXFRAME();
		int nResult = 0;

		Fmcos.fm_make_create_file(frame, file_id, buf, len);

		// nResult = TXWriteRead(&frame);
		nResult = ISO14443A_WTX(frame);
		if (nResult == 0) {
			return TxApdu.tx_apdu_parse_frame_status(frame);
		}

		return nResult;
	}

	public static int ISO14443A_WriteKey(byte type, byte id, byte[] buf,
			byte len, byte mac_type, byte[] mac_key) {
		TXFRAME frame = new TXFRAME();
		int nResult = 0;
		byte[] byChallenge = new byte[ISO1443Constant.ISO14443A_CHALLENGE_SHORT];
		byte byLen = ISO1443Constant.ISO14443A_CHALLENGE_SHORT;

		if (Apdu.is_mac(mac_type)) {
			nResult = ISO14443A_GetChallenge(byChallenge, byLen);
			if (nResult != 0)
				return nResult;
		}

		Fmcos.fm_make_write_key(frame, type, id, buf, len, mac_type, mac_key,
				byChallenge);

		nResult = ISO14443A_WTX(frame);
		if (nResult == 0) {
			return TxApdu.tx_apdu_parse_frame_status(frame);
		}

		return nResult;
	}

	public static int ISO14443A_ReadBinary(byte file, short offset, byte[] buf,
			short len, byte mac_type, byte[] mac_key) {
		short NUM = 240;
		int nResult = 0;
		byte sTotal = 0;
		byte byLen = 0;
		byte[] bufTmp = new byte[TXFRAME.TX_BUF_LEN];

		if (file != 0x00) {
			byte[] byFileId = { 0x00, 0x00 };
			byFileId[1] = file;
			byte[] bySelBuf = new byte[TXFRAME.TX_BUF_LEN];
			byte bySelLen = 0;
			nResult = ISO14443A_Select(true, byFileId,
					(byte) (byFileId.length / 1), bySelBuf, bySelLen);
			if (nResult != 0)
				return nResult;
		}

		// len == 0时
		while ((offset == 0 && (len == 0) && sTotal == 0) || sTotal < len) {
			if (sTotal + NUM > len) {
				byLen = (byte) (len - sTotal);
			} else {
				byLen = (byte) NUM;
			}
			// 不确定是否正确
			// memset(bufTmp, 0, bufTmp.length);//sizeof(bufTmp)
			// System.arraycopy(0, 0, bufTmp, 0, bufTmp.length);
			for (int i = 0; i <= bufTmp.length - 1; i++) {
				bufTmp[i] = 0x00;
			}
			nResult = ISO14443A_ReadBinaryBase((byte) 0x00,
					(byte) (offset + sTotal), bufTmp, byLen, mac_type, mac_key);
			if (nResult != 0)
				return nResult;

			// 线路保护读时有时可能出现读出0字节。从而进入死循环
			if (byLen == 0) {
				len = 0;
				return -2;
			}
			// 不确定是否正确
			// memcpy(buf + sTotal, bufTmp, byLen);
			System.arraycopy(bufTmp, 0, buf, sTotal, byLen);
			sTotal += byLen;
		}

		len = sTotal;

		return 0;
	}

	static int ISO14443A_ReadBinaryBase(byte file, short offset,
			byte[] buf, byte len, byte mac_type, byte[] mac_key) {
		TXFRAME frame = new TXFRAME();
		int nResult = 0;
		byte[] byChallenge = new byte[ISO1443Constant.ISO14443A_CHALLENGE_SHORT];
		byte byLen = ISO1443Constant.ISO14443A_CHALLENGE_SHORT;

		if (Apdu.is_mac(mac_type)) {
			nResult = ISO14443A_GetChallenge(byChallenge, byLen);
			if (nResult != 0)
				return nResult;
		}

		Fmcos.fm_make_read_binary(frame, file, offset, len, mac_type, mac_key,
				byChallenge);

		nResult = ISO14443A_WTX(frame);
		if (nResult == 0) {
			return Fmcos.fm_parse_frame_with_mac(frame, buf, len, mac_type,
					mac_key);
		}

		return nResult;
	}

	public static int ISO14443A_WriteBinary(byte file, short offset,
			byte[] buf, short len, byte mac_type, byte[] mac_key) {
		short NUM = 240;
		int nResult = 0;
		short sTotal = 0;
		byte byLen = 0;

		if (file != 0x00) {
			byte byFileId[] = { 0x00, 0x00 };
			byFileId[1] = file;
			byte[] bySelBuf = new byte[TXFRAME.TX_BUF_LEN];
			byte bySelLen = 0;
			nResult = ISO14443A_Select(true, byFileId,
					(byte) (byFileId.length / 1), bySelBuf, bySelLen);
			if (nResult != 0)
				return nResult;
		}

		while (sTotal < len) {
			if (sTotal + NUM > len) {
				byLen = (byte) (len - sTotal);
			} else {
				byLen = (byte) NUM;
			}
			nResult = ISO14443A_WriteBinaryBase((byte) 0x00,
					(byte) (offset + sTotal),
					ByteUtils.cutByte(buf, sTotal), byLen,
					mac_type, mac_key);
			if (nResult != 0)
				return nResult;

			sTotal += byLen;
		}

		return 0;
	}

	static int ISO14443A_WriteBinaryBase(byte file, short offset,
			byte[] buf, byte len, byte mac_type, byte[] mac_key) {
		TXFRAME frame = new TXFRAME();
		int nResult = 0;
		byte[] byChallenge = new byte[ISO1443Constant.ISO14443A_CHALLENGE_SHORT];
		byte byLen = ISO1443Constant.ISO14443A_CHALLENGE_SHORT;

		if (Apdu.is_mac(mac_type)) {
			nResult = ISO14443A_GetChallenge(byChallenge, byLen);
			if (nResult != 0)
				return nResult;
		}

		Fmcos.fm_make_write_binary(frame, file, offset, buf, len, mac_type,
				mac_key, byChallenge);

		nResult = ISO14443A_WTX(frame);
		if (nResult == 0) {
			return TxApdu.tx_apdu_parse_frame_status(frame);
		}

		return nResult;
	}

	public static int ISO14443A_ReadRecord(byte file, byte record_index,
                                           byte record_id, byte[] buf, RInt len, byte mac_type, byte[] mac_key) {
		TXFRAME frame = new TXFRAME();
		int nResult = 0;
		byte[] byChallenge = new byte[ISO1443Constant.ISO14443A_CHALLENGE_SHORT];
		byte byLen = ISO1443Constant.ISO14443A_CHALLENGE_SHORT;

		if (Apdu.is_mac(mac_type)) {
			nResult = ISO14443A_GetChallenge(byChallenge, byLen);
			if (nResult != 0)
				return nResult;
		}

		Fmcos.fm_make_read_record(frame, file, record_index, record_id,
				mac_type, mac_key, byChallenge);

		nResult = ISO14443A_WTX(frame);
		if (nResult == 0) {
			return Fmcos.fm_parse_frame_with_mac2(frame, buf, len, mac_type,
					mac_key);
		}

		return nResult;
	}

	public static int ISO14443A_WriteRecord(byte file, byte record_index,
			byte record_pos, byte[] buf, byte len, byte mac_type, byte[] mac_key) {
		TXFRAME frame = new TXFRAME();
		int nResult = 0;
		byte[] byChallenge = new byte[ISO1443Constant.ISO14443A_CHALLENGE_SHORT];
		byte byLen = ISO1443Constant.ISO14443A_CHALLENGE_SHORT;

		if (Apdu.is_mac(mac_type)) {
			nResult = ISO14443A_GetChallenge(byChallenge, byLen);
			if (nResult != 0)
				return nResult;
		}

		Fmcos.fm_make_write_record(frame, file, record_index, record_pos, buf,
				len, mac_type, mac_key, byChallenge);

		nResult = ISO14443A_WTX(frame);
		if (nResult == 0) {
			return TxApdu.tx_apdu_parse_frame_status(frame);
		}

		return nResult;
	}

	public static int ISO14443A_AppendRecord(byte file, byte[] buf, byte len,
			byte mac_type, byte[] mac_key) {
		TXFRAME frame = new TXFRAME();
		int nResult = 0;
		byte[] byChallenge = new byte[ISO1443Constant.ISO14443A_CHALLENGE_SHORT];
		byte byLen = ISO1443Constant.ISO14443A_CHALLENGE_SHORT;

		if (Apdu.is_mac(mac_type)) {
			nResult = ISO14443A_GetChallenge(byChallenge, byLen);
			if (nResult != 0)
				return nResult;
		}

		Fmcos.fm_make_append_record(frame, file, buf, len, mac_type, mac_key,
				byChallenge);

		nResult = ISO14443A_WTX(frame);
		if (nResult == 0) {
			return TxApdu.tx_apdu_parse_frame_status(frame);
		}

		return nResult;
	}

	public static int ISO14443A_VerifyPin(byte key_id, byte[] buf, byte len) {
		TXFRAME frame = new TXFRAME();
		int nResult = 0;

		Fmcos.fm_make_verify_pin(frame, key_id, buf, len);

		nResult = ISO14443A_WTX(frame);
		if (nResult == 0) {
			return TxApdu.tx_apdu_parse_frame_status(frame);
		}

		return nResult;
	}

	public static int ISO14443A_ChangePin(byte key_id, byte[] old_key,
			byte old_len, byte[] new_key, byte new_len) {
		TXFRAME frame = new TXFRAME();
		int nResult = 0;

		Fmcos.fm_make_change_pin(frame, key_id, old_key, old_len, new_key,
				new_len);

		nResult = ISO14443A_WTX(frame);
		if (nResult == 0) {
			return TxApdu.tx_apdu_parse_frame_status(frame);
		}

		return nResult;
	}

	public static int ISO14443A_UnLockPin(byte key_id, byte[] key, byte len,
			byte[] unlock_key, byte unlock_key_len) {
		TXFRAME frame = new TXFRAME();
		int nResult = 0;
		byte[] byChallenge = new byte[ISO1443Constant.ISO14443A_CHALLENGE_SHORT];
		byte byLen = ISO1443Constant.ISO14443A_CHALLENGE_SHORT;

		nResult = ISO14443A_GetChallenge(byChallenge, byLen);
		if (nResult != 0)
			return nResult;

		Fmcos.fm_make_unlock_pin(frame, key_id, key, len, unlock_key,
				unlock_key_len, byChallenge);

		nResult = ISO14443A_WTX(frame);
		if (nResult == 0) {
			return TxApdu.tx_apdu_parse_frame_status(frame);
		}
		return nResult;
	}

	public static int ISO14443A_ReloadPin(byte key_id, byte[] key, byte len,
			byte[] reload_key, byte reload_key_len) {
		TXFRAME frame = new TXFRAME();
		int nResult = 0;

		Fmcos.fm_make_reload_pin(frame, key_id, key, len, reload_key,
				reload_key_len);

		nResult = ISO14443A_WTX(frame);
		if (nResult == 0) {
			return TxApdu.tx_apdu_parse_frame_status(frame);
		}
		return nResult;
	}

	public static int ISO14443A_CreditLoadEx(boolean bank, byte key_id, byte[] money,
			byte[] pos_id, byte[] date, byte[] time, byte[] load_key,
			byte load_key_len, byte[] tac_key, byte tac_key_len) {
		TXFRAME frame = new TXFRAME();
		int nResult = 0;
		byte[] byBuf = new byte[TXFRAME.TX_BUF_LEN];
		byte byLen = 0;
		byte[] byMac2 = new byte[ISO1443Constant.ISO14443A_MAC_LEN];
		byte[] byTac = new byte[ISO1443Constant.ISO14443A_MAC_LEN];

		nResult = ISO14443A_InitLoad(bank, key_id, money, pos_id, byBuf, byLen);
		if (nResult != 0)
			return nResult;

		nResult = ISO14443A_ValidInitLoad(bank, load_key, load_key_len, money,
				pos_id, byBuf, date, time, byMac2);
		if (nResult != 0)
			return nResult;

		nResult = ISO14443A_CreditLoad(date, time, byMac2, byTac, byLen);
		if (nResult != 0)
			return nResult;

		nResult = ISO14443A_ValidCreditLoad(bank, tac_key, tac_key_len, money,
				pos_id, byBuf, date, time, byTac);
		if (nResult != 0)
			return nResult;

		return nResult;
	}

	static int ISO14443A_InitLoad(boolean bank, byte key_id, byte[] money,
			byte[] pos_id, byte[] buf, byte len) {
		TXFRAME frame = new TXFRAME();
		int nResult = 0;

		Fmcos.fm_make_init_load(frame, bank, key_id, money, pos_id);

		nResult = ISO14443A_WTX(frame);
		if (nResult == 0) {
			return TxApdu.tx_apdu_parse_frame(frame, buf, len);
		}
		return nResult;
	}

	static int ISO14443A_ValidInitLoad(boolean bank, byte[] key, byte key_len,
			byte[] money, byte[] pos_id, byte[] init_val, byte[] date,
			byte[] time, byte[] mac2) {
		if (Fmcos.fm_valid_init_load(bank, key, key_len, money, pos_id,
				init_val, date, time, mac2))
			return 0;

		return ISO14443A_INIT_LOAD_ERROR;
	}

	static int ISO14443A_CreditLoad(byte[] date, byte[] time, byte[] mac,
			byte[] buf, byte len) {
		TXFRAME frame = new TXFRAME();
		int nResult = 0;

		Fmcos.fm_make_credit_load(frame, date, time, mac);

		nResult = ISO14443A_WTX(frame);
		if (nResult == 0) {
			return TxApdu.tx_apdu_parse_frame(frame, buf, len);
		}

		return nResult;
	}

	static int ISO14443A_ValidCreditLoad(boolean bank, byte[] key,
			byte key_len, byte[] money, byte[] pos_id, byte[] init_val,
			byte[] date, byte[] time, byte[] tac) {
		if (Fmcos.fm_valid_credit_load(bank, key, key_len, money, pos_id,
				init_val, date, time, tac))
			return 0;

		return ISO14443A_CREDIT_LOAD_ERROR;
	}

	public static int ISO14443A_PurchaseEx(boolean bank, byte key_id,
			byte[] money, byte[] pos_id, byte[] sn, byte[] date, byte[] time,
			byte[] load_key, byte load_key_len, byte[] tac_key, byte tac_key_len) {
		//TXFRAME frame = new TXFRAME();
		int nResult = 0;
		byte[] byBuf = new byte[TXFRAME.TX_BUF_LEN];
		byte byLen = 0;
		byte[] byMac1 = new byte[ISO1443Constant.ISO14443A_MAC_LEN];
		byte[] byTac = new byte[8];

		nResult = ISO14443A_InitPurchase(bank, key_id, money, pos_id, byBuf,
				byLen);
		if (nResult != 0)
			return nResult;

		nResult = ISO14443A_ValidInitPurchase(bank, load_key, load_key_len,
				money, pos_id, byBuf, sn, date, time, byMac1);
		if (nResult != 0)
			return nResult;

		nResult = ISO14443A_DebitPurchase(sn, date, time, byMac1, byTac, byLen);
		if (nResult != 0)
			return nResult;

		nResult = ISO14443A_ValidDebitPurchase(bank, tac_key, tac_key_len,
				money, pos_id, byBuf, sn, date, time, byTac);
		if (nResult != 0)
			return nResult;

		return nResult;
	}

	static int ISO14443A_InitPurchase(boolean bank, byte key_id, byte[] money,
			byte[] pos_id, byte[] buf, byte len) {
		TXFRAME frame = new TXFRAME();
		int nResult = 0;
		Fmcos.fm_make_init_purchase(frame, bank, key_id, money, pos_id);
		nResult = ISO14443A_WTX(frame);
		if (nResult == 0) {
			return tx_apdu_parse_frame(frame, buf, len);
		}
		return nResult;
	}

	static int ISO14443A_ValidInitPurchase(boolean bank, byte[] key,
			byte key_len, byte[] money, byte[] pos_id, byte[] init_val,
			byte[] sn, byte[] date, byte[] time, byte[] mac1) {
		if (Fmcos.fm_valid_init_purchase(bank, key, key_len, money, pos_id,
				init_val, sn, date, time, mac1))
			return 0;

		return ISO14443A_INIT_LOAD_ERROR;
	}

	static int ISO14443A_DebitPurchase(byte[] sn, byte[] date, byte[] time,
			byte[] mac, byte[] buf, byte len) {
		TXFRAME frame = new TXFRAME();
		int nResult = 0;
		Fmcos.fm_make_debit_purchase(frame, sn, date, time, mac);
		nResult = ISO14443A_WTX(frame);
		if (nResult == 0) {
			return tx_apdu_parse_frame(frame, buf, len);
		}
		return nResult;
	}

	static int ISO14443A_ValidDebitPurchase(boolean bank, byte[] key,
			byte key_len, byte[] money, byte[] pos_id, byte[] init_val,
			byte[] sn, byte[] date, byte[] time, byte[] tac) {
		if (Fmcos.fm_valid_debit_purchase(bank, key, key_len, money, pos_id,
				init_val, sn, date, time, tac))
			return 0;

		return ISO14443A_CREDIT_LOAD_ERROR;
	}

	public static int ISO14443A_CreditUnLoadEx(byte[] key_id, byte[] money,
			byte[] pos_id, byte[] date, byte[] time, byte[] key, byte key_len) {
		TXFRAME frame = new TXFRAME();
		int nResult = 0;
		byte[] byBuf = new byte[TXFRAME.TX_BUF_LEN];
		byte byLen = 0;
		byte[] byMac2 = new byte[ISO1443Constant.ISO14443A_MAC_LEN];
		byte[] bySk = new byte[ISO1443Constant.ISO14443A_KEY_SHORT];
		byte[] byTac = new byte[ISO1443Constant.ISO14443A_MAC_LEN];
		nResult = ISO14443A_InitUnLoad(key_id, money, pos_id, byBuf, byLen);
		if (nResult != 0)
			return nResult;
		nResult = ISO14443A_ValidInitUnLoad(key, key_len, money, pos_id, byBuf,
				date, time, byMac2, bySk);
		if (nResult != 0)
			return nResult;
		nResult = ISO14443A_CreditUnLoad(date, time, byMac2, byTac, byLen);
		if (nResult != 0)
			return nResult;
		nResult = ISO14443A_ValidCreditUnLoad(money, pos_id, byBuf, date, time,
				bySk, byTac);
		if (nResult != 0)
			return nResult;
		return nResult;
	}

	static int ISO14443A_InitUnLoad(byte[] key_id, byte[] money, byte[] pos_id,
			byte[] buf, byte len) {
		TXFRAME frame = new TXFRAME();
		int nResult = 0;

		Fmcos.fm_make_init_unload(frame, key_id, money, pos_id);

		nResult = ISO14443A_WTX(frame);
		if (nResult == 0) {
			return tx_apdu_parse_frame(frame, buf, len);
		}

		return nResult;
	}

	static int ISO14443A_ValidInitUnLoad(byte[] key, byte key_len,
			byte[] money, byte[] pos_id, byte[] init_val, byte[] date,
			byte[] time, byte[] mac2, byte[] sk) {
		if (Fmcos.fm_valid_init_unload(key, key_len, money, pos_id, init_val,
				date, time, mac2, sk))
			return 0;
		return ISO14443A_INIT_LOAD_ERROR;
	}

	static int ISO14443A_CreditUnLoad(byte[] date, byte[] time, byte[] mac,
			byte[] buf, byte len) {
		TXFRAME frame = new TXFRAME();
		int nResult = 0;
		Fmcos.fm_make_credit_unload(frame, date, time, mac);
		nResult = ISO14443A_WTX(frame);
		if (nResult == 0) {
			return tx_apdu_parse_frame(frame, buf, len);
		}
		return nResult;
	}

	static int ISO14443A_ValidCreditUnLoad(byte[] money, byte[] pos_id,
			byte[] init_val, byte[] date, byte[] time, byte[] sk, byte[] tac) {
		if (Fmcos.fm_valid_credit_unload(money, pos_id, init_val, date, time,
				sk, tac))
			return 0;
		return ISO14443A_CREDIT_LOAD_ERROR;
	}

	public static int ISO14443A_CashEx(byte key_id, byte[] money,
			byte[] pos_id, byte[] sn, byte[] date, byte[] time,
			byte[] load_key, byte load_key_len, byte[] tac_key, byte tac_key_len) {
		TXFRAME frame = new TXFRAME();
		int nResult = 0;
		byte[] byBuf = new byte[TXFRAME.TX_BUF_LEN];
		byte byLen = 0;
		byte[] byMac1 = new byte[ISO1443Constant.ISO14443A_MAC_LEN];
		byte[] byTac = new byte[8];
		nResult = ISO14443A_InitCashWithdraw(key_id, money, pos_id, byBuf,
				byLen);
		if (nResult != 0)
			return nResult;
		nResult = ISO14443A_ValidInitCash(load_key, load_key_len, money,
				pos_id, byBuf, sn, date, time, byMac1);
		if (nResult != 0)
			return nResult;
		nResult = ISO14443A_DebitCashWithdraw(sn, date, time, byMac1, byTac,
				byLen);
		if (nResult != 0)
			return nResult;
		nResult = ISO14443A_ValidCashWithdraw(tac_key, tac_key_len, money,
				pos_id, byBuf, sn, date, time, byTac);
		if (nResult != 0)
			return nResult;
		return nResult;
	}

	static int ISO14443A_InitCashWithdraw(byte key_id, byte[] money,
			byte[] pos_id, byte[] buf, byte len) {
		TXFRAME frame = new TXFRAME();
		int nResult = 0;
		Fmcos.fm_make_init_cash_withdraw(frame, key_id, money, pos_id);
		nResult = ISO14443A_WTX(frame);
		if (nResult == 0) {
			return TxApdu.tx_apdu_parse_frame(frame, buf, len);
		}
		return nResult;
	}

	static int ISO14443A_ValidInitCash(byte[] key, byte key_len, byte[] money,
			byte[] pos_id, byte[] init_val, byte[] sn, byte[] date,
			byte[] time, byte[] mac1) {
		if (Fmcos.fm_valid_init_cash(key, key_len, money, pos_id, init_val, sn,
				date, time, mac1))
			return 0;
		return ISO14443A_INIT_LOAD_ERROR;
	}

	static int ISO14443A_DebitCashWithdraw(byte[] sn, byte[] date, byte[] time,
			byte[] mac, byte[] buf, byte len) {
		TXFRAME frame = new TXFRAME();
		int nResult = 0;
		Fmcos.fm_make_debit_capp_purchase(frame, sn, date, time, mac);
		nResult = ISO14443A_WTX(frame);
		if (nResult == 0) {
			return tx_apdu_parse_frame(frame, buf, len);
		}
		return nResult;
	}

	static int ISO14443A_ValidCashWithdraw(byte[] key, byte key_len,
			byte[] money, byte[] pos_id, byte[] init_val, byte[] sn,
			byte[] date, byte[] time, byte[] tac) {
		if (Fmcos.fm_valid_cash_withdraw(key, key_len, money, pos_id, init_val,
				sn, date, time, tac))
			return 0;
		return ISO14443A_CREDIT_LOAD_ERROR;
	}

	public static int ISO14443A_GetBalance(boolean bank, byte[] buf, byte len) {
		TXFRAME frame = new TXFRAME();
		int nResult = 0;
		Fmcos.fm_make_get_balance(frame, bank);
		nResult = ISO14443A_WTX(frame);
		if (nResult == 0) {
			return tx_apdu_parse_frame(frame, buf, len);
		}
		return nResult;
	}

	public static int ISO14443A_UpdateLimitEx(byte key_id, byte[] pos_id,
			byte[] money, byte[] date, byte[] time, byte[] load_key,
			byte load_key_len, byte[] tac_key, byte tac_key_len) {
		TXFRAME frame = new TXFRAME();
		int nResult = 0;
		byte[] byBuf = new byte[TXFRAME.TX_BUF_LEN];
		byte byLen = 0;
		byte[] byMac2 = new byte[ISO1443Constant.ISO14443A_MAC_LEN];
		byte[] byTac = new byte[ISO1443Constant.ISO14443A_MAC_LEN];

		nResult = ISO14443A_InitUpdateLimit(key_id, pos_id, byBuf, byLen);
		if (nResult != 0)
			return nResult;

		nResult = ISO14443A_ValidInitUpdatelimit(load_key, load_key_len,
				pos_id, byBuf, money, date, time, byMac2);
		if (nResult != 0)
			return nResult;

		nResult = ISO14443A_UpdateOverdrawLimit(money, date, time, byMac2,
				byTac, byLen);
		if (nResult != 0)
			return nResult;

		nResult = ISO14443A_ValidUpdateLimit(tac_key, tac_key_len, pos_id,
				byBuf, money, date, time, byTac);
		if (nResult != 0)
			return nResult;

		return nResult;
	}
	
	static int ISO14443A_InitUpdateLimit(byte key_id, byte[] pos_id, byte[] buf, byte len){
		TXFRAME	frame	= new TXFRAME();
		int		nResult	= 0;
		Fmcos.fm_make_init_update_limit(frame, key_id, pos_id);
		nResult = ISO14443A_WTX(frame);
		if (nResult == 0){
			return tx_apdu_parse_frame(frame, buf, len);
		}
		return nResult;
	}
	static int ISO14443A_ValidInitUpdatelimit(byte[] key, byte key_len,
			byte[] pos_id, byte[] init_val, byte[] money,
			byte[] date, byte[] time, byte[] mac2){
		if (Fmcos.fm_valid_init_update_limit(key, key_len, pos_id, init_val, money, date, time, mac2))
			return 0;

		return ISO14443A_INIT_LOAD_ERROR;
	}
	static int ISO14443A_UpdateOverdrawLimit(byte[] money, byte[] date, byte[] time, byte[] mac, byte[] buf, byte len){
		TXFRAME	frame	= new TXFRAME();
		int		nResult	= 0;
		Fmcos.fm_make_update_overdraw_limit(frame, money, date, time, mac);
		nResult = ISO14443A_WTX(frame);
		if (nResult == 0){
			return tx_apdu_parse_frame(frame, buf, len);
		}
		return nResult;
	}
	static int ISO14443A_ValidUpdateLimit(byte[] key, byte key_len,
			byte[] pos_id, byte[] init_val, byte[] money,
			byte[] date, byte[] time, byte[] tac){
		if (Fmcos.fm_valid_update_limit(key, key_len, pos_id, init_val, money, date, time, tac))
			return 0;
		return ISO14443A_CREDIT_LOAD_ERROR;
	}
	
	/*
	 *对增值功能进行的封装 
	 */
//	public static int ISO14443A_IncrementBase(byte block,byte[] buf){
//		int nResult=-1;
//		nResult=ISO14443A_Increment1(block);
//		if (nResult != 0)
//			return nResult;
//
//		nResult =ISO14443A_Increment2(buf);
//		if (nResult != 0)
//			return nResult;
//		return 0;
//	}
//	public static int ISO14443A_Increment1(byte block){
//		int				nResult	= -1;
//		TXFRAME	frame	= new TXFRAME();
//		TXFRAME.tx_make_increment(frame, block);
//		nResult = ISO14443A_WriteReadAPDUFrame(frame);
//		if (nResult == 0)
//		{
//			if (frame.rx_len == 1 && frame.rx_data[0] == 0x0A)
//				return 0;
//			else
//				return ISO14443A_INIT_VALUE_ERROR;
//		}
//		
//		return nResult;
//	}
//	public static int ISO14443A_Increment2(byte[] buf){
//		int nResult=-1;
//		TXFRAME frame=new TXFRAME();
//		TXFRAME.tx_make_increment2(frame, buf);
//		nResult = ISO14443A_WriteReadAPDUFrame(frame);
//		if (nResult == frame.TX_EE_ERROR)
//			return 0;
//		
//		return nResult;
//	}
//	public static int ISO14443A_Increment(byte block, int val){
//		byte[] buf=new byte[val];
//		ByteUtils.long2byte(buf,val);
//		return ISO14443A_IncrementBase(block, buf);
//	}

}
