package com.siliconlabs.bledemo.ble;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.util.Log;

import com.siliconlabs.bledemo.utils.IOUtils;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;

import timber.log.Timber;

class BluetoothClient extends Thread {
    private final BluetoothAdapter bluetoothAdapter;
    private final BluetoothSocket mSocket;
    @SuppressWarnings({"unused", "FieldCanBeLocal"})
    private final BluetoothDevice mDevice;

    private volatile boolean closing;
    private InputStream is;
    private OutputStream os;

    private byte[] buffer = new byte[1024];

    public BluetoothClient(BluetoothAdapter bluetoothAdapter, BluetoothDevice device, UUID serviceUUID) {
        this.bluetoothAdapter = bluetoothAdapter;

        // Use a temporary object that is later assigned to mSocket,
        // because mSocket is final
        BluetoothSocket tmp = null;
        mDevice = device;

        // Get a BluetoothSocket to connect with the given BluetoothDevice
        try {
            // MY_UUID is the app's UUID string, also used by the server code
            tmp = device.createRfcommSocketToServiceRecord(serviceUUID);
        } catch (IOException ignored) {
        }
        mSocket = tmp;
    }

    public void run() {
        // Cancel discovery because it will slow down the connection
        if (bluetoothAdapter.isDiscovering()) {
            bluetoothAdapter.cancelDiscovery();
        }

        try {
            // Connect the device through the socket. This will block
            // until it succeeds or throws an exception
            mSocket.connect();
            // Do work to manage the connection (in a separate thread)
            manageConnectedSocket(mSocket);
        } catch (IOException connectException) {
            if (!closing) {
                Timber.e(connectException, "Error in Bluetooth Client Thread");
                Log.e("BluetoothClient", "Error in Bluetooth Client Thread: " + connectException);
            }
        } finally {
            IOUtils.closeStream(os);
            IOUtils.closeStream(is);
            cancel();
        }
    }

    public void write(byte[] bytes) {
        synchronized (this) {
            if (os == null) {
                return;
            }
        }

        try {
            os.write(bytes);
        } catch (IOException ignored) {
        }
    }

    /**
     * Will cancel an in-progress connection, and close the socket
     */
    public void cancel() {
        try {
            closing = true;
            mSocket.close();
        } catch (IOException ignored) {
        }
    }

    private void manageConnectedSocket(BluetoothSocket socket) throws IOException {
        synchronized (this) {
            os = socket.getOutputStream();
        }

        is = socket.getInputStream();
        //noinspection InfiniteLoopStatement
        while (true) {
            // While loop will terminate only upon an actual IOException
            // or upon a close of the socket that will also cause an IOException.
            int didRead = is.read(buffer);
            //noinspection StatementWithEmptyBody
            if (didRead > 0) {
                // TODO
            }
        }
    }
}