#include "bluetoothagent.h"
#include "globalsize.h"

//取消发送蓝牙设备状态信号,在SessionDbusRegister定义
extern int cancelEmitDevStatus(QString addr);
extern void addDelay(BluezQt::DevicePtr dev);


BluetoothAgent::BluetoothAgent(QObject *parent)
    : Agent(parent)
    , m_pinRequested(false)
    , m_passkeyRequested(false)
    , m_authorizationRequested(false)
    , m_cancelCalled(false)
    , m_releaseCalled(false)
    , m_hasClosePinCode(false)
{
    qDebug() << Q_FUNC_INFO;
    if(daemonIsNotRunning()){
        //QDBusConnection bus = QDBusConnection::systemBus();
        // 在session bus上注册名为"org.bluez.Agent1"的service

        //if (!bus.registerService("org.bluez.Agent1")) {  //注意命名规则-和_
        //        qDebug() << bus.lastError().message();
        //        exit(1);
        //}
        // "QDBusConnection::ExportAllSlots"表示把类Hotel的所有Slot都导出为这个Object的method
        //bus.registerObject("/", this ,QDBusConnection::ExportAllContents);
    }

    QDBusConnection::sessionBus().connect("com.ukui.bluetooth",
                                         "/com/ukui/bluetooth",
                                         "com.ukui.bluetooth",
                                         "replyRequestConfirmation",
                                         this,
                                         SLOT(replyRequestConfirmationFunc(bool)));
}

void BluetoothAgent::emitRemoveSignal(BluezQt::DevicePtr device) {
    if (device.data()->isPaired()) {
        QTimer::singleShot(100,this,[=]{
            emit agentRemoveDevice(device);
        });

    }
}

void BluetoothAgent::replyRequestConfirmationFunc(bool v)
{
    qDebug() << Q_FUNC_INFO << v;
    //if (tmpRequestConfirmation == NULL)
    //    qDebug() << "BluetoothAgent::replyRequestConfirmationFunc--qk-0";
    //qDebug() << "BluetoothAgent::replyRequestConfirmationFunc--qk-01";
    if (v)
        tmpRequestConfirmation.accept();
    else
        tmpRequestConfirmation.reject();


    //发送蓝牙连接信号
    //条件：蓝牙设备未配对，蓝牙适配器配对,且蓝牙设备主动连接
    //约束条件: 点击确定、被动连接、连接成功、配对
    if(v && nullptr != m_device && !GlobalSize::IsBlueDevActive(m_device->address()) &&
            m_device->isConnected() && m_device->isPaired())
    {
        //若对端拒绝、超时等，会出现蓝牙设备状态发送异常情况，暂时无法避免
        addDelay(m_device);
    }

    qDebug() << "BluetoothAgent::replyRequestConfirmationFunc--qk";
}

QDBusObjectPath BluetoothAgent::objectPath() const
{
    return QDBusObjectPath(QStringLiteral("/BluetoothAgent"));
}

void BluetoothAgent::requestPinCode(BluezQt::DevicePtr device, const BluezQt::Request<QString> &request)
{
    qDebug() << Q_FUNC_INFO;
    m_device = device;
    m_pinRequested = true;

    request.accept(QString());

}

void BluetoothAgent::displayPinCode(BluezQt::DevicePtr device, const QString &pinCode)
{
    m_device = device;
    m_displayedPinCode = pinCode;
    qDebug() << Q_FUNC_INFO;
}

void BluetoothAgent::requestPasskey(BluezQt::DevicePtr device, const BluezQt::Request<quint32> &request)
{
    qDebug() << Q_FUNC_INFO;
    m_device = device;
    m_passkeyRequested = true;

    request.accept(0);
}

void BluetoothAgent::displayPasskey(BluezQt::DevicePtr device, const QString &passkey, const QString &entered)
{
    qDebug() << Q_FUNC_INFO << ( m_device.isNull() ? "NULL" : m_device.data()->address() ) << entered << passkey;
    cancelEmitDevStatus(device->address());
    if(m_displayedPasskey == passkey)
        return;
    QDBusMessage displayPasskeySignal  = QDBusMessage::createSignal("/com/ukui/bluetooth",
                                                                    "com.ukui.bluetooth",
                                                                    "displayPasskey");
    displayPasskeySignal << device.data()->name() << passkey;
    QDBusConnection::sessionBus().send(displayPasskeySignal);
}

void BluetoothAgent::requestConfirmation(BluezQt::DevicePtr device, const QString &passkey, const BluezQt::Request<> &request)
{
    qDebug() << Q_FUNC_INFO << device->name() << passkey << device->isConnected() << device->isPaired();

    cancelEmitDevStatus(device->address());

    m_device = device;
    //规避设备类型为耳机、音响设备时还会弹出pin窗口的问题
    if ((nullptr != m_device) &&
        (m_device.data()->type() == BluezQt::Device::AudioVideo ||
         m_device.data()->type() == BluezQt::Device::Headphones ||
         m_device.data()->type() == BluezQt::Device::Headset ))
    {
        request.accept();
    }
    else
    {
        QDBusMessage displayPasskeySignal  = QDBusMessage::createSignal("/com/ukui/bluetooth",
                                                                        "com.ukui.bluetooth",
                                                                        "requestConfirmation");
        displayPasskeySignal << device.data()->name() << passkey;
        QDBusConnection::sessionBus().send(displayPasskeySignal);

        tmpRequestConfirmation = request;
    }
}

void BluetoothAgent::requestAuthorization(BluezQt::DevicePtr device, const BluezQt::Request<> &request)
{
    qDebug() << Q_FUNC_INFO << device->name();
    m_device = device;
    m_authorizationRequested = true;

    request.accept();
}

void BluetoothAgent::authorizeService(BluezQt::DevicePtr device, const QString &uuid, const BluezQt::Request<> &request)
{
    qDebug() << Q_FUNC_INFO << device->name();
    m_device = device;
    m_authorizedUuid = uuid;

    request.accept();
}

void BluetoothAgent::cancel()
{
    qDebug() << Q_FUNC_INFO;
    if (m_cancelCalled)
        return;

    QDBusMessage pairAgentCanceled  = QDBusMessage::createSignal("/com/ukui/bluetooth",
                                                                    "com.ukui.bluetooth",
                                                                    "pairAgentCanceled");

    QDBusConnection::sessionBus().send(pairAgentCanceled);
}

void BluetoothAgent::release()
{
    qDebug() << Q_FUNC_INFO;
    m_releaseCalled = true;
}

int BluetoothAgent::daemonIsNotRunning()
{
    QDBusConnection conn = QDBusConnection::systemBus();
    if (!conn.isConnected())
        return 0;

    QDBusReply<QString> reply = conn.interface()->call("GetNameOwner", "org.bluez.Agent1");
    return reply.value() == "";
}
