package com.intel.realsense.librealsense;

import android.content.Context;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbManager;
import android.util.Log;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

class DeviceWatcher extends LrsClass {
    private static final String TAG = "librs DeviceWatcher";

    private final List<DeviceListener> mAppDeviceListener;

    public synchronized void addListener(DeviceListener deviceListener){
        if(!mAppDeviceListener.contains(deviceListener)) {
            mAppDeviceListener.add(deviceListener);
        }
    }

    public synchronized void removeListener(DeviceListener deviceListener){
        mAppDeviceListener.remove(deviceListener);
    }

    public int getDeviceCount() {
        return mDescriptors.size();
    }

    private final Context mContext;
    private final Enumerator mEnumerator;

    private HashMap<String, UsbDesc> mDescriptors = new LinkedHashMap<>();


    private DeviceListener mListener = new DeviceListener() {
        @Override
        public void onDeviceAttach() {
            invalidateDevices();
        }

        @Override
        public void onDeviceDetach() {
            invalidateDevices();
        }
    };

    DeviceWatcher(Context context){
        mContext = context;
        mEnumerator = new Enumerator(mContext, mListener);
        mAppDeviceListener = new ArrayList<>();
    }

    private synchronized void invalidateDevices() {
        UsbManager usbManager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE);
        HashMap<String, UsbDevice> devicesMap = usbManager.getDeviceList();
        List<String> intelDevices = new ArrayList<String>();
        for (Map.Entry<String, UsbDevice> entry : devicesMap.entrySet()) {
            UsbDevice usbDevice = entry.getValue();
            if (UsbUtilities.isIntel(usbDevice))
                intelDevices.add(entry.getKey());
        }
        Iterator<Map.Entry<String, UsbDesc>> iter = mDescriptors.entrySet().iterator();
        while (iter.hasNext()) {
            Map.Entry<String, UsbDesc> entry = iter.next();
            if(!intelDevices.contains(entry.getKey())) {
                removeDevice(entry.getValue());
                iter.remove();
            }
        }
        for(String name : intelDevices) {
            if(!mDescriptors.containsKey(name)) {
                addDevice(devicesMap.get(name));
            }
        }
    }

    private void updateListeners(){
        for(DeviceListener listener : mAppDeviceListener) {
            try {
                listener.onDeviceDetach();
            } catch (Exception e) {
                Log.e(TAG, e.getMessage());
            }
        }
    }

    private void removeDevice(UsbDesc desc) {
        Log.d(TAG, "Removing device: " + desc.name);

        nRemoveUsbDevice(desc.descriptor);
        desc.connection.close();
        updateListeners();
        Log.d(TAG, "Device: " + desc.name + " removed successfully");
    }

    private void addDevice(UsbDevice device) {
        if (device == null)
            return;

        UsbManager usbManager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE);
        UsbDeviceConnection conn = usbManager.openDevice(device);
        if(conn == null)
            return;
        UsbDesc desc = new UsbDesc(device.getDeviceName(), conn.getFileDescriptor(), conn);
        Log.d(TAG, "Adding device: " + desc.name);
        mDescriptors.put(device.getDeviceName(), desc);
        nAddUsbDevice(desc.name, desc.descriptor);

        updateListeners();
        Log.d(TAG, "Device: " + desc.name + " added successfully");
    }

    @Override
    public void close() {
        Iterator<Map.Entry<String, UsbDesc>> iter = mDescriptors.entrySet().iterator();
        while (iter.hasNext()) {
            Map.Entry<String, UsbDesc> entry = iter.next();
            removeDevice(entry.getValue());
            iter.remove();
        }
    }

    private static native void nAddUsbDevice(String deviceName, int fileDescriptor);
    private static native void nRemoveUsbDevice(int fileDescriptor);
}

@@ -2606,110 +2606,339 @@
 ate 
-void updateListeners()%7B%0A        for(DeviceListener listener : mAppDeviceListener) %7B%0A            try %7B%0A
+enum UpdateListenersType %7B%0A        ATTACH,%0A        DETACH%0A    %7D%0A%0A    private void updateListeners(UpdateListenersType type)%7B%0A        for(DeviceListener listener : mAppDeviceListener) %7B%0A            try %7B%0A                if (type == UpdateListenersType.ATTACH)%0A                    listener.onDeviceAttach();%0A                else%0A    
     
@@ -3279,32 +3279,58 @@
 updateListeners(
+UpdateListenersType.DETACH
 );%0A        Log.d
@@ -3968,16 +3968,42 @@
 steners(
+UpdateListenersType.ATTACH
 );%0A     

Fix bug: Detach event was sent instead of Attach event, when device was connected