package com.mq.mylibrary.tool;

import android.content.Intent;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.MifareClassic;
import android.util.Base64;
import android.util.Log;

import com.mq.mylibrary.CardData;
import com.mq.mylibrary.base.BaseApp;
import com.mq.mylibrary.base.BaseCard;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 创建人 mQ
 * 创建时间 2019/10/31 0031 17:07
 * 文件名称 NFCTool
 * 说明:
 **/
public class NFCTool implements BaseCard {

    private static NfcAdapter mNfcAdapter;
    public static Intent newIntent;

    private NFCTool() {
    }

    private static class Helper {
        private static final NFCTool instance = new NFCTool();
    }

    public static NFCTool get(NfcAdapter nfcAdapter, Intent intent) {
        mNfcAdapter = nfcAdapter;
        newIntent = intent;
        return Helper.instance;
    }

    @Override
    public void open() {

    }

    @Override
    public void close() {

    }

//    @Override
//    public CardData readCard() {
//        CardData info = new CardData();
//        if (mNfcAdapter == null) {
//            info.state = "1";
//            info.msg = "不支持NFC";
//            return info;
//        }
//        if (!mNfcAdapter.isEnabled()) {
//            info.state = "2";
//            info.msg = "未启用NFC";
//            return info;
//        }
//        if (mTagFromIntent == null) {
//            info.state = "3";
//            info.msg = "请重新放卡";
//            return info;
//        }
//        info.state = "0";
//        MifareClassic mfc = MifareClassic.get(mTagFromIntent);
//        for (String tech : mTagFromIntent.getTechList()) {
//            LogTool.d("tech: " + tech);
//        }
//        boolean auth = false;
//        //读取TAG
//        try {
//            StringBuilder sb = new StringBuilder();
//            StringBuilder metaInfo = new StringBuilder();
//            //Enable I/O operations to the tag from this TagTechnology object.
//            mfc.connect();
//            int type = mfc.getType();//获取TAG的类型
//            int sectorCount = mfc.getSectorCount();//获取TAG中包含的扇区数
//            String typeS = "";
//            switch (type) {
//                case MifareClassic.TYPE_CLASSIC:
//                    typeS = "TYPE_CLASSIC";
//                    break;
//                case MifareClassic.TYPE_PLUS:
//                    typeS = "TYPE_PLUS";
//                    break;
//                case MifareClassic.TYPE_PRO:
//                    typeS = "TYPE_PRO";
//                    break;
//                case MifareClassic.TYPE_UNKNOWN:
//                    typeS = "TYPE_UNKNOWN";
//                    break;
//            }
//            metaInfo.append("卡片类型：")
//                    .append(typeS)
//                    .append("\n共")
//                    .append(sectorCount)
//                    .append("个扇区\n共")
//                    .append(mfc.getBlockCount())
//                    .append("个块\n存储空间: ")
//                    .append(mfc.getSize())
//                    .append("B\n");
//
//            StringBuffer sbOriginal = new StringBuffer();
//            StringBuffer sbDebug = new StringBuffer();
//
//            for (int j = 0; j < sectorCount; j++) {
//                //Authenticate a sector with key A.
//                auth = mfc.authenticateSectorWithKeyA(j,
//                        MifareClassic.KEY_DEFAULT);
//                int bCount;
//                int bIndex;
//                if (auth) {
//                    // 读取扇区中的块
//                    bCount = mfc.getBlockCountInSector(j);
//                    bIndex = mfc.sectorToBlock(j);
//                    for (int i = 0; i < bCount; i++) {
//                        byte[] data = mfc.readBlock(bIndex);
//                        String strRead = new String(data, "gb2312");
//
//                        sbOriginal.append("\n第")
//                                .append(bIndex)
//                                .append("块数据:");
//                        String original = strRead;
//                        if (strRead.contains("*")) {
//                            original = strRead.substring(0, strRead.indexOf("*"));
//                        }
//                        try {
//                            if ("0000000000000000".equals(original))
//                                sbOriginal.append(original);
//                            else
//                                sbOriginal.append(new String(
//                                        Base64.decode(original.getBytes(), Base64.DEFAULT), "gb2312"));
//                        } catch (Exception e) {
//                            sbOriginal.append(original);
//                        }
//
//                        if (i != bCount - 1) {
//                            if (j != 0 || i != 0) {//0区0块为制造商占用块
//                                sbDebug.append(strRead);
////                            sb.append(bytesToHexString(data));
////                                String strRead=bytesToHexString(data);
////                                sb.append(strRead);
////                                strRead = strRead.substring(0, 16);
//                                LogTool.d((j * 4 + i + 1) + ":" + strRead);
//                                if (strRead.contains("*")) {
//                                    sb.append(strRead.substring(0, strRead.indexOf("*")));
//                                } else if ("0000000000000000".equals(strRead)) {
//                                } else {
//                                    sb.append(strRead);
//                                }
//                            }
//                        }
//                        bIndex++;
//                    }
//                } else {
//                    metaInfo.append("Sector ").append(j).append(":验证失败\n");
//                }
//            }
//            LogTool.d(metaInfo.toString());
//            LogTool.d("结果：" + sb.toString());
////            byte b[] = Base64.decode(sb.toString().getBytes(), Base64.DEFAULT);
////            String cardInfo = new String(b, "gb2312");
////            String mCardInfo=sb.toString();
//
//            String debugStr = sbDebug.toString();
//            String debugStrResult = null;
//            if (debugStr.contains("*")) {
//                debugStrResult = debugStr.substring(0, debugStr.indexOf("*"));
//            } else {
//                debugStrResult = debugStr;
//            }
//            byte[] debugBytes = Base64.decode(debugStrResult.getBytes(), Base64.DEFAULT);
//            String gb2312 = new String(debugBytes, "gb2312");
//            String cardInfo = gb2312;
//            StringBuffer buffer = new StringBuffer();
//            String[] split = gb2312.split("\\|");
//            buffer.append("字段数:")
//                    .append(split.length)
//                    .append("\n");
//            for (int i = 0; i < split.length; i++) {
//                buffer.append(split[i])
//                        .append("\n");
//            }
//            info.resultData = cardInfo;
//            info.originalData = sbOriginal.toString();
//            info.debugData = buffer.toString();
//            return info;
//        } catch (IllegalArgumentException e) {
//            e.printStackTrace();
//            info.state = "3";
//            info.msg = "数据解码错误，请检查卡内数据是否正确";
//            return info;
//        } catch (Exception e) {
//            LogTool.e("读卡异常:" + e);
//            e.printStackTrace();
//        } finally {
//            if (mfc != null) {
//                try {
//                    mfc.close();
//                } catch (IOException e) {
//                    LogTool.e("读卡异常:" + e);
//                }
//            }
//        }
//        return null;
//    }

    @Override
    public CardData readCard() {
        CardData info = new CardData();
        if (mNfcAdapter == null) {
            info.state = "1";
            info.msg = "不支持NFC";
            return info;
        }
        if (!mNfcAdapter.isEnabled()) {
            info.state = "2";
            info.msg = "未启用NFC";
            return info;
        }
        if (newIntent == null) {
            info.state = "3";
            info.msg = "请重新放卡";
            return info;
        }
        info.state = "0";
        if (!NfcAdapter.ACTION_TAG_DISCOVERED.equals(newIntent.getAction())) {
            info.state = "3";
            info.msg = "请重新放卡";
            return info;
        }
        StringBuilder metaInfo = new StringBuilder();

        Tag tag = newIntent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        metaInfo.append("可用技术: \n");
        for (String tech : tag.getTechList()) {
            metaInfo.append(tech)
                    .append("\n");
        }
        MifareClassic mfc = MifareClassic.get(tag);

        //读取卡
        try {
            //Enable I/O operations to the tag from this TagTechnology object.
            mfc.connect();
            if (!mfc.isConnected()) {
                info.state = "3";
                info.msg = "连接失败,请重新放卡";
                return info;
            }

            int type = mfc.getType();//获取卡的类型
            int sectorCount = mfc.getSectorCount();//获取卡中包含的扇区数
            String typeS = "";
            switch (type) {
                case MifareClassic.TYPE_CLASSIC:
                    typeS = "TYPE_CLASSIC";
                    break;
                case MifareClassic.TYPE_PLUS:
                    typeS = "TYPE_PLUS";
                    break;
                case MifareClassic.TYPE_PRO:
                    typeS = "TYPE_PRO";
                    break;
                case MifareClassic.TYPE_UNKNOWN:
                    typeS = "TYPE_UNKNOWN";
                    break;
            }
            metaInfo.append("卡片类型：")
                    .append(typeS)
                    .append("\n共")
                    .append(sectorCount)
                    .append("个扇区\n共")
                    .append(mfc.getBlockCount())
                    .append("个块\n存储空间: ")
                    .append(mfc.getSize())
                    .append("B\n");

            StringBuffer sbResult = new StringBuffer();

            List<byte[]> dataList = new ArrayList<>();

            for (int i = 0; i < sectorCount; i++) {
                //Authenticate a sector with key A.
                //验证扇区
                boolean auth = false;
                if (mfc.authenticateSectorWithKeyA(i, MifareClassic.KEY_MIFARE_APPLICATION_DIRECTORY)) {
                    auth = true;
                } else if (mfc.authenticateSectorWithKeyA(i, MifareClassic.KEY_DEFAULT)) {
                    auth = true;
                } else if (mfc.authenticateSectorWithKeyA(i, MifareClassic.KEY_NFC_FORUM)) {
                    auth = true;
                } else {
                    Log.d("TAG", "Authorization denied ");
                }
                if (!auth) {
                    info.state = "3";
                    info.msg = "卡验证失败,请重新放卡";
                    return info;
                }

                // 读取扇区中的块
                int bCount = mfc.getBlockCountInSector(i);
                metaInfo.append("\n")
                        .append(i)
                        .append("扇区验证通过,共")
                        .append(bCount)
                        .append("个块\n");

                int bIndex = mfc.sectorToBlock(i);
                for (int j = 0; j < bCount; j++) {
                    byte[] data = mfc.readBlock(bIndex);
                    String strRead = new String(data, "gb2312");

                    //0区0块为制造商占用块 不取数据
                    //每区最后一块为控制块 不取数据
                    if (i != 0 || j != 0)
                        if (j < bCount - 1) {
                            sbResult.append(strRead);
                            dataList.add(data);
                        }

//                    String strRead = new String(data, "gb2312");
//
//                    sbOriginal.append("\n第")
//                            .append(bIndex)
//                            .append("块数据:");
//                    String original = strRead;
//                    if (strRead.contains("*")) {
//                        original = strRead.substring(0, strRead.indexOf("*"));
//                    }
//                    try {
//                        if ("0000000000000000".equals(original))
//                            sbOriginal.append(original);
//                        else
//                            sbOriginal.append(new String(
//                                    Base64.decode(original.getBytes(), Base64.DEFAULT), "gb2312"));
//                    } catch (Exception e) {
//                        sbOriginal.append(original);
//                    }

//                            sbDebug.append(strRead);
////                            sb.append(bytesToHexString(data));
////                                String strRead=bytesToHexString(data);
////                                sb.append(strRead);
////                                strRead = strRead.substring(0, 16);
//                            LogTool.d((j * 4 + i + 1) + ":" + strRead);
//                            if (strRead.contains("*")) {
//                                sb.append(strRead.substring(0, strRead.indexOf("*")));
//                            } else if ("0000000000000000".equals(strRead)) {
//                            } else {
//                                sb.append(strRead);
//                            }
                    bIndex++;
                }
            }
            // 关闭数据流
            mfc.close();

            metaInfo.append("读取结果:\n").append(sbResult.toString());
            LogTool.d(metaInfo.toString());

            // 计算字节长度
            int byteCount = 0;
            for (byte[] bytes : dataList) {
                byteCount += bytes.length;
            }
            LogTool.d("数据源的字节长度:" + byteCount);

            // 将所有字节存到byte数组中
            byte[] byteResult = new byte[byteCount];
            int byteIndex = 0;
            for (byte[] bytes : dataList) {
                for (byte b : bytes) {
                    byteResult[byteIndex] = b;
                    byteIndex++;
                }
            }

            // 字节转为字符串
            String sourceData = new String(byteResult, "gb2312");
            LogTool.d("数据源的内容:" + sourceData);

            // 截取业务数据
            String newData = null;
            if (sourceData.contains("*")) {
                newData = sourceData.substring(0, sourceData.indexOf("*"));
            } else {
                newData = sourceData;
            }

            // 原数据是否加密
            boolean isEncryption = !newData.contains("|");
            BaseApp.saveIsEncryption(isEncryption);// 存储加密状态

            // 加密数据进行解密
            String cardInfo = null;
            if (isEncryption) {
                byte[] debugBytes = Base64.decode(newData.getBytes(), Base64.DEFAULT);
                cardInfo = new String(debugBytes, "gb2312");
            } else {
                cardInfo = newData;
            }

            LogTool.d("解析后的业务数据：" + cardInfo);

            StringBuffer buffer = new StringBuffer();
            String[] split = cardInfo.split("\\|");
            buffer.append("字段数:")
                    .append(split.length)
                    .append("\n");
            for (int i = 0; i < split.length; i++) {
                buffer.append(split[i])
                        .append("\n");
            }
            info.resultData = cardInfo;
            info.originalData = sourceData;
            info.debugData = buffer.toString();
            return info;
        } catch (
                IllegalArgumentException e) {
            e.printStackTrace();
            info.state = "3";
            info.msg = "数据解码错误，请检查卡内数据是否正确";
            return info;
        } catch (
                Exception e) {
            LogTool.e("读卡异常:" + e);
            e.printStackTrace();
        }
        return null;
    }

//    @Override
//    public String writeCard(String newCardInfo) {
//        String result = "";
//        if (newIntent == null) {
//            result = "请重新放卡";
//            return result;
//        }
//        Tag tag = newIntent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
//        MifareClassic mfc = MifareClassic.get(tag);
//        try {
//            mfc.connect();
//            LogTool.d(newCardInfo);
//            byte[] b = newCardInfo.getBytes("gb2312");
//
//            String encReadData = null;
//            if (BaseApp.getIsEncryption()) {
//                // 加密
//                encReadData = Base64.encodeToString(b, Base64.DEFAULT);//加密后的数据
//            } else {
//                // 不加密
//                encReadData = newCardInfo;
//            }
//            String newEncReadData = encReadData + "*000";//字符串+特殊字符生成新的字符串 写入块中
//            LogTool.d(newEncReadData);
//            Pattern p = Pattern.compile("\\s*|\t|\r|\n");
//            Matcher m = p.matcher(newEncReadData);
//            newEncReadData = m.replaceAll("");
//
//            int encLengs = newEncReadData.length();//字符串长度
//            LogTool.d(String.valueOf(encLengs));
//            int count = encLengs / 16;//根据数据长度计算循环次数 4/16
//            int remainLen = encLengs % 16;
//            boolean flag = true;
//            StringBuilder encodeData = new StringBuilder();//每个块写入的数据
//            int k = 0;
//            boolean authOk;
//            for (int i = 0; i < 16; i++) {
//                LogTool.d(String.valueOf(i));
//                try {
//                    authOk = mfc.authenticateSectorWithKeyA(i,
//                            MifareClassic.KEY_DEFAULT);
//                } catch (IOException e) {
//                    e.printStackTrace();
//                    result = "卡片连接失效，写入失败，请重新放卡";
//                    return result;
//                }
//                LogTool.d(String.valueOf(result));
//                if (!authOk) {
//                    result = "卡片连接失效，写入失败，请重新放卡";
//                    return result;
//                }
//                for (int j = i * 4; j < i * 4 + 3; j++) {
//                    if (j != 0) {
//                        //截取加密字符串
//                        if (count == 0 && j == 1) {//写入的数据不够16位,差值补0
//                            flag = false;
//                            encodeData = new StringBuilder(newEncReadData.substring(0, remainLen));
//                            for (int x = 0; x < 16 - remainLen; x++) {
//                                encodeData.append("0");
//                            }
//                        } else if (k < count) {//如果写入字符超过16位，整除的部分肯定够截取16位
//                            encodeData = new StringBuilder(newEncReadData.substring(k * 16, k * 16 + 16));
//                        } else if (flag && remainLen != 0) {//如果写入字符有余数，有且只执行一次方法
//                            flag = false;
//                            encodeData = new StringBuilder(newEncReadData.substring(k * 16, k * 16 + remainLen));
//                            for (int x = 0; x < 16 - remainLen; x++) {
//                                encodeData.append("0");
//                            }
//                        } else {//上述所有条件不满足后，全部补0
//                            encodeData = new StringBuilder("0000000000000000");
//                        }
//                        k++;
//                        LogTool.d(encodeData.toString());
//                        LogTool.d(Arrays.toString(encodeData.toString().getBytes("gb2312")));
//                        LogTool.d(String.valueOf(j));
//                        mfc.writeBlock(j, encodeData.toString().getBytes("gb2312"));
//                    }
//                }
//            }
//        } catch (Exception e) {
//            e.printStackTrace();
//            result = "写入失败，请重新放卡";
//        } finally {
//            try {
//                mfc.close();
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
//        }
//        return result;
//    }


    @Override
    public String writeCard(String newCardInfo) {
        String result = "";
        if (newIntent == null) {
            result = "请重新放卡";
            return result;
        }
        LogTool.d("数据源:" + newCardInfo);

        String readData = null;
        if (BaseApp.getIsEncryption()) {
            try {
                readData = Base64.encodeToString(newCardInfo.getBytes("gb2312"), Base64.DEFAULT)
                        + "*000";
            } catch (UnsupportedEncodingException ex) {
                ex.printStackTrace();
                result = "数据加密失败";
                return result;
            }
        } else {
            readData = newCardInfo + "*000";
        }
        LogTool.d("加密后数据:" + readData);

        Pattern p = Pattern.compile("\\s*|\t|\r|\n");
        Matcher m = p.matcher(readData);
        readData = m.replaceAll("");
        LogTool.d("格式化后数据:" + readData);


        byte[] bytes = new byte[0];
        try {
            bytes = readData.getBytes("gb2312");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            result = "字节转换失败";
            return result;
        }
        LogTool.i("数据源的字节数:" + bytes.length);
        int count = bytes.length / 16;//根据数据长度计算循环次数 4/16
        int remainLen = bytes.length % 16;
        if (remainLen > 0)
            count += 1;
        LogTool.i("循环次数:" + count);
        LogTool.i("余:" + count);

        // 将源字节拆成16个为一组
        List<byte[]> resultList = new ArrayList<>();
        for (int i = 0; i < count; i++) {
            byte[] newByte = new byte[16];
            if (i < count - 1) {
                System.arraycopy(bytes, i * 16, newByte, 0, 16);
            } else {
                // 当最后不足16位时 用0补足
                int end = bytes.length - (i * 16);
                System.arraycopy(bytes, i * 16, newByte, 0, end);
                for (int j = 0; j < 16 - end; j++) {
                    newByte[j + end] = "0".getBytes()[0];
                }
            }
            resultList.add(newByte);
            LogTool.i("字节分组--" + i + ":" + Arrays.toString(newByte));
            try {
                LogTool.i("字节分组--" + i + "内容:" + new String(newByte, "gb2312"));
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                result = "字节转换失败";
                return result;
            }
        }


        Tag tag = newIntent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        MifareClassic mfc = MifareClassic.get(tag);
        try {
            mfc.connect();

            int bIndex = 0;
            int line = 0;
            for (int i = 0; i < 16; i++) {
                boolean authOk = mfc.authenticateSectorWithKeyA(i, MifareClassic.KEY_DEFAULT);
                if (!authOk) {
                    result = "卡验证失败,请重新放卡";
                    return result;
                }
                for (int j = 0; j < 4; j++) {
                    if (i != 0 || j != 0)
                        if (j < 4 - 1) {
                            if (line <= count - 1) {
                                byte[] resultByte = resultList.get(line);
                                LogTool.i("索引:" + line);
                                // 写入字节
                                mfc.writeBlock(bIndex, resultByte);

                                LogTool.d(i + "区" + j + "块插入数据:" + Arrays.toString(resultByte));
                                line++;
                            }
                        }
                    bIndex++;
                }
            }

//            int encLengs = newEncReadData.length();//字符串长度
//            LogTool.d(String.valueOf(encLengs));
//            boolean flag = true;
//            StringBuilder encodeData = new StringBuilder();//每个块写入的数据
//            int k = 0;
//            boolean authOk;
//            for (int i = 0; i < 16; i++) {
//                LogTool.d(String.valueOf(i));
//                try {
//                    authOk = mfc.authenticateSectorWithKeyA(i,
//                            MifareClassic.KEY_DEFAULT);
//                } catch (IOException e) {
//                    e.printStackTrace();
//                    result = "卡片连接失效，写入失败，请重新放卡";
//                    return result;
//                }
//                LogTool.d(String.valueOf(result));
//                if (!authOk) {
//                    result = "卡片连接失效，写入失败，请重新放卡";
//                    return result;
//                }
//                for (int j = i * 4; j < i * 4 + 3; j++) {
//                    if (j != 0) {
//                        //截取加密字符串
//                        if (count == 0 && j == 1) {//写入的数据不够16位,差值补0
//                            flag = false;
//                            encodeData = new StringBuilder(newEncReadData.substring(0, remainLen));
//                            for (int x = 0; x < 16 - remainLen; x++) {
//                                encodeData.append("0");
//                            }
//                        } else if (k < count) {//如果写入字符超过16位，整除的部分肯定够截取16位
//                            encodeData = new StringBuilder(newEncReadData.substring(k * 16, k * 16 + 16));
//                        } else if (flag && remainLen != 0) {//如果写入字符有余数，有且只执行一次方法
//                            flag = false;
//                            encodeData = new StringBuilder(newEncReadData.substring(k * 16, k * 16 + remainLen));
//                            for (int x = 0; x < 16 - remainLen; x++) {
//                                encodeData.append("0");
//                            }
//                        } else {//上述所有条件不满足后，全部补0
//                            encodeData = new StringBuilder("0000000000000000");
//                        }
//                        k++;
//                        LogTool.d(encodeData.toString());
//                        LogTool.d(Arrays.toString(encodeData.toString().getBytes("gb2312")));
//                        LogTool.d(String.valueOf(j));
//                        mfc.writeBlock(j, encodeData.toString().getBytes("gb2312"));
//                    }
//                }
//            }
        } catch (
                Exception e) {
            e.printStackTrace();
            result = "写入失败，请重新放卡";
        } finally {
            try {
                mfc.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    @Override
    public String clearCard() {
        String result = "";
        if (newIntent == null) {
            result = "请重新放卡";
            return result;
        }
        Tag tag = newIntent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        MifareClassic mfc = MifareClassic.get(tag);
        try {
            mfc.connect();
            StringBuilder encodeData = new StringBuilder();//每个块写入的数据
            boolean authOk;
            for (int i = 0; i < 16; i++) {
                LogTool.d(String.valueOf(i));
                try {
                    authOk = mfc.authenticateSectorWithKeyA(i,
                            MifareClassic.KEY_DEFAULT);
                } catch (IOException e) {
                    e.printStackTrace();
                    result = "写入失败，请重新放卡";
                    return result;
                }
                LogTool.d(String.valueOf(result));
                if (!authOk) {
                    result = "写入失败，请重新放卡";
                    return result;
                }
                for (int j = i * 4; j < i * 4 + 3; j++) {
                    if (j != 0) {
                        //截取加密字符串
                        encodeData = new StringBuilder("0000000000000000");
                        mfc.writeBlock(j, encodeData.toString().getBytes("gb2312"));
                    }
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
            result = "写入失败，请重新放卡";
        } finally {
            try {
                mfc.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }
}
