//-*-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 "pairedtab.h"
#include <kapplication.h>
#include <dcopclient.h>
#include <klistview.h>
#include <qlistview.h>
#include <kurllabel.h>
#include <kglobal.h>
#include <kpixmap.h>
#include <kiconloader.h>
#include <libkbluetooth/devicemimeconverter.h>
#include <qpushbutton.h>
#include <kmessagebox.h>
#include "dcopcall.h"
#include <kurl.h>
#include <kconfig.h>
#include <krun.h>
#include <qtimer.h>
#include <bluetooth/bluetooth.h>
#include <kdebug.h>
#include <kprocess.h>
#include <kdialogbase.h>
#include <klocale.h>
#include <qfile.h>
#include <qlistview.h>
#include <qpushbutton.h>
#include <kmessagebox.h>
#include <libkbluetooth/namecache.h>
#include <kdirwatch.h>
#include <kapplication.h>
#include <kurlrequester.h>
#include <filesettingsbase.h>

using namespace std;
using namespace KBluetooth;

struct HcidLinkKeyStruct {
        bdaddr_t sba;
        bdaddr_t dba;
        uint8_t  key[16];
        uint8_t  type;
        time_t   time;
};

PairedTab::PairedTab(QWidget *parent, const char* name) :
    PairedTabBase(parent, name)
{
    KConfig* config = KApplication::kApplication()->config();
    linkKeyFilename = config->readEntry("linkKeyFile", "/etc/bluetooth/link_key");
    config->writeEntry("linkKeyFile", linkKeyFilename);
    hcidStartCommand = config->readEntry("hcidStartCommand", "/etc/init.d/bluez-utils start");
    hcidStopCommand = config->readEntry("hcidStopCommand", "/etc/init.d/bluez-utils stop");
    bDirty = false;
    linkKeyFileValid = false;
    reloadList();
    updateGUI();
    linkKeyFileWatch = new KDirWatch(this);
    connect(linkKeyFileWatch, SIGNAL(dirty(const QString&)),
        this, SLOT(slotKeyFileChanged()));
    connect(linkKeyFileWatch, SIGNAL(created(const QString&)),
        this, SLOT(slotKeyFileChanged()));
    connect(linkKeyFileWatch, SIGNAL(deleted(const QString&)),
        this, SLOT(slotKeyFileChanged()));
    connect(removePairingButton, SIGNAL(clicked()),
        this, SLOT(slotRemovePairing()));
    connect(pairingListView, SIGNAL(selectionChanged()),
        this, SLOT(slotSelectionChanged()));
    connect(fileSettingsButton, SIGNAL(leftClickedURL()),
        this, SLOT(slotFileSettings()));
        
    KDialogBase* baseDialog = new KDialogBase(this);
    fileSettingsDialog = new FileSettingsBase(baseDialog);
    baseDialog->setMainWidget(fileSettingsDialog);
    baseDialog->hide();
    connect(baseDialog, SIGNAL(applyClicked()), this, SLOT(slotApplyFileSettings()));
    connect(baseDialog, SIGNAL(okClicked()), this, SLOT(slotApplyFileSettings()));
        
    linkKeyFileWatch->addFile(linkKeyFilename);
    linkKeyFileWatch->startScan(true, true);
}

void PairedTab::reloadList()
{
    if (bDirty) {
        if (KMessageBox::warningContinueCancel(this, i18n(
"The link key file has changed on disk. Do you want to reload the table and \
lose your pending changes?"), i18n("Link Keys Have Changed"), i18n("Reload")) == KMessageBox::Cancel ) {
            return;
        }
    }    

    QFile file(linkKeyFilename);
    
    kdDebug() << "reloadList()" << endl;
    pairingList.clear();
    linkKeyFileValid = false;
    if (file.open(IO_ReadOnly)) {    
        linkKeyFileValid = true;
        bool readSizeMismatch = false;
        while (true) {
            PairingInfo newInfo;
            HcidLinkKeyStruct linkKeyStruct;
            int rSize = 0;
            if ((rSize = file.readBlock((char*)&linkKeyStruct, sizeof(HcidLinkKeyStruct))) 
                == sizeof(HcidLinkKeyStruct)) 
            {
                newInfo.localAddr = DeviceAddress(linkKeyStruct.sba);
                newInfo.remoteAddr = DeviceAddress(linkKeyStruct.dba);
                newInfo.time.setTime_t(linkKeyStruct.time);
                newInfo.type = linkKeyStruct.type;
                for (int n=0; n<16; ++n) {
                    newInfo.linkKey[n] = linkKeyStruct.key[n];
                }
                newInfo.remoteName = QString(newInfo.remoteAddr);
                NameCache::getCachedName(newInfo.remoteAddr, newInfo.remoteName);
                newInfo.remoteClass = 0;
                NameCache::getCachedClass(newInfo.remoteAddr, newInfo.remoteClass);
                pairingList.push_back(newInfo);
            }
            else {
                if (rSize != 0) {
                    readSizeMismatch = true;
                }
                break;
            }
            kdDebug() << "localAddr read:" << QString(newInfo.localAddr) << endl;
        }     
        
        linkKeyFileValid = !readSizeMismatch;
        file.close();
    }
}

bool PairedTab::saveList()
{
    if (bDirty == false) return true;    

    kdDebug() << "saveList()" << endl;
    
    if (!stopDaemon()) return false;
    
    QFile file(linkKeyFilename);
    if (file.open(IO_WriteOnly)) {
        for (unsigned int n=0; n<pairingList.size(); ++n) {
            HcidLinkKeyStruct info;
            info.dba = pairingList[n].remoteAddr.getBdaddr(false);
            for (int p=0; p<16; ++p) {
                info.key[p] = pairingList[n].linkKey[p];
            }
            info.sba = pairingList[n].localAddr.getBdaddr(false);
            info.time = pairingList[n].time.toTime_t();
            info.type = pairingList[n].type;
            file.writeBlock(reinterpret_cast<char*>(&info), sizeof(info));
        }
        file.close();
        
        if (!startDaemon()) return false;

        bDirty = false;
        return true;
    }
    else {
        KMessageBox::error(this, i18n("Could not write \
link key file. Your changes cannot be saved."), i18n("Error"));
        return false;
    }
}

bool PairedTab::stopDaemon()
{
    KProcess daemon;
    daemon << "/bin/sh" << "-c" << hcidStopCommand;
    return daemon.start(KProcess::Block);
}

bool PairedTab::startDaemon()
{
    KProcess daemon;
    daemon << "/bin/sh" << "-c" << hcidStartCommand;
    return daemon.start(KProcess::Block);
}

void PairedTab::updateGUI()
{
    vector<PairingInfo>::iterator pairIt;
    pairingListView->clear();
    for (pairIt = pairingList.begin(); pairIt != pairingList.end(); ++pairIt) {
        QListViewItem *viewItem = new QListViewItem(pairingListView);
        pairIt->listViewItem = viewItem;
        
        viewItem->setText(0, QString(pairIt->remoteName));
        QListViewItem *remoteAddrItem = new QListViewItem(viewItem);
        remoteAddrItem->setPixmap(0, KGlobal::iconLoader()->loadIcon(
            "pda_blue", KIcon::Small, 16));
        remoteAddrItem->setSelectable(false);
        remoteAddrItem->setText(0, QString(pairIt->remoteAddr));
        
        QListViewItem *localAddrItem = new QListViewItem(viewItem);
        localAddrItem->setPixmap(0, KGlobal::iconLoader()->loadIcon(
            "usbpendrive_unmount", KIcon::Small, 16));
        localAddrItem->setSelectable(false);
        localAddrItem->setText(0, QString(pairIt->localAddr));
        
        QListViewItem *timeItem = new QListViewItem(viewItem);
        timeItem->setPixmap(0, KGlobal::iconLoader()->loadIcon(
            "clock", KIcon::Small, 16));
        timeItem->setSelectable(false);
        timeItem->setText(0, pairIt->time.toString());
        
        QString iconName = DeviceClassMimeConverter::classToIconName(pairIt->remoteClass);
        viewItem->setPixmap(0, KGlobal::iconLoader()->loadIcon(
            iconName, KIcon::Small, 16));
    }
}

void PairedTab::slotKeyFileChanged()
{
    kdDebug() << "slotKeyFileChanged()" << endl;
    reloadList();
    updateGUI();
}

void PairedTab::slotRemovePairing()
{
    bool bDirty = false;
    for (int n=pairingList.size()-1; n>=0; --n) {
        if (pairingList[n].listViewItem->isSelected()) {
            pairingList.erase(pairingList.begin()+n);
            bDirty = true;
        }
    }
    if (bDirty) {
        updateGUI();
        this->bDirty = true;
        emit dirty();
    }
}

void PairedTab::slotSelectionChanged()
{
    for (QListViewItem* i=pairingListView->firstChild(); i != NULL;
         i = i->nextSibling()) 
    {
        if (i->isSelected()) {
            removePairingButton->setEnabled(true);
            return;
        }
    }
    removePairingButton->setEnabled(false);
}

void PairedTab::slotFileSettings()
{
    fileSettingsDialog->linkKeyFileEdit->setURL(linkKeyFilename);
    fileSettingsDialog->startCommandEdit->setURL(hcidStartCommand);
    fileSettingsDialog->stopCommandEdit->setURL(hcidStopCommand);
    
    fileSettingsDialog->parentWidget()->show();
}

void PairedTab::slotApplyFileSettings()
{
    linkKeyFileWatch->removeFile(linkKeyFilename);
    
    linkKeyFilename = fileSettingsDialog->linkKeyFileEdit->url();
    hcidStartCommand = fileSettingsDialog->startCommandEdit->url();
    hcidStopCommand = fileSettingsDialog->stopCommandEdit->url();
    
    KConfig* config = KApplication::kApplication()->config();
    config->writeEntry("linkKeyFile", linkKeyFilename);
    config->writeEntry("hcidStartCommand", hcidStartCommand);
    config->writeEntry("hcidStopCommand", hcidStopCommand);
    reloadList();
    updateGUI();

    linkKeyFileWatch->addFile(linkKeyFilename);
}


void PairedTab::apply()
{
    saveList();
}

void PairedTab::defaults()
{
}


PairedTab::~PairedTab()
{
}


#include "pairedtab.moc"
