/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, GNU version 3. This project is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include "bluetoothdevice.h"

BluetoothDevice::BluetoothDevice(const QBluetoothDeviceInfo &deviceInfo, QObject *parent) :
    QObject(parent),
    m_deviceInfo(deviceInfo),
    m_connected(false)
{
    m_controller = QLowEnergyController::createCentral(deviceInfo, this);
//    m_controller->setRemoteAddressType(QLowEnergyController::PublicAddress);

    connect(m_controller, &QLowEnergyController::connected, this, &BluetoothDevice::onConnected);
    connect(m_controller, &QLowEnergyController::disconnected, this, &BluetoothDevice::onDisconnected);
    connect(m_controller, &QLowEnergyController::stateChanged, this, &BluetoothDevice::onDeviceStateChanged);
    connect(m_controller, SIGNAL(error(QLowEnergyController::Error)), this, SLOT(onDeviceError(QLowEnergyController::Error)));

    connect(m_controller, SIGNAL(discoveryFinished()), this, SIGNAL(serviceDiscoveryFinished()));
}

QString BluetoothDevice::name() const
{
    return m_deviceInfo.name();
}

QBluetoothAddress BluetoothDevice::address() const
{
    return m_deviceInfo.address();
}

QString BluetoothDevice::addressString() const
{
#ifdef Q_OS_MAC
    // On OS X and iOS we do not have addresses,
    // only unique UUIDs generated by Core Bluetooth.
    return m_deviceInfo.deviceUuid().toString();
#else
    return m_deviceInfo.address().toString();
#endif
}

bool BluetoothDevice::connected() const
{
    return m_connected;
}

QString BluetoothDevice::statusText() const
{
    return m_statusText;
}

void BluetoothDevice::connectDevice()
{
    if (m_controller->state() != QLowEnergyController::UnconnectedState) {
        qDebug() << "Controller in state:" << m_controller->state() << "Not connecting...";
        return;
    }
    qDebug() << "QLoweEnergyController connecting...";
    m_controller->connectToDevice();
}

void BluetoothDevice::disconnectDevice()
{
    m_controller->disconnectFromDevice();
}

void BluetoothDevice::setConnected(const bool &connected)
{
    m_connected = connected;
    emit connectedChanged();
}

void BluetoothDevice::setStatusText(const QString &statusText)
{
    m_statusText = statusText;
    emit statusTextChanged();
}

QLowEnergyController *BluetoothDevice::controller()
{
    return m_controller;
}

void BluetoothDevice::onConnected()
{
    qDebug() << "BluetoothDevice: Connected to" << name() << addressString();
    m_controller->discoverServices();
}

void BluetoothDevice::onDisconnected()
{
    qWarning() << "BluetoothDevice: Disconnected from" << name() << addressString();
    setConnected(false);
    setStatusText("Disconnected from " +  name());
}

void BluetoothDevice::onDeviceError(const QLowEnergyController::Error &error)
{
    qWarning() << "BluetoothDevice: Error" << name() << addressString() << ": " << error << m_controller->errorString();
    setConnected(false);
}

void BluetoothDevice::onDeviceStateChanged(const QLowEnergyController::ControllerState &state)
{
    switch (state) {
    case QLowEnergyController::ConnectingState:
        qDebug() << "BluetoothDevice: Connecting...";
        setStatusText(QString(tr("Connecting to %1...").arg(name())));
        break;
    case QLowEnergyController::ConnectedState:
        qDebug() << "BluetoothDevice: Connected!";
        setStatusText(QString(tr("Connected to %1").arg(name())));
        break;
    case QLowEnergyController::ClosingState:
        qDebug() << "BluetoothDevice: Connection: Closing...";
        setStatusText(QString(tr("Disconnecting from %1...").arg(name())));
        break;
    case QLowEnergyController::DiscoveringState:
        qDebug() << "BluetoothDevice: Discovering...";
        setStatusText(QString(tr("Discovering services of %1...").arg(name())));
        break;
    case QLowEnergyController::DiscoveredState:
        qDebug() << "BluetoothDevice: Discovered!";
        setStatusText(QString(tr("%1 connected and discovered.").arg(name())));
        setConnected(true);
        break;
    case QLowEnergyController::UnconnectedState:
        qDebug() << "BluetoothDevice: Not connected.";
        setStatusText(QString(tr("%1 disconnected.").arg(name())));
        break;
    default:
        qDebug() << "BluetoothDevice: Unhandled state entered:" << state;
        break;
    }
}
