package com.sensetime.demo;

import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.text.TextUtils;

import com.blankj.utilcode.util.LogUtils;
import com.blankj.utilcode.util.ThreadUtils;
import com.blankj.utilcode.util.ToastUtils;
import com.blankj.utilcode.util.Utils;

import java.util.Collections;
import java.util.HashMap;

public class UsbDeviceHelper {
    public static final String TAG = "UsbDeviceHelper";
    // m10 m20 m20s
    public static final int DEVICE_PRODUCT_VID_4817 = 4817;
    public static final int DEVICE_PRODUCT_PID_17185 = 17185;
    // m30
    public static final int DEVICE_PRODUCT_VID_8711 = 8711;
    public static final int DEVICE_PRODUCT_PID_22 = 22;

    private static final String ACTION_USB_PERMISSION_BASE = "com.sensetime.demo.USB_PERMISSION.";
    private final String ACTION_USB_PERMISSION = ACTION_USB_PERMISSION_BASE + hashCode();

    private static final UsbDeviceHelper instance = new UsbDeviceHelper();

    private final UsbManager mUsbManager;
    private UsbDevice mUsbDevice;
    private int mConnectCode;
    private UsbInterface mUsbInterface;
    private UsbDeviceConnection mConnection;
    private UsbEndpoint mEndpointOut;
    private UsbEndpoint mEndpointIn;
    private UsbStateCallBack mCallBack;
    private PendingIntent mPermissionIntent;
    private int packageSize;
    private int mBusNum, mDevNum;
    private int interfaceNumber = -1;

    public boolean isConnceion = false;


    public int getFd() {
        return mConnection != null ? mConnection.getFileDescriptor() : Integer.MIN_VALUE;
    }

    public int getBusNum() {
        return mBusNum;
    }

    public int getDevNum() {
        return mDevNum;
    }

    public int getVendorId() {
        if (mUsbDevice != null) {
            return mUsbDevice.getVendorId();
        }
        return -1;
    }

    public int getProductId() {
        if (mUsbDevice != null) {
            return mUsbDevice.getProductId();
        }
        return -1;
    }

    public int getEndPointInAddress() {
        if (mEndpointIn != null) {
            return mEndpointIn.getAddress();
        }
        return -1;
    }

    public int getEndPointOutAddress() {
        if (mEndpointOut != null) {
            return mEndpointOut.getAddress();
        }
        return -1;
    }

    public int getInterfaceNumber() {
        return interfaceNumber;
    }

    public static synchronized UsbDeviceHelper getInstance() {
        return instance;
    }

    public UsbDeviceHelper() {
        mUsbManager = (UsbManager) Utils.getApp().getSystemService(Context.USB_SERVICE);
        start();
    }

    public void setCallBack(UsbStateCallBack mCallBack) {
        this.mCallBack = mCallBack;
    }

    public void start() {
        mPermissionIntent = PendingIntent.getBroadcast(Utils.getApp(), 0, new Intent(ACTION_USB_PERMISSION), 0);
        IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
        Utils.getApp().registerReceiver(mUsbPermissionsReceiver, filter);

        IntentFilter filter1 = new IntentFilter();
        filter1.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
        filter1.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
        Utils.getApp().registerReceiver(mUsbReceiver, filter1);
        //一开始就查找一下设备
        ThreadUtils.getMainHandler().postDelayed(new Runnable() {
            @Override
            public void run() {
                getUsbDevice();
                requestPermission(mUsbDevice);
            }
        }, 500);
    }

    BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action) || UsbManager.ACTION_USB_ACCESSORY_ATTACHED.equals(action)) {
                UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                LogUtils.dTag(TAG, "on usb attached" + device);
                if (device == null) return;
                if (((device.getProductId() == DEVICE_PRODUCT_PID_17185) && (device.getVendorId() == DEVICE_PRODUCT_VID_4817)) ||
                        (device.getVendorId() == DEVICE_PRODUCT_VID_8711 && device.getProductId() == DEVICE_PRODUCT_PID_22)) {
                    requestPermission(device);
                }
            } else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action) || UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) {
                UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                LogUtils.dTag(TAG, "on usb detached" + device);
                if (device == null) return;
                if (((device.getProductId() == DEVICE_PRODUCT_PID_17185) && (device.getVendorId() == DEVICE_PRODUCT_VID_4817)) ||
                        (device.getVendorId() == DEVICE_PRODUCT_VID_8711 && device.getProductId() == DEVICE_PRODUCT_PID_22)) {
                    mCallBack.usbDisConnect();
                    isConnceion = false;
                }
            }
        }
    };

    private final BroadcastReceiver mUsbPermissionsReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (ACTION_USB_PERMISSION.equals(action)) {
                synchronized (this) {
                    mUsbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                        LogUtils.dTag(TAG, "permission granted for device " + mUsbDevice);
                        if (mUsbDevice != null) {
                            //call method to set up device communication
                            openDevice();
                        }
                    } else {
                        LogUtils.dTag(TAG, "permission denied for device " + mUsbDevice);
                    }
                }
            }
        }
    };

    private void requestPermission(UsbDevice device) {
        if (device == null) {
            return;
        }
        if (!mUsbManager.hasPermission(device)) {
            LogUtils.dTag(TAG, "requestPermission not have permission=" + device);
            mUsbManager.requestPermission(device, this.mPermissionIntent);
            mUsbDevice = device;
        } else if (mUsbManager.hasPermission(device)) {
            LogUtils.dTag(TAG, "requestPermission has Permission=" + device);
            mUsbDevice = device;
            openDevice();
        }
    }

    private UsbDevice getUsbDevice() {
        HashMap<String, UsbDevice> deviceList = this.mUsbManager.getDeviceList();
        if (!deviceList.isEmpty()) {
            LogUtils.dTag(TAG, "getUsbDevice deviceList=" + Collections.singletonList(deviceList));
            for (UsbDevice device : deviceList.values()) {
                if ((device.getVendorId() == DEVICE_PRODUCT_VID_4817 && device.getProductId() == DEVICE_PRODUCT_PID_17185) ||
                        (device.getVendorId() == DEVICE_PRODUCT_VID_8711 && device.getProductId() == DEVICE_PRODUCT_PID_22)) {
                    this.mUsbDevice = device;
                    this.mConnectCode = 2;
                    break;
                }
            }
            if (this.mUsbDevice == null) {
                this.mConnectCode = -100;
            }
        }
        return mUsbDevice;
    }

    public boolean isConnectionDevice()
    {
        if(mUsbManager!=null)
        {
            HashMap<String, UsbDevice> deviceList = this.mUsbManager.getDeviceList();
            if(deviceList!=null && deviceList.size() > 0 ) return true;
        }
        return false;

    }


    private void openDevice() {
        try {
            if (mUsbManager.hasPermission(this.mUsbDevice)) {
                mConnection = this.mUsbManager.openDevice(this.mUsbDevice);
                for (int i = 0; i < mUsbDevice.getInterfaceCount(); i++) {
                    UsbInterface itemInterface = mUsbDevice.getInterface(i);
                    LogUtils.dTag(TAG, "itemInterface name " + itemInterface.getName());
                   /* if ("CDC ACM Data".equals(itemInterface.getName()) && itemInterface.getEndpointCount() == 2) {
                        mUsbInterface = mUsbDevice.getInterface(i);
                    }*/
                    if (itemInterface.getInterfaceClass() == 10 && itemInterface.getEndpointCount() == 2) {
                        mUsbInterface = mUsbDevice.getInterface(i);
                    }
                    if (itemInterface.getInterfaceClass() == 2) {
                        interfaceNumber = i;
                    }
                }
                mEndpointIn = mUsbInterface.getEndpoint(0);
                mEndpointOut = mUsbInterface.getEndpoint(1);

                if (mConnection != null) {
                    if (mConnection.claimInterface(this.mUsbInterface, true)) {
                        mConnectCode = 4;
                        packageSize = mEndpointIn.getMaxPacketSize();
                    } else {
                        this.mConnection.close();
                        this.mConnectCode = -104;
                    }

                    final String name = mUsbDevice.getDeviceName();
                    final String[] v = !TextUtils.isEmpty(name) ? name.split("/") : null;
                    int busnum = 0;
                    int devnum = 0;
                    if (v != null) {
                        busnum = Integer.parseInt(v[v.length - 2]);
                        devnum = Integer.parseInt(v[v.length - 1]);
                    }
                    mBusNum = busnum;
                    mDevNum = devnum;

                    mCallBack.usbConnect();
                    isConnceion = true;
                    //                USBFSName=getUSBFSName(mUsbDevice);
                    //                openUsbConnection(mConnection.getFileDescriptor(),4817,17185,mBusNum,mDevNum,USBFSName);

                } else {
                    this.mConnectCode = -103;
                    ToastUtils.showShort("connection fail!");
                }
            } else {
                this.mUsbManager.requestPermission(this.mUsbDevice, this.mPermissionIntent);
            }
        }catch (Exception e){
            ToastUtils.showShort("connection fail!");
            this.mUsbManager.requestPermission(this.mUsbDevice, this.mPermissionIntent);
        }
    }


    public void closeDevice() {
        try {
            if (mConnection != null) {
                if (mUsbInterface != null) {
                    mConnection.releaseInterface(mUsbInterface);
                    LogUtils.dTag(TAG, "Interface released");
                }
                mConnection.close();
                LogUtils.dTag(TAG, "Connection closed");
            }

            mConnection = null;
            mUsbInterface = null;
            mEndpointIn = null;
            mEndpointOut = null;
            mConnectCode = 0;
            mBusNum = 0;
            mDevNum = 0;

            ToastUtils.showShort("USB disconnected");

        } catch (Exception e) {
            LogUtils.e(TAG, "Error while closing USB device", e);
            ToastUtils.showShort("Failed to close USB connection");
        }
    }


}
