package info.izumin.android.bletia;

import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;

import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

import info.izumin.android.bletia.wrapper.BluetoothGattCallbackWrapper;
import info.izumin.android.bletia.wrapper.BluetoothGattWrapper;

/**
 * Created by izumin on 9/7/15.
 */
public class BluetoothGattCallbackHandler extends BluetoothGattCallbackWrapper {

    private EnumMap<BleEvent.Type, Map<UUID, BleEvent>> mEventMap;
    private Callback mCallback;

    public BluetoothGattCallbackHandler(Callback callback) {
        mEventMap = new EnumMap<>(BleEvent.Type.class);
        mCallback = callback;
    }

    public BleEvent append(BleEvent.Type key, BleEvent event) {
        if (!mEventMap.containsKey(key)) {
            mEventMap.put(key, new HashMap<UUID, BleEvent>());
        }
        return mEventMap.get(key).put(event.getUuid(), event);
    }

    @Override
    public void onConnectionStateChange(BluetoothGattWrapper gatt, int status, int newState) {
        if (status == BluetoothGatt.GATT_SUCCESS) {
            if (newState == BluetoothGatt.STATE_CONNECTED) {
                mCallback.onConnect(gatt);
            }
            if (newState == BluetoothGatt.STATE_DISCONNECTED) {
                mCallback.onDisconnect(gatt);
            }
        } else {
            mCallback.onError(BleStatus.valueOf(status));
        }
    }

    @Override
    public void onServicesDiscovered(BluetoothGattWrapper gatt, int status) {
        // TODO: Not yet implemented.
    }

    @Override
    public void onCharacteristicRead(BluetoothGattWrapper gatt, BluetoothGattCharacteristic characteristic, int status) {
        handleBleEvent(BleEvent.Type.READING_CHARACTERISTIC, characteristic, status);
    }

    @Override
    public void onCharacteristicWrite(BluetoothGattWrapper gatt, BluetoothGattCharacteristic characteristic, int status) {
        handleBleEvent(BleEvent.Type.WRITING_CHARACTERISTIC, characteristic, status);
    }

    @Override
    public void onCharacteristicChanged(BluetoothGattWrapper gatt, BluetoothGattCharacteristic characteristic) {
        // TODO: Not yet implemented.
    }

    @Override
    public void onDescriptorRead(BluetoothGattWrapper gatt, BluetoothGattDescriptor descriptor, int status) {
        // TODO: Not yet implemented.
    }

    @Override
    public void onDescriptorWrite(BluetoothGattWrapper gatt, BluetoothGattDescriptor descriptor, int status) {
        // TODO: Not yet implemented.
    }

    @Override
    public void onReliableWriteCompleted(BluetoothGattWrapper gatt, int status) {
        // TODO: Not yet implemented.
    }

    @Override
    public void onReadRemoteRssi(BluetoothGattWrapper gatt, int rssi, int status) {
        // TODO: Not yet implemented.
    }

    @Override
    public void onMtuChanged(BluetoothGattWrapper gatt, int mtu, int status) {
        // TODO: Not yet implemented.
    }

    public UUID generateUuid(BleEvent.Type type) {
        UUID uuid;
        final Map<UUID, BleEvent> map = mEventMap.get(type);
        final Set<UUID> usedUuids = (map != null) ? map.keySet() : new HashSet<UUID>();
        do {
            uuid = UUID.randomUUID();
        } while (usedUuids.contains(uuid));
        return uuid;
    }

    private void handleBleEvent(BleEvent.Type type, BluetoothGattCharacteristic characteristic, int status) {
        UUID uuid = UUID.fromString(new String(characteristic.getDescriptor(Bletia.BRETIA_UUID).getValue()));
        BleEvent event = mEventMap.get(type).get(uuid);
        if (status == BluetoothGatt.GATT_SUCCESS) {
            event.getDeferred().resolve(characteristic);
        } else {
            event.getDeferred().reject(BluetoothGattStatus.valueOf(status));
        }
    }

    interface Callback {
        void onConnect(BluetoothGattWrapper gatt);
        void onDisconnect(BluetoothGattWrapper gatt);
        void onError(BleStatus status);
    }
}

@@ -179,130 +179,8 @@
 r;%0A%0A
-import java.util.EnumMap;%0Aimport java.util.HashMap;%0Aimport java.util.HashSet;%0Aimport java.util.Map;%0Aimport java.util.Set;%0A
 impo
@@ -474,40 +474,39 @@
 ate 
-EnumMap%3CBleEvent.Type, Map%3CUUID,
+Callback mCallback;%0A    private
  Ble
@@ -514,52 +514,25 @@
 vent
-%3E%3E
+Store
  mEvent
-Map;%0A    private Callback mCallback
+Store
 ;%0A%0A 
@@ -591,67 +591,37 @@
 back
-) %7B%0A        mEventMap = new EnumMap%3C%3E(BleEvent.Type.class);
+, BleEventStore eventStore) %7B
 %0A   
@@ -655,252 +655,36 @@
     
-%7D%0A%0A
     
-public BleEvent append(BleEvent.Type key, BleEvent event) %7B%0A        if (!mEventMap.containsKey(key)) %7B%0A            mEventMap.put(key, new HashMap%3CUUID, BleEvent%3E());%0A        %7D%0A        return mEventMap.get(key).put(event.getUuid(), event)
+mEventStore = eventStore
 ;%0A  
@@ -1497,19 +1497,16 @@
 ype.READ
-ING
 _CHARACT
@@ -1728,11 +1728,9 @@
 WRIT
-ING
+E
 _CHA
@@ -2716,618 +2716,220 @@
    p
-ublic UUID generateUuid(BleEvent.Type type) %7B%0A        UUID uuid;%0A        final Map%3CUUID, BleEvent%3E map = mEventMap.get(type);%0A        final Set%3CUUID%3E usedUuids = (map != null) ? map.keySet() : new HashSet%3CUUID%3E();%0A        do %7B%0A            uuid = UUID.randomUUID();%0A        %7D while (usedUuids.contains(uuid));%0A        return uuid;%0A    %7D%0A%0A    private void handleBleEvent(BleEvent.Type type, BluetoothGattCharacteristic characteristic, int status) %7B%0A        UUID uuid = UUID.fromString(new String(characteristic.getDescriptor(Bletia.BRETIA_UUID).getValue()));%0A        BleEvent event = mEventMap.get(type)
+rivate void handleBleEvent(BleEvent.Type type, BluetoothGattCharacteristic characteristic, int status) %7B%0A        BleEvent%3CBluetoothGattCharacteristic%3E event = mEventStore.closeEvent(type, characteristic
 .get
-(u
+U
 uid
+()
 );%0A 
@@ -3094,27 +3094,17 @@
 eject(Bl
-uetoothGatt
+e
 Status.v

Make BleGattCallbackHandler use BleEventStore