//-*-c++-*-
/***************************************************************************
 *   Copyright (C) 2003 by Fred Schaettgen                                 *
 *   kbluetoothd@schaettgen.de                                             *
 *                                                                         *
 *   This program 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.                                   *
 ***************************************************************************/

#include <qtimer.h>
#include <kcombobox.h>
#include <kprogress.h>
#include <kdebug.h>
#include <kapplication.h>
#include <qlabel.h>
#include <qpushbutton.h>
#include <klocale.h>
#include <klineedit.h>
#include "procinheritsock.h"
#include <libkbluetooth/adapter.h>
#include <libkbluetooth/hcisocket.h>
#include <libkbluetooth/namecache.h>

#include "connectiondlg.h"
#include "conmainwidget.h"
#include "condetailswidget.h"
#include <kmessagebox.h>


using namespace KBluetooth;

ConnectionDlg::ConnectionDlg(QWidget* parent) :
    KDialogBase(parent, "ConnectionDlg", false, i18n("Connection Info"),
        KDialogBase::Close | KDialogBase::Details)
{
    this->address = DeviceAddress::invalid;
    this->deviceName = i18n("invalid");

    mainDlg = new ConnectionMainWidget(this);
    connect(mainDlg->linkComboBox, SIGNAL(activated(int)),
        this, SLOT(connectionSelected(int)));
    detailsDlg = new ConnectionDetailsWidget(this);
    setMainWidget(mainDlg);
    mainDlg->setMinimumSize(mainDlg->sizeHint());
    setDetailsWidget(detailsDlg);
    detailsDlg->setMinimumSize(detailsDlg->sizeHint());

    connect(detailsDlg->killButton, SIGNAL(clicked()), 
        this, SLOT(killCurrentConnection()));
    
    mainDlg->deviceName->setText(deviceName);
    mainDlg->address->setText(QString(deviceName));

    mainDlg->mainPage->setEnabled(false);
    detailsDlg->setEnabled(false);

    mainDlg->rssidProgressBar->setFormat("");
    mainDlg->rssidProgressBar->setTotalSteps(100);

    timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(slotTimer()));
    timer->start(500);
    slotTimer();
}


ConnectionDlg::~ConnectionDlg()
{
}

void ConnectionDlg::slotTimer()
{
    if (isVisible()) {
        update();
    }
}

void ConnectionDlg::update()
{
    // Update the list of ACL links
    Adapters adapters;
    bool currentLinkFound = false;
    if (adapters.count() > 0) {
        Adapter::ConnectionInfoVector connections = adapters[0].getAclConnections();
        Adapter::ConnectionInfo currentLinkInfo;
        for (int n=0; n < int(connections.count()); n++) {
            DeviceAddress nAddr = connections[n].address;
            QString linkLabel = QString(connections[n].address);
            if (n < mainDlg->linkComboBox->count()) {
                if (mainDlg->linkComboBox->text(n) != linkLabel) {
                    mainDlg->linkComboBox->changeItem(linkLabel, n);
                }
            }
            else {
                mainDlg->linkComboBox->insertItem(linkLabel);
            }
            if (nAddr == selectedAddress) {
                currentLinkFound = true;
                currentLinkInfo = connections[n];
                mainDlg->linkComboBox->setCurrentItem(n);
            }
        }
        for (int n = mainDlg->linkComboBox->count(); n > int(connections.count()); --n) {
            mainDlg->linkComboBox->removeItem(connections.count());
        }

        if (currentLinkFound == false && connections.count() > 0) {
            selectedAddress = connections[0].address;
            currentLinkInfo = connections[0];
            currentLinkFound = true;
        }

        if (currentLinkFound == true) {
            // Update the user interface with new information
            // for the selected link
            HciSocket *hcisocket = new HciSocket(0);
            hcisocket->open();
            int s = hcisocket->socket();
            uint16_t ch = uint16_t(currentLinkInfo.handle);
            mainDlg->address->setText(QString(currentLinkInfo.address));
            QString cachedName;
            KBluetooth::NameCache::getCachedName(currentLinkInfo.address, cachedName);
            mainDlg->deviceName->setText(cachedName);
            detailsDlg->handle->setText(QString("%1 (0x%2)")
                .arg(ch, 0, 10).arg(ch, 0, 16));
            detailsDlg->direction->setText(
                currentLinkInfo.out?i18n("outgoing"):i18n("incoming"));
            detailsDlg->linkMode->setText(QString("%1 (0x%2)")
                .arg(currentLinkInfo.link_mode, 0, 10).arg(currentLinkInfo.link_mode, 0, 16));
            updateRssi(s, ch);
            updateRole(s, ch);

            delete hcisocket;
        }
    }
    else {
        mainDlg->linkComboBox->clear();
    }
    mainDlg->mainPage->setEnabled(currentLinkFound);
    detailsDlg->setEnabled(currentLinkFound);
}

void ConnectionDlg::updateRssi(int dd, uint16_t conHandle)
{
    // Read RSSI
    read_rssi_rp rp;
    struct hci_request rq;
    memset(&rq, 0, sizeof(rq));
    rq.ogf = OGF_STATUS_PARAM;
    rq.ocf = OCF_READ_RSSI;
    rq.cparam = &conHandle;
    rq.clen = 2;
    rq.rparam = &rp;
    rq.rlen = READ_RSSI_RP_SIZE;

    if (hci_send_req(dd, &rq, 100) < 0) {
        kdDebug() << "HCI get_link_quality request failed" << endl;
        return;
    }

    if (rp.status != 0) {
        kdDebug() << "HCI get_link_quality cmd failed. " << rp.status << endl;
        return;
    }
    //this->signalStrength = rp.rssi;

    // update the user interface
    const int minRssid = -50;
    const int maxRssid = 50;
    mainDlg->rssidProgressBar->setFormat(QString("%1dB").arg(rp.rssi));
    mainDlg->rssidProgressBar->setValue(
        (100*(rp.rssi-minRssid))/(maxRssid-minRssid));
}


void ConnectionDlg::updateRole(int dd, uint16_t conHandle)
{
    role_discovery_rp rp;
    struct hci_request rq;
    memset(&rq, 0, sizeof(rq));
    rq.ogf = OGF_LINK_POLICY;
    rq.ocf = OCF_ROLE_DISCOVERY;
    rq.cparam = &conHandle;
    rq.clen = 2;
    rq.rparam = &rp;
    rq.rlen = ROLE_DISCOVERY_RP_SIZE;

    if (hci_send_req(dd, &rq, 100) < 0) {
        kdDebug() << "HCI role_discovery request failed" << endl;
        return;
    }

    if (rp.status != 0) {
        kdDebug() << "HCI role_discovery cmd failed. " << rp.status << endl;
        return;
    }

    // update the user interface
    if (rp.role == 0) {
        detailsDlg->role->setText(i18n("master"));
    }
    else {
        detailsDlg->role->setText(i18n("slave"));
    }
}

void ConnectionDlg::connectionSelected(int n)
{
    // Update the list of ACL links
    Adapters adapters;
    selectedAddress = DeviceAddress::invalid;
    if (adapters.count() > 0) {
        Adapter::ConnectionInfoVector connections = adapters[0].getAclConnections();
        if (n < int(connections.count())) {
            selectedAddress = connections[n].address;
        }
    }
    update();
}

void ConnectionDlg::killCurrentConnection()
{
    KProcessInheritSocket process(0);
    process << "kdesu" << "hcitool" << "dc" << QString(selectedAddress);
    if (!process.start(KProcess::DontCare)) {
        KMessageBox::information(this,
            i18n("Could not start hcitool to kill the connection."),
            i18n("KBluetoothD"));
    }
}

#include "connectiondlg.moc"
