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


import com.mq.mylibrary.rfid.io.translate.frame.ApduFrame;
import com.mq.mylibrary.rfid.io.util.ByteUtils;

public class Apdu {

	public static boolean apdu_resp_success(short status) {
		return (status == ApduFrame.APDU_RESP_OK);
	}

	public static short apdu_parse_status(ApduFrame aframe) {
		short status = 0;

		status = (short) (aframe.SW2 | aframe.SW1 << 8);
		if (apdu_resp_success(status)) {
			return 0;
		}

		if (status == 0)
			status = (short) 0xFFFF;

		return status;
	}

	public static int apdu_parse_status2(byte[] recv, int len) {
		short status = 0;

		status = (short) (recv[len - 1] + recv[len - 2] << 8);

		if (apdu_resp_success(status)) {
			return 0;
		}

		if (status == 0)
			status = (byte) 0xFFFF;

		return status;
	}

	public static int apdu_parse_data(ApduFrame aFrame, byte[] buf, byte len) {
		int result = -1;

		result = apdu_parse_status(aFrame);
		if (result == 0) {
			if (aFrame.Le != 0xFF)
				len = aFrame.Le;
			else
				len = 0;
			// memcpy(buf, aFrame.DATA, len);
			System.arraycopy(buf, 0, aFrame.DATA, 0, len);
			return 0;
		}

		return result;
	}

	public static int get_key_len(byte mac_type) {
		if (mac_type == ISO1443Constant.FM_MAC_16
				|| mac_type == ISO1443Constant.FM_DES_16
				|| mac_type == ISO1443Constant.FM_MACDES_16)
			return ISO1443Constant.ISO14443A_KEY_LONG;
		else
			return ISO1443Constant.ISO14443A_KEY_SHORT;
	}

	public static boolean is_mac_none(byte mac_type) {
		return (mac_type == ISO1443Constant.FM_MAC_NONE);
	}

	public static boolean is_mac(byte mac_type) {
		return (mac_type == ISO1443Constant.FM_MAC_8
				|| mac_type == ISO1443Constant.FM_MAC_16
				|| mac_type == ISO1443Constant.FM_MACDES_8 || mac_type == ISO1443Constant.FM_MACDES_16);
	}

	public static void fm_des(byte[] src, byte[] key, byte key_len, byte[] dst) {
		if (key_len == ISO1443Constant.ISO14443A_KEY_LONG) {
			D3Des.ThreeDES_Encript(key, src, dst);
		} else
			D3Des.Des(src, dst, key, 1);
	}

	static void fm_make_des(ApduFrame aFrame, byte[] mac_key, byte mac_key_len) {
		byte buf[] = new byte[ApduFrame.APDU_BUF_LEN];
		byte len = 0;
		int i, count;

		if (aFrame.Lc != 0xFF) {
			buf[0] = aFrame.Lc;
			// 待修改
			// memcpy(buf[1], aFrame.DATA, aFrame.Lc);
			System.arraycopy(aFrame.DATA, 0, buf, 1, len);
			len = (byte) (1 + aFrame.Lc);
		} else {
			buf[0] = 00;
			len = 1;
		}

		/*
		 * if (req->Le != 0xFF) { buf[len++] = req->Le; req->Le = 0xFF; }
		 */

		if (len % 8 != 0)
			buf[len++] = (byte) 0x80;

		while (len % 8 != 0) {
			buf[len++] = 0x00;
		}

		count = len / 8;

		for (i = 0; i < count; i++) {
			// 待修改
			// fm_des(buf[i * 8], mac_key, mac_key_len, aFrame.DATA[i * 8]);
			fm_des(ByteUtils.cutByte(buf, i * 8), mac_key, mac_key_len,
					ByteUtils.cutByte(aFrame.DATA, i * 8));
		}

		aFrame.Lc = len;
	}

	public static void fm_make_mac_base(byte[] src, byte src_len,
			byte[] init_value, byte[] mac_key, byte mac_key_len, byte[] mac) {
		byte[] buf = new byte[ApduFrame.APDU_BUF_LEN];
		byte len = 0;
		byte[] temp = new byte[ISO1443Constant.ISO14443A_KEY_LONG];
		byte[] dest = new byte[ISO1443Constant.ISO14443A_KEY_LONG];
		int i, j, count;

		System.arraycopy(src, 0, buf, 0, src_len);
		// memcpy(buf, src, src_len);
		len = src_len;
		buf[len++] = (byte) 0x80;

		while (len % 8 != 0) {
			buf[len++] = 0x00;
		}

		// memcpy(dest, init_value, ISO1443Constant.ISO14443A_CHALLENGE_SHORT);
		// memcpy(temp, init_value, ISO1443Constant.ISO14443A_CHALLENGE_SHORT);

		System.arraycopy(init_value, 0, dest, 0,
				ISO1443Constant.ISO14443A_CHALLENGE_SHORT);
		System.arraycopy(init_value, 0, temp, 0,
				ISO1443Constant.ISO14443A_CHALLENGE_SHORT);

		count = len / 8;

		for (i = 0; i < count; i++) {
			for (j = 0; j < 8; j++) {
				dest[j] ^= buf[i * 8 + j];
			}

			// memcpy(temp, dest, 8);
			System.arraycopy(dest, 0, temp, 0, 8);

			if (mac_key_len == ISO1443Constant.ISO14443A_KEY_LONG
					&& i == count - 1) {
				fm_des(temp, mac_key, ISO1443Constant.ISO14443A_KEY_LONG, dest);
			} else
				fm_des(temp, mac_key, ISO1443Constant.ISO14443A_KEY_SHORT, dest);
		}

		// memcpy(mac, dest, ISO1443Constant.ISO14443A_MAC_LEN);
		System.arraycopy(dest, 0, mac, 0, ISO1443Constant.ISO14443A_MAC_LEN);
	}

	public static void fm_make_mac(ApduFrame aFrame, byte[] init_value,
			byte[] mac_key, byte mac_key_len) {
		byte[] buf = new byte[ApduFrame.APDU_BUF_LEN];
		byte len = 0;
		byte[] mac = new byte[ISO1443Constant.ISO14443A_MAC_LEN];

		// 如果req.Le有数据，放到req.DATA后，以避免fm_make_mac中特殊处理的麻烦
		/*
		 * if (req->Le != 0xFF) { req->DATA[req->Lc - FM_MAC_LEN] = req->Le;
		 * req->Lc++; req->Le = 0xFF; }
		 */

		if (aFrame.Lc == 0xFF)
			aFrame.Lc = 0x00;

		aFrame.Lc += ISO1443Constant.ISO14443A_MAC_LEN;

		buf[0] = aFrame.CLA;
		buf[1] = aFrame.INS;
		buf[2] = aFrame.P1;
		buf[3] = aFrame.P2;
		buf[4] = aFrame.Lc;
		// 待修改
		// memcpy(buf[5], aFrame.DATA, aFrame.Lc -
		// ISO1443Constant.ISO14443A_MAC_LEN);
		// System.arraycopy(buf[5], 0, aFrame.DATA, 0, aFrame.Lc -
		// ISO1443Constant.ISO14443A_MAC_LEN);
		System.arraycopy(aFrame.DATA, 0, buf, 5, aFrame.Lc
				- ISO1443Constant.ISO14443A_MAC_LEN);
		len = (byte) (5 + aFrame.Lc - ISO1443Constant.ISO14443A_MAC_LEN);
		fm_make_mac_base(buf, len, init_value, mac_key, mac_key_len, mac);

		// 待修改
		// memcpy(aFrame.DATA[aFrame.Lc - ISO1443Constant.ISO14443A_MAC_LEN],
		// mac, ISO1443Constant.ISO14443A_MAC_LEN);
		// System.arraycopy(aFrame.DATA[aFrame.Lc -
		// ISO1443Constant.ISO14443A_MAC_LEN], 0, mac, 0,
		// ISO1443Constant.ISO14443A_MAC_LEN);
		System.arraycopy(mac, 0, aFrame.DATA, aFrame.Lc
				- ISO1443Constant.ISO14443A_MAC_LEN,
				ISO1443Constant.ISO14443A_MAC_LEN);
	}

}
