/*
 *
 *  Authorization Agent implementation of bluez5
 *
 *  Copyright (C) 2019  Emanoil Kotsev <deloptes@gmail.com>
 *
 *
 *  This file is part of tdebluezauth.
 *
 *  tdebluezauth is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  tdebluezauth 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 kbluetooth; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

// TQt includes
#include <tqdbusobjectpath.h>
#include <deviceImpl.h>
#include <btuuids.h>

#include "authservice.h"
#include "pindialog.h"
#include "authorize.h"

#define DBUS_AUTH_SERVICE_PATH  "/org/trinitydesktop/tdebluez"

Agent1InterfaceImpl::Agent1InterfaceImpl(TQT_DBusConnection &conn) :
        m_connection(&conn)
{
}

Agent1InterfaceImpl::~Agent1InterfaceImpl()
{
}


/*!
 * Implement virtual methods
 *
 */

void Agent1InterfaceImpl::handleMethodReply(const TQT_DBusMessage& reply)
{
    m_connection->send(reply);
}

bool Agent1InterfaceImpl::Release(TQT_DBusError& error)
{
    // do something
    return true;
}

void Agent1InterfaceImpl::RequestPinCodeAsync(int asyncCallId, const TQT_DBusObjectPath& device)
{
    TQT_DBusError error;
    TDEBluetooth::DeviceImpl *devImpl = new TDEBluetooth::DeviceImpl("org.bluez", device);
    devImpl->setConnection((*m_connection));
    TQString addr = devImpl->getAddress(error);
    TQString name = devImpl->getAlias(error);
    delete devImpl;
    PinDialog *pinDialog = new PinDialog(addr, name);
    pinDialog->pinDlg->pinEdit->setText(TQString());
    pinDialog->pinDlg->pinEdit->setEnabled(true);
    KDialogBase::centerOnScreen(pinDialog);
    pinDialog->setActiveWindow();
    pinDialog->show();
    pinDialog->raise();

    if (pinDialog->exec() == TQDialog::Accepted)
        RequestPinCodeAsyncReply(asyncCallId, pinDialog->pinDlg->pinEdit->text());
    else
        RequestPinCodeAsyncError(asyncCallId, TQT_DBusError::stdFailed("Request canceled"));
    delete pinDialog;
}

void Agent1InterfaceImpl::DisplayPinCodeAsync(int asyncCallId, const TQT_DBusObjectPath& device, const TQString& pincode)
{
    TQT_DBusError error;
    TDEBluetooth::DeviceImpl *devImpl = new TDEBluetooth::DeviceImpl("org.bluez", device);
    devImpl->setConnection((*m_connection));
    TQString addr = devImpl->getAddress(error);
    TQString name = devImpl->getAlias(error);
    kdDebug() << addr << " " << name << endl;
    delete devImpl;
    PinDialog *pinDialog = new PinDialog(addr, name);
    pinDialog->pinDlg->pinEdit->setText(TQString("%1").arg(pincode));
    pinDialog->pinDlg->pinEdit->setEnabled(false);
    KDialogBase::centerOnScreen(pinDialog);
    pinDialog->setActiveWindow();
    pinDialog->show();
    pinDialog->raise();

    if (pinDialog->exec() == TQDialog::Accepted)
        DisplayPinCodeAsyncReply(asyncCallId);
    else
        DisplayPinCodeAsyncError(asyncCallId, TQT_DBusError::stdFailed("Request not accepted"));
    delete pinDialog;
}

void Agent1InterfaceImpl::RequestPasskeyAsync(int asyncCallId, const TQT_DBusObjectPath& device)
{
    TQT_DBusError error;
    TDEBluetooth::DeviceImpl *devImpl = new TDEBluetooth::DeviceImpl("org.bluez", device);
    devImpl->setConnection((*m_connection));
    TQString addr = devImpl->getAddress(error);
    TQString name = devImpl->getAlias(error);
    delete devImpl;
    PinDialog *pinDialog = new PinDialog(addr, name);
    pinDialog->pinDlg->pinEdit->setText(TQString());
    pinDialog->pinDlg->pinEdit->setEnabled(true);
    KDialogBase::centerOnScreen(pinDialog);
    pinDialog->setActiveWindow();
    pinDialog->show();
    pinDialog->raise();

    if (pinDialog->exec() == TQDialog::Accepted)
        RequestPasskeyAsyncReply(asyncCallId, pinDialog->pinDlg->pinEdit->text().toUInt());
    else
        RequestPasskeyAsyncError(asyncCallId, TQT_DBusError::stdFailed("Request not accepted"));
    delete pinDialog;
}

void Agent1InterfaceImpl::DisplayPasskeyAsync(int asyncCallId, const TQT_DBusObjectPath& device, TQ_UINT32 passkey, TQ_UINT16 entered)
{
    TQT_DBusError error;
    TDEBluetooth::DeviceImpl *devImpl = new TDEBluetooth::DeviceImpl("org.bluez", device);
    devImpl->setConnection((*m_connection));
    TQString addr = devImpl->getAddress(error);
    TQString name = devImpl->getAlias(error);
    delete devImpl;
    PinDialog *pinDialog = new PinDialog(addr, name);
    pinDialog->pinDlg->pinEdit->setText(TQString("%1").arg(passkey));
    pinDialog->pinDlg->pinEdit->setEnabled(false);
    KDialogBase::centerOnScreen(pinDialog);
    pinDialog->setActiveWindow();
    pinDialog->show();
    pinDialog->raise();

    if (pinDialog->exec() == TQDialog::Accepted)
        DisplayPasskeyAsyncReply(asyncCallId);
    else
        DisplayPasskeyAsyncError(asyncCallId, TQT_DBusError::stdFailed("Request not accepted"));
    delete pinDialog;
}

void Agent1InterfaceImpl::RequestConfirmationAsync(int asyncCallId, const TQT_DBusObjectPath& device, TQ_UINT32 passkey)
{
    TQT_DBusError error;
    TDEBluetooth::DeviceImpl *devImpl = new TDEBluetooth::DeviceImpl("org.bluez", device);
    devImpl->setConnection((*m_connection));
    TQString addr = devImpl->getAddress(error);
    TQString name = devImpl->getAlias(error);
    delete devImpl;
    PinDialog *pinDialog = new PinDialog(addr, name);
    pinDialog->pinDlg->pinEdit->setText(TQString("%3").arg(passkey));
    pinDialog->pinDlg->pinEdit->setEnabled(false);
    KDialogBase::centerOnScreen(pinDialog);
    pinDialog->setActiveWindow();
    pinDialog->show();
    pinDialog->raise();

    if (pinDialog->exec() == TQDialog::Accepted)
        RequestConfirmationAsyncReply(asyncCallId);
    else
        RequestConfirmationAsyncError(asyncCallId, TQT_DBusError::stdFailed("Request not accepted"));
    delete pinDialog;
}

void Agent1InterfaceImpl::RequestAuthorizationAsync(int asyncCallId, const TQT_DBusObjectPath& device)
{
    TQT_DBusError error;
    TDEBluetooth::DeviceImpl *devImpl = new TDEBluetooth::DeviceImpl("org.bluez", device);
    devImpl->setConnection((*m_connection));
    TQString addr = devImpl->getAddress(error);
    TQString name = devImpl->getAlias(error);
    delete devImpl;
    AuthorizeDialog *authDialog = new AuthorizeDialog(addr, name, TQString());
    KDialogBase::centerOnScreen(authDialog);
    authDialog->setActiveWindow();
    authDialog->show();
    authDialog->raise();

    if (authDialog->exec() == TQDialog::Accepted)
        RequestAuthorizationAsyncReply(asyncCallId);
    else
        RequestAuthorizationAsyncError(asyncCallId, TQT_DBusError::stdFailed("Request not authorized"));
    delete authDialog;
}

void Agent1InterfaceImpl::AuthorizeServiceAsync(int asyncCallId, const TQT_DBusObjectPath& device, const TQString& uuid)
{
    kdDebug() << __func__ << "()" << endl;

    TQT_DBusError error;
    TDEBluetooth::DeviceImpl *devImpl = new TDEBluetooth::DeviceImpl("org.bluez", device);
    devImpl->setConnection((*m_connection));
    TQString addr = devImpl->getAddress(error);
    TQString name = devImpl->getAlias(error);
    delete devImpl;
    AuthorizeDialog *authDialog = new AuthorizeDialog(addr, name, resolveUUID(uuid));
    KDialogBase::centerOnScreen(authDialog);
    authDialog->setActiveWindow();
    authDialog->show();
    authDialog->raise();

    if (authDialog->exec() == TQDialog::Accepted)
        AuthorizeServiceAsyncReply(asyncCallId);
    else
        AuthorizeServiceAsyncError(asyncCallId, TQT_DBusError::stdFailed("Request not accepted"));
    delete authDialog;
}

bool Agent1InterfaceImpl::Cancel(TQT_DBusError& error)
{
    kdDebug() << __func__ << "()" << endl;

    // do something
    return true;
}

RootNodeService::RootNodeService(TQT_DBusConnection &connection) :
        DBusBaseNode(), m_connection(connection)
{
    addChildNode("org");
    registerObject(m_connection, "/");
}

RootNodeService::~RootNodeService()
{
}

TQT_DBusObjectBase* RootNodeService::createInterface(const TQString& interfaceName)
{
    return (TQT_DBusObjectBase*) m_interfaces[interfaceName];
}

OrgNodeService::OrgNodeService(TQT_DBusConnection &connection) :
        DBusBaseNode(), m_connection(connection)
{
    addChildNode("trinitydesktop");
    registerObject(m_connection, "/org");
}

OrgNodeService::~OrgNodeService()
{
}

TQT_DBusObjectBase* OrgNodeService::createInterface(const TQString& interfaceName)
{
    return (TQT_DBusObjectBase*) m_interfaces[interfaceName];
}

TrinityDekstopNodeService::TrinityDekstopNodeService(TQT_DBusConnection &connection) :
        DBusBaseNode(), m_connection(connection)
{
    addChildNode("tdebluez");
    registerObject(m_connection, "/org/trinitydesktop");
}

TrinityDekstopNodeService::~TrinityDekstopNodeService()
{
}

TQT_DBusObjectBase* TrinityDekstopNodeService::createInterface(const TQString& interfaceName)
{
    return (TQT_DBusObjectBase*) m_interfaces[interfaceName];
}

AuthService::AuthService(TQT_DBusConnection &conn) :
        org::trinitydesktop::tdebluezNode(), m_connection(conn)
{
    m_interfaces.insert("org.freedesktop.DBus.Introspectable", this);
    m_interfaces.insert("org.bluez.Agent1", new Agent1InterfaceImpl(m_connection));
    registerObject(m_connection, DBUS_AUTH_SERVICE_PATH);
}

AuthService::~AuthService()
{
}

TQT_DBusObjectBase* AuthService::createInterface(const TQString& interfaceName)
{
    return (TQT_DBusObjectBase*) m_interfaces[interfaceName];
}
