package com.device.comm.mylibrary;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.SystemClock;
import android.util.Base64;
import android.util.Log;


import com.device.comm.mylibrary.NativeDevice.InvsConst;
import com.device.comm.mylibrary.NativeDevice.InvsDes3;
import com.device.comm.mylibrary.NativeDevice.InvsIdCard;
import com.device.comm.mylibrary.NativeDevice.InvsUid;
import com.device.comm.mylibrary.NativeDevice.InvsUtil;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * Created by lvwang2002 on 16/3/18.
 */
public class BTCSFZReaderDevice extends BleDevice {

    private String TAG = "BT_CLASSIC_DEVICE";
    private static final String SPP_UUID = "00001101-0000-1000-8000-00805F9B34FB";// 蓝牙服务器的标识

    protected String mAddr1 = null;
    protected String mAddr = "";
    protected Timer mTimer = null;
    protected TimerTask mTimerTask = null;
    public Context mContext = null;
    protected static final int Suc_RecvContinue = 0;
    protected static final int Suc_RecvOk = 1;
    protected static final int Err_CheckHead = 2;
    protected static final int Err_CheckCrc = 3;
    protected int mResult = 0;
    protected int mPos = 0;
    protected int mDataLen = 0;
    protected byte[] mData = new byte['ஸ'];
    public InvsIdCard mInvsIdCard = null;
    //    protected IClientCallBack mCallback = null;
    private ReentrantReadWriteLock mRxLock = new ReentrantReadWriteLock();
    protected int m_iRecvLen = 0;
    protected int mValue = 0;
    protected byte[] mParam = null;
    protected int mPosExt = 0;
    protected int mPackNum = 0;
    protected byte[] mDataExt = new byte['ஸ'];
    protected byte[] mWlt = null;
    protected int mCmd = 0;
    private BluetoothAdapter mBltAdapter;

    private int mConnect = 0;

    private BluetoothSocket mSocket = null;
    private OutputStream os = null;
    private InputStream is = null;

    private String mMacAddress;
    private BleDeviceManager mDeviceManager;
    private BluetoothAdapter mBluetoothAdapter;
    private BluetoothDevice mBluetoothDevice;
    public BTCSFZReaderDevice(BluetoothAdapter bluetoothAdapter,
                              BleDeviceManager deviceManager,
                              BluetoothDevice bluetoothDevice){
        mDeviceManager = deviceManager;
        mMacAddress = bluetoothDevice.getAddress();
        mBluetoothAdapter = bluetoothAdapter;
        mBluetoothDevice = bluetoothDevice;

        regRecv();

    }


    public BluetoothDevice getBluetoothDevice(){
        mDeviceManager.stopScan();

        return mBluetoothDevice;
    }

    public void tryConnect(){
        mDeviceManager.stopScan();

        connect(mBluetoothDevice);

    }

    @Override
    public String getMacAddress(){
        return mMacAddress;
    }

    public interface BTCSFZReaderDeviceCallback extends BleDeviceCallback{
        public void onConnect(BleDevice device);
        public void onDisconnect(BleDevice device);
        public void onResult(BleDevice device, InvsIdCard card);
        public void onError(BleDevice device, String error);
    }

    BTCSFZReaderDeviceCallback mClassicDeviceCallback = null;
    public  void setDeviceCallback(BTCSFZReaderDeviceCallback deviceCallback) {
        mClassicDeviceCallback = deviceCallback;
    }

    private DeviceConnectState mDeviceState = DeviceConnectState.Discovered; //0:被发现未被连接 1:正在连接 2:已经连接上 3.断开连接

    private boolean postNeeded() {
        return mDeviceManager.getUpdateLoop().postNeeded();
    }

    private void post(final Runnable runnable) {
        final UpdateLoop updateLoop = mDeviceManager.getUpdateLoop();

        updateLoop.postIfNeeded(runnable);
    }

    private boolean postMainThreadNeeded() {
        return mDeviceManager.getMainUpdateLoop().postNeeded();
    }

    private void postMainThread(final Runnable runnable) {
        final UpdateLoop updateLoop = mDeviceManager.getMainUpdateLoop();

        updateLoop.postIfNeeded(runnable);
    }


    private BluetoothSocket mBluetoothSocket = null;

    @Override
    /** 蓝牙连接 */
    public void connect(BleDeviceCallback deviceCallback){
        mClassicDeviceCallback = (BTCSFZReaderDeviceCallback) deviceCallback;
        final BluetoothDevice device  = getBluetoothDevice();
        connect(device);
    }

    public void connect(final BluetoothDevice device) {

        boolean isConnected = btConnect(device);

        if (isConnected) {
            // 记录最新的连接设备名称
            mDeviceState = DeviceConnectState.Connected;
            if(mClassicDeviceCallback ==null) return;
            mClassicDeviceCallback.onConnect(this);

        }else{
            mDeviceState = DeviceConnectState.ConnectFailed;
            mDeviceManager.uhOh(this,"connect error");
        }


    }

    private boolean btConnect(final BluetoothDevice device){
        this.mWlt = null;
        String addr  = device.getAddress();
        if ((addr == null) || (addr == "") || (!BluetoothAdapter.checkBluetoothAddress(addr))) {
//            callOnBtState(false);
            return false;
        }

        if (addr.indexOf("00:0E:0B") == 0) {
            this.mAddr1 = addr;
            addr = "00:0E:0E" + this.mAddr1.substring(8);
        } else {
            this.mAddr1 = null;
        }

        this.mAddr = addr;
        if (!initialize()) {
//            callOnBtState(false);
            return false;
        }

        if (!initSock(addr)) {
//            callOnBtState(false);
            return false;
        }

        if (!connSock()) {
//            callOnBtState(false);
            return false;
        }

        this.mRecvThread = new RecvThread();
        this.mRecvThread.start();

        return true;
    }




//    ACTION_BOND_STATE_CHANGED



    public void disconnect(){
        this.mWlt = null;
        this.mRxLock.writeLock().lock();
        if (this.mSocket != null) {
            try {
                if (this.os != null)
                    this.os.close();
                if (this.is != null)
                    this.is.close();
                this.mSocket.close();
            }
            catch (Exception localException) {}
            this.os = null;
            this.is = null;
            this.mSocket = null;
        }
        this.mRxLock.writeLock().unlock();


        mBluetoothSocket = null;
        mDeviceState = DeviceConnectState.Disconnect;
        mDeviceManager.removeDevice(this);

        if(mClassicDeviceCallback ==null) return;
        mClassicDeviceCallback.onDisconnect(this);
    }

    public boolean initialize() {
        this.mBltAdapter = BluetoothAdapter.getDefaultAdapter();
        if (this.mBltAdapter == null) {
            return false;
        }

        if (!this.mBltAdapter.isEnabled()) {
            this.mBltAdapter.enable();
        }

        return true;
    }

    private boolean initSock(String addr) { this.mBltAdapter.cancelDiscovery();
        BluetoothDevice device = this.mBltAdapter.getRemoteDevice(addr);
        try
        {
            this.mSocket = device.createInsecureRfcommSocketToServiceRecord(InvsUid.MY_UUID);
        } catch (IOException e) {
            return initSock1(device);
        }

        return true;
    }


    private boolean initSock1(BluetoothDevice device)
    {
        Method m = null;
        try {
            m = device.getClass().getMethod("createRfcommSocket", new Class[] { Integer.TYPE });
            try {
                this.mSocket = ((BluetoothSocket)m.invoke(device, new Object[] { Integer.valueOf(1) }));
                return true;
            }
            catch (IllegalArgumentException localIllegalArgumentException) {}catch (IllegalAccessException localIllegalAccessException) {}catch (InvocationTargetException localInvocationTargetException) {}




            return false;
        } catch (NoSuchMethodException localNoSuchMethodException) {}
        return false;
    }

    private boolean connSock()
    {
        new Thread()
        {
            public void run()
            {
                try
                {
                    mSocket.connect();
                    mConnect = 1;
                } catch (IOException e) {
                    mConnect = -1;
                }

            }
        }.start();
        this.mConnect = 0;
        int iCount = 0;
        do {
            SystemClock.sleep(150L);
            if (this.mConnect != 0) {
                break;
            }
            iCount++; } while (iCount <= 100);
//        return false;



        if (this.mConnect == -1) {
            return false;
        }
        try
        {
            this.os = this.mSocket.getOutputStream();
            this.is = this.mSocket.getInputStream();
        } catch (IOException e) {
            return false;
        }
        return true;
    }


    public static final String msg = "invs.blt.readcard";

    public class BaseThread extends Thread { public BaseThread() {}
        public boolean mOver = false;

        public boolean isOver() { return (interrupted()) || (this.mOver); }

        public void over()
        {
            interrupted();
            this.mOver = true;
        }
    }

    RecvThread mRecvThread = null;
    public class RecvThread extends BaseThread { public RecvThread() { super(); }
        int m_iBufLen = 4096;

        public void run() {
//            Blt2.this.callOnBtState(true);
            while (!isOver()) {
                recvData();
            }

//            Blt2.this.callOnBtState(false);
        }

        public void recvData() {
            Log.i(TAG,"读取数据!!!!!");
            try { byte[] data = new byte[this.m_iBufLen];
                int iRecvLen = is.read(data, 0, this.m_iBufLen);
                Log.i(TAG,"读取数据:"+iRecvLen+data);

                mRxLock.writeLock().lock();
                if (mCmd == 7) {
                    System.arraycopy(data, 0, mDataExt, mPosExt, iRecvLen);
                    mPosExt += iRecvLen;
                    if (recvPackData() == 1) {
                        switch (checkData()) {
                            case 0:
                                break;
                            case 3:
                                mResult = 65;
                                break;
                            case 1:
                                mResult = (0xFF & mData[9]);
                        }
                    }
                }
                else {
                    if (iRecvLen > 0) {
                        System.arraycopy(data, 0, mData, mPos, iRecvLen);
                        mPos += iRecvLen;
                    } else {
                        mPos = 0;
                    }

                    switch (checkData()) {
                        case 0:
                            break;
                        case 3:
                            mResult = 65;
                            break;
                        case 1:
                            mResult = (0xFF & mData[9]);
                    }

                }
                mRxLock.writeLock().unlock();
            } catch (Exception e) {
                mRxLock.writeLock().lock();
                mResult = -1;
                mRecvThread = null;
                os = null;
                is = null;
                mSocket = null;
                mRxLock.writeLock().unlock();

                post(new Runnable() {
                    @Override
                    public void run() {
                        disconnect();
                    }
                });

                over();
            }
        }
    }



    BTCSFZReaderDevice mDevice = this;
    public class ReadThread extends BaseThread{
        public InvsIdCard mCard = null;
        protected void sendMsg(int cmd, boolean succ){
            Intent intent = new Intent();
            intent.setAction(msg);

            intent.putExtra("cmd", cmd);
            intent.putExtra("tag", succ);

            if (succ && cmd == InvsConst.Cmd_ReadCard){
                intent.putExtra("InvsIdCard", mCard);
            }

            mDeviceManager.getContext().sendBroadcast(intent);
        }

        void readCard() {
            try {
                SystemClock.sleep(1000);

                Log.i(TAG,"find card cmd");
                int iResult = findCardCmd();
                if (iResult == -1){
//                    mClient.disconnectBt();
                    Log.i(TAG,"error"+iResult);
                    mDeviceManager.getContext().unregisterReceiver(mBltReceiver);
                    mDeviceManager.uhOh(mDevice,"unknown error"+iResult);
                    over();
                    return;
                }else if (iResult == 0x9f){
                }else{
                    sendMsg(InvsConst.Cmd_ReadCard, false);
                    return;
                }
                Log.i(TAG,"read card cmd");
                iResult = readCardCmd();
                if (iResult == -1){
//                    mClient.disconnectBt();
                    mDeviceManager.getContext().unregisterReceiver(mBltReceiver);

                    mDeviceManager.uhOh(mDevice,"unknown error"+iResult);

                    over();

                    return;
                }else if (iResult == 0x90){
                    mCard = mInvsIdCard;
                    sendMsg(InvsConst.Cmd_ReadCard, true);
                }else{
                    sendMsg(InvsConst.Cmd_ReadCard, false);
                    return;
                }

                while(!isOver()){
                    SystemClock.sleep(50);
                    iResult = readAppCmd();
                    if (iResult == 0x90 || iResult == 0x91)
                        continue;

                    if (iResult == -1){
//                        mClient.disconnectBt();
                        mDeviceManager.uhOh(mDevice,"unknown error");

                        over();
                    }

                    break;
                }
            } catch (Exception e) {

            }

        }
        public void run(){
            while(!isOver()){
                readCard();
            }

            SystemClock.sleep(5);
        }
    }

    /** 非加密方式 */
    public InvsIdCard readCard()
    {
        if (readCardCmd() == 144) {
            if(mClassicDeviceCallback !=null) {
                this.mClassicDeviceCallback.onResult(this,this.mInvsIdCard);
            }
            return this.mInvsIdCard;
        }
        return null;
    }

    public int readCardCmd()
    {
        boolean desRead = false;
        int iCmd = 0;
        this.mWlt = null;
        if (desRead)
        {
            if (getKey1() == null) {
                return 0;
            }
            iCmd = sendCmd(22, 2500);
        }
        else
        {
            iCmd = sendCmd(6, 2500);
        }
        Log.i(TAG,"iCmd:"+iCmd);

        if (iCmd != 144) {
            return iCmd;
        }
        if (desRead)
        {
            byte[] des = null;
            try
            {
                InvsDes3 des3 = new InvsDes3();
                byte[] desData = new byte['Ԁ'];
                System.arraycopy(this.mData, 14, desData, 0, desData.length);
                des = InvsDes3.des3EncodeCBC(this.mParam, null, desData);
                System.arraycopy(des, 0, this.mData, 14, this.mData.length);
            }
            catch (Exception e)
            {
                return 0;
            }
        }
        this.mInvsIdCard = InvsUtil.IdCardByte2String(this.mData);
        this.mWlt = this.mInvsIdCard.wlt;
        return iCmd;
    }

    private int recvCmdResult(int timeOut)
    {
        long iTick = SystemClock.uptimeMillis();
        while (SystemClock.uptimeMillis() - iTick < timeOut)
        {
            SystemClock.sleep(100L);
            if (this.mResult != 0) {
                break;
            }
        }
        this.mCmd = 0;
        return this.mResult;
    }

    /** 加密方式读取 */
    public Map readCert()
    {
        this.mWlt = null;
        HashMap map = new HashMap();
        if (getKey1() == null)
        {
            sendMsg(6, false);

            map.put("resultFlag", Integer.valueOf(-1));
            map.put("errorMsg", "失败");
            if (this.mAddr1 == null) {
                map.put("mac", this.mAddr);
            } else {
                map.put("mac", this.mAddr1);
            }
            map.put("resultContent", null);
            return map;
        }
        if (readCardCmd() == 144)
        {
            map.put("resultFlag", Integer.valueOf(0));
            map.put("errorMsg", "成功");
            if (this.mAddr1 == null) {
                map.put("mac", this.mAddr);
            } else {
                map.put("mac", this.mAddr1);
            }
            String str = "<certificate>\r\n";
            str = str + "<partyName>" + this.mInvsIdCard.name + "</partyName>\r\n";
            String szTmp = "0";
            if (this.mInvsIdCard.sex.equalsIgnoreCase("男")) {
                szTmp = "1";
            }
            str = str + "<gender>" + szTmp + "</gender>\r\n";
            str = str + "<nation>" + this.mInvsIdCard.nation + "</nation>\r\n";
            str = str + "<bornDay>" + this.mInvsIdCard.birth + "</bornDay>\r\n";
            str = str + "<certAddress>" + this.mInvsIdCard.address + "</certAddress>\r\n";
            str = str + "<certNumber>" + this.mInvsIdCard.idNo + "</certNumber>\r\n";
            str = str + "<certOrg>" + this.mInvsIdCard.police + "</certOrg>\r\n";
            str = str + "<effDate>" + this.mInvsIdCard.start + "</effDate>\r\n";
            str = str + "<expDate>" + this.mInvsIdCard.end + "</expDate>\r\n";
            str = str + "</certificate>\r\n";

            byte[] des = null;
            try
            {
                InvsDes3 des3 = new InvsDes3();

                des = InvsDes3.des3EncodeCBC(this.mParam, null, str.getBytes("utf8"));
                str = Base64.encodeToString(des, 0);
            }
            catch (Exception e)
            {
                map.put("resultFlag", Integer.valueOf(-1));
                map.put("errorMsg", "fail");
                if (this.mAddr1 == null) {
                    map.put("mac", this.mAddr);
                } else {
                    map.put("mac", this.mAddr1);
                }
                map.put("resultContent", null);
                return map;
            }
            map.put("resultContent", str);

            return map;
        }
        map.put("resultFlag", Integer.valueOf(-1));
        map.put("errorMsg", "失败");
        map.put("mac", this.mAddr);
        if (this.mAddr1 == null) {
            map.put("mac", this.mAddr);
        } else {
            map.put("mac", this.mAddr1);
        }
        map.put("resultContent", null);
        return map;
    }

    protected void sendMsg(int cmd, boolean succ)
    {
        Intent intent = new Intent();
        intent.setAction("invs.blt");

        intent.putExtra("cmd", cmd);
        intent.putExtra("tag", succ);
        if ((succ) && (cmd == 6)) {
            intent.putExtra("InvsIdCard", this.mInvsIdCard);
        }
        if ((succ) && (cmd == 8)) {
            intent.putExtra("value", this.mValue);
        }
        if ((succ) && (cmd == 21)) {
            intent.putExtra("param", this.mParam);
        }
        if (cmd == 1) {
            intent.setAction("invs.blt1");
        }
        try
        {
            this.mContext.sendBroadcast(intent);
        }
        catch (Exception localException) {}
    }

    public String readPhoto()
    {
        if ((this.mWlt == null) &&
                (readCardCmd() != 144)) {
            return "";
        }
        return Base64.encodeToString(this.mWlt, 0);
    }

    public int readAppCmd()
    {
        return sendCmd(15, 500);
    }

    public int findCardCmd()
    {
        return sendCmd(4, 500);
    }
    public byte[] getKey()
    {
        if (sendCmd(21, 1500) == 144)
        {
            this.mParam = new byte[this.mDataLen - 4];
            System.arraycopy(this.mData, 10, this.mParam, 0, this.mParam.length);
            return this.mParam;
        }
        return null;
    }

    public byte[] getKey1()
    {
        if (sendCmd(21, 1500) == 144)
        {
            this.mParam = new byte[this.mDataLen - 4];
            System.arraycopy(this.mData, 10, this.mParam, 0, this.mParam.length);
            return this.mParam;
        }
        return null;
    }

    protected int sendCmd(int cmd, int timeOut)
    {
        clearData();
        if (cmd == 7)
        {
            this.mCmd = cmd;
            getPack(0);
        }
        else
        {
            byte[] data = InvsUtil.getCmdData(cmd, this.mParam);
            if (!sendCmdData(data)) {
                return -1;
            }
        }
        return recvCmdResult(timeOut);
    }
    protected void clearData()
    {
        this.mRxLock.writeLock().lock();
        this.mPos = 0;
        this.mDataLen = 0;
        this.m_iRecvLen = 0;
        this.mResult = 0;
        this.mRxLock.writeLock().unlock();
    }

    protected boolean getPack(int packNum)
    {
        if (packNum == 0)
        {
            clearData();
            this.mPackNum = 0;
        }
        clearDataExt();
        if (!sendCmdData(InvsUtil.CmdData(new byte[] { -31, (byte)packNum, 50 }))) {
            return false;
        }
        return true;
    }

    private void clearDataExt()
    {
        this.mPosExt = 0;
    }

    protected boolean sendCmdData(byte[] data)
    {
        try
        {
            this.os.write(data, 0, data.length);
        }
        catch (Exception e)
        {
            return false;
        }
        return true;
    }

    int recvPackData()
    {
        if ((this.mDataExt[0] & 0xFF) != 204)
        {
            clearData();
            return 0;
        }
        if (this.mPosExt < 3) {
            return 0;
        }
        int packNum = this.mDataExt[1] & 0xFF;
        int packLen = this.mDataExt[2] & 0xFF;
        if (this.mPosExt < packLen + 4) {
            return 0;
        }
        if (InvsUtil.ChkSum(this.mDataExt, 0, packLen + 4) != 0) {
            return 3;
        }
        System.arraycopy(this.mDataExt, 3, this.mData, this.mPos, packLen);
        this.mPos += packLen;
        if (packNum != 255)
        {
            if (!getPack(++this.mPackNum)) {
                return 3;
            }
            return 0;
        }
        return 1;
    }


    int checkData()
    {
        if (this.mPos < 5)
        {
            this.mDataLen = 0;
            return 0;
        }
        if ((this.mDataLen == 0) &&
                (this.mPos >= 7))
        {
            if (!InvsUtil.checkHead(this.mData))
            {
                clearData();
                return 0;
            }
            int iLow = this.mData[6] & 0xFF;
            int iHight = (this.mData[5] & 0xFF) << 8;
            this.mDataLen = (iHight + iLow);
        }
        if (this.mPos - 7 < this.mDataLen) {
            return 0;
        }
        if (InvsUtil.ChkSum(this.mData, 5, this.mDataLen + 2) != 0) {
            return 3;
        }
        return 1;
    }

    void regRecv()
    {
        final IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(msg);
        mDeviceManager.getContext().registerReceiver(mBltReceiver, intentFilter);
    }

    //接收蓝牙传回的消息
    private final BroadcastReceiver mBltReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
            if (msg.equals(action)) {
                if (intent.getBooleanExtra("tag", false)){
                    InvsIdCard invsIdCard = (InvsIdCard) intent.getSerializableExtra("InvsIdCard");
//                    displayView(invsIdCard);
                    if(mClassicDeviceCallback != null){
                        mClassicDeviceCallback.onResult(mDevice,invsIdCard);
                    }
                    Log.i(TAG,"接收到连续读卡信息:"+invsIdCard.getName());
                }else{
//                    initView("读卡失败");
                    if(mClassicDeviceCallback != null){
                        mClassicDeviceCallback.onResult(mDevice,null);
                    }

                    Log.i(TAG,"读卡失败");

                }
            }
        }
    };

    ReadThread mReadThread = null;
    public void startThreadReadCard() {
        mReadThread = new ReadThread();
        mReadThread.start();
    }

    public void stopThreadReadCard() {
        if (mReadThread != null && mReadThread.isAlive()){
            mReadThread.over();
            mReadThread = null;
        }
    }

    @Override
    public DeviceConnectState getDeviceState() {
        return mDeviceState;
    }



}


