#include "BluetoothLeUartServer.h"

BluetoothLeUartServer::BluetoothLeUartServer(String deviceName, const char uartServiceUUID[36], const char rxUUID[36], const char txUUID[36])
{
    this->uartServiceUUID = uartServiceUUID;
    this->rxUUID = rxUUID;
    this->txUUID = txUUID;

    this->callbacks = nullptr;
    this->deviceConnected = false;
    this->deviceConnectionId = -1;

    // Create the BLE Device
    BLEDevice::init(deviceName.c_str()); // Give it a name

    // Create the BLE Server
    bleServer = BLEDevice::createServer();
    bleServer->setCallbacks(this);

    // Create the BLE Service
    bleService = bleServer->createService(this->uartServiceUUID);

    // Create a BLE Characteristic
    txCharacteristic = bleService->createCharacteristic(
        this->txUUID,
        BLECharacteristic::PROPERTY_NOTIFY);

    txCharacteristic->addDescriptor(new BLE2902());

    rxCharacteristic = bleService->createCharacteristic(
        this->rxUUID,
        BLECharacteristic::PROPERTY_READ |
            BLECharacteristic::PROPERTY_WRITE);

    rxCharacteristic->setCallbacks(this);

    // Start the service
    bleService->start();

    // Start advertising
    bleServer->getAdvertising()->addServiceUUID(bleService->getUUID());
    bleServer->getAdvertising()->setScanResponse(true);
    bleServer->getAdvertising()->setMinPreferred(0x06); // functions that help with iPhone connections issue
    bleServer->getAdvertising()->setMinPreferred(0x12);
    bleServer->getAdvertising()->start();
}

void BluetoothLeUartServer::setCallbacks(BluetoothLeUartServerCallbacks *callbacks)
{
    this->callbacks = callbacks;
}

void BluetoothLeUartServer::sendData(String data)
{
    //txCharacteristic->setValue(data.c_str());
    //Serial.printf("String is : '%s' with length of %d\n", data.c_str(), data.length() );
    txCharacteristic->setValue((uint8_t*)data.c_str(),data.length());
    txCharacteristic->notify();
}

bool BluetoothLeUartServer::getDeviceConnected()
{
    return this->deviceConnected;
}

bool BluetoothLeUartServer::disconnectCurrentDevice() {
    if(!this->getDeviceConnected())
        return false;

    this->bleServer->disconnect(this->deviceConnectionId);
    return true;
}

String BluetoothLeUartServer::getDeviceAddress() {
    
    String address = BLEDevice::getAddress().toString().c_str();
    address.toUpperCase();

    return address;
}

void BluetoothLeUartServer::onConnect(BLEServer* pServer, esp_ble_gatts_cb_param_t *param)
{
    // only allow one device
    if(this->deviceConnected)
        return this->bleServer->disconnect(param->connect.conn_id);

    this->deviceConnected = true;
    this->deviceConnectionId = param->connect.conn_id;

    if (this->callbacks != nullptr)
    {
        this->callbacks->onDeviceConnectedChanged(this->deviceConnected);
    }
}

void BluetoothLeUartServer::onDisconnect(BLEServer *pServer)
{
    this->deviceConnected = false;
    this->deviceConnectionId = -1;
    bleServer->getAdvertising()->start();
    Serial.println("Restart advertising after disconnect ...");

    if (this->callbacks != nullptr)
        this->callbacks->onDeviceConnectedChanged(this->deviceConnected);
}

void BluetoothLeUartServer::onWrite(BLECharacteristic *rxCharacteristic)
{
    if (this->callbacks != nullptr)
        this->callbacks->onDataReceived(rxCharacteristic->getValue().c_str());
}