package info.izumin.android.bletia;

import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.content.Context;

import org.jdeferred.Deferred;
import org.jdeferred.Promise;
import org.jdeferred.impl.DeferredObject;

import java.util.UUID;

import info.izumin.android.bletia.helper.ConnectionHelper;
import info.izumin.android.bletia.wrapper.BluetoothDeviceWrapper;
import info.izumin.android.bletia.wrapper.BluetoothGattWrapper;

/**
 * Created by izumin on 9/7/15.
 */
public class Bletia implements BluetoothGattCallbackHandler.Callback {

    public static UUID BRETIA_UUID = UUID.fromString("00000000-0000-4e6c-abcf-960c2715e72d");

    private Context mContext;
    private BluetoothGattWrapper mGattWrapper;

    private BleState mState = BleState.DISCONNECTED;

    private ConnectionHelper mConnectionHelper;

    private EventEmitter mEmitter;
    private BluetoothGattCallbackHandler mCallbackHandler;

    public Bletia(Context context) {
        mContext = context;
        mConnectionHelper = new ConnectionHelper(mContext);
        mCallbackHandler = new BluetoothGattCallbackHandler(this);
        mEmitter = new EventEmitter();
    }

    public BleState getState() {
        return mState;
    }

    public void addListener(BletiaListener listener) {
        mEmitter.addListener(listener);
    }

    public void removeListener(BletiaListener listener) {
        mEmitter.removeListener(listener);
    }

    public void connect(BluetoothDevice device) {
        mState = BleState.CONNECTING;
        mConnectionHelper.connect(new BluetoothDeviceWrapper(device), mCallbackHandler);
    }

    public void disconenct() {
        mState = BleState.DISCONNECTING;
        mConnectionHelper.disconnect();
    }

    public Promise<BluetoothGattCharacteristic, BluetoothGattStatus, Object> writeCharacteristic(BluetoothGattCharacteristic characteristic) {
        Deferred<BluetoothGattCharacteristic, BluetoothGattStatus, Object> deferred = new DeferredObject<>();
        Promise<BluetoothGattCharacteristic, BluetoothGattStatus, Object> promise = deferred.promise();
        BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(Bletia.BRETIA_UUID, BluetoothGattDescriptor.PERMISSION_READ);
        UUID uuid = mCallbackHandler.generateUuid(BleEvent.Type.WRITING_CHARACTERISTIC);
        descriptor.setValue(uuid.toString().getBytes());
        characteristic.addDescriptor(descriptor);
        BleEvent event = new BleEvent(uuid, deferred);
        event.setCharacteristic(characteristic);

        mGattWrapper.writeCharacteristic(characteristic);
        mCallbackHandler.append(BleEvent.Type.WRITING_CHARACTERISTIC, event);

        return promise;
    }

    public Promise<BluetoothGattCharacteristic, BluetoothGattStatus, Object> readCharacteristic(BluetoothGattCharacteristic characteristic) {
        Deferred<BluetoothGattCharacteristic, BluetoothGattStatus, Object> deferred = new DeferredObject<>();
        Promise<BluetoothGattCharacteristic, BluetoothGattStatus, Object> promise = deferred.promise();
        BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(Bletia.BRETIA_UUID, BluetoothGattDescriptor.PERMISSION_READ);
        UUID uuid = mCallbackHandler.generateUuid(BleEvent.Type.READING_CHARACTERISTIC);
        descriptor.setValue(uuid.toString().getBytes());
        characteristic.addDescriptor(descriptor);
        BleEvent event = new BleEvent(uuid, deferred);
        event.setCharacteristic(characteristic);

        mGattWrapper.readCharacteristic(characteristic);
        mCallbackHandler.append(BleEvent.Type.READING_CHARACTERISTIC, event);

        return promise;
    }

    @Override
    public void onConnect(BluetoothGattWrapper gatt) {
        mState = BleState.CONNECTED;
        mEmitter.emitConnectEvent();
    }

    @Override
    public void onDisconnect(BluetoothGattWrapper gatt) {
        mState = BleState.DISCONNECTED;
        mConnectionHelper.close();
        mEmitter.emitDisconnectEvent();
    }

    @Override
    public void onError(BleStatus status) {
        mEmitter.emitError(status);
    }
}

@@ -145,107 +145,59 @@
 oid.
-bluetooth.BluetoothGattDescriptor;%0Aimport android.content.Context;%0A%0Aimport org.jdeferred.Defer
+content.Context;%0Aimport android.os.HandlerTh
 re
+a
 d;%0A
+%0A
 impo
@@ -225,50 +225,8 @@
 ise;
-%0Aimport org.jdeferred.impl.DeferredObject;
 %0A%0Aim
@@ -860,16 +860,55 @@
 mitter;%0A
+    private BleEventStore mEventStore;%0A
     priv
@@ -957,16 +957,61 @@
 Handler;
+%0A    private BleMessageThread mMessageThread;
 %0A%0A    pu
@@ -1129,16 +1129,98 @@
 ntext);%0A
+        mEmitter = new EventEmitter();%0A        mEventStore = new BleEventStore();%0A
         
@@ -1279,47 +1279,21 @@
 this
-);%0A        mEmitter = new EventEmitter(
+, mEventStore
 );%0A 
@@ -1743,24 +1743,199 @@
 ackHandler);
+%0A%0A        HandlerThread thread = new HandlerThread(device.getName());%0A        thread.start();%0A        mMessageThread = new BleMessageThread(thread, mGattWrapper, mEventStore);
 %0A    %7D%0A%0A    
@@ -2038,24 +2038,55 @@
 sconnect();%0A
+        mMessageThread.stop();%0A
     %7D%0A%0A    p
@@ -2126,35 +2126,25 @@
 teristic, Bl
-uetoothGatt
+e
 Status, Obje
@@ -2217,32 +2217,32 @@
 ) %7B%0A        
-Deferred
+BleEvent
 %3CBluetoothGa
@@ -2261,362 +2261,48 @@
 stic
-, BluetoothGattStatus, Object%3E deferred = new DeferredObject%3C%3E();%0A        Promise%3CBluetoothGattCharacteristic, BluetoothGattStatus, Object%3E promise = deferred.promise();%0A        BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(Bletia.BRETIA_UUID, BluetoothGattDescriptor.PERMISSION_READ);%0A        UUID uuid = mCallbackHandler.generateUuid
+%3E event =%0A                new BleEvent%3C%3E
 (Ble
@@ -2308,35 +2308,33 @@
 eEvent.Type.WRIT
-ING
+E
 _CHARACTERISTIC)
@@ -2336,382 +2336,100 @@
 STIC
-);%0A        descriptor.setValue(uuid.toString().getBytes());%0A        characteristic.addDescriptor(descriptor);%0A        BleEvent event = new BleEvent(uuid, deferred);%0A        event.setCharacteristic(characteristic);%0A%0A        mGattWrapper.writeCharacteristic(characteristic);%0A        mCallbackHandler.append(BleEvent.Type.WRITING_CHARACTERISTIC, event);%0A%0A        return promise
+, characteristic.getUuid(), characteristic);%0A%0A        return mMessageThread.sendEvent(event)
 ;%0A  
@@ -2479,35 +2479,25 @@
 teristic, Bl
-uetoothGatt
+e
 Status, Obje
@@ -2573,24 +2573,24 @@
         
-Deferred
+BleEvent
 %3CBluetoo
@@ -2613,362 +2613,48 @@
 stic
-, BluetoothGattStatus, Object%3E deferred = new DeferredObject%3C%3E();%0A        Promise%3CBluetoothGattCharacteristic, BluetoothGattStatus, Object%3E promise = deferred.promise();%0A        BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(Bletia.BRETIA_UUID, BluetoothGattDescriptor.PERMISSION_READ);%0A        UUID uuid = mCallbackHandler.generateUuid
+%3E event =%0A                new BleEvent%3C%3E
 (Ble
@@ -2660,35 +2660,32 @@
 eEvent.Type.READ
-ING
 _CHARACTERISTIC)
@@ -2687,381 +2687,100 @@
 STIC
-);%0A        descriptor.setValue(uuid.toString().getBytes());%0A        characteristic.addDescriptor(descriptor);%0A        BleEvent event = new BleEvent(uuid, deferred);%0A        event.setCharacteristic(characteristic);%0A%0A        mGattWrapper.readCharacteristic(characteristic);%0A        mCallbackHandler.append(BleEvent.Type.READING_CHARACTERISTIC, event);%0A%0A        return promise
+, characteristic.getUuid(), characteristic);%0A%0A        return mMessageThread.sendEvent(event)
 ;%0A  

Fix methods on Bletia