//-*-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 "servicetab.h"
#include <kapplication.h>
#include <dcopclient.h>
#include <klistview.h>
#include <qlistview.h>
#include <kurllabel.h>
#include <qpushbutton.h>
#include <qtextedit.h>
#include <qcheckbox.h>
#include <kmessagebox.h>
#include "dcopcall.h"
#include <kurl.h>
#include <krun.h>
#include <qtimer.h>
#include <klocale.h>
#include <kdebug.h>

ServiceTab::ServiceTab(QWidget *parent, const char* name) :
    ServiceTabBase(parent, name)
{
    client = KApplication::dcopClient();
    if (client->isAttached()) {
        m_services = getServiceList();
        for (unsigned int n=0; n<m_services.count(); ++n) {
            serviceListView->insertItem(new QCheckListItem(
                serviceListView, m_services[n], QCheckListItem::CheckBox));
            authenticateState[m_services[n]] = getAuthentication(m_services[n]);
            encryptState[m_services[n]] = getEncryption(m_services[n]);
        }
        update();
    }
    else {
        disableInterface(i18n("Cannot access the DCOP-Server."));
    }

    connect(serviceListView, SIGNAL(selectionChanged()),
        this, SLOT(slotSelectionChanged()));
    connect(serviceListView, SIGNAL(clicked(QListViewItem*)),
        this, SLOT(slotItemClicked()));
    connect(enableButton, SIGNAL(clicked()),
        this, SLOT(slotEnableService()));
    connect(disableButton, SIGNAL(clicked()),
        this, SLOT(slotDisableService()));
    connect(docUrlLabel, SIGNAL(leftClickedURL()),
        this, SLOT(slotClickedHelpURL()));
    connect(docUrlLabel, SIGNAL(rightClickedURL()),
        this, SLOT(slotClickedHelpURL()));
    connect(configureButton, SIGNAL(clicked()),
        this, SLOT(slotConfigure()));
    connect(authenticationButton, SIGNAL(stateChanged(int)),
        this, SLOT(slotAuthenticateChanged()));
    connect(encryptionButton, SIGNAL(stateChanged(int)),
        this, SLOT(slotEncryptChanged()));
    QTimer::singleShot(0, this, SLOT(slotUpdate()));
}

void ServiceTab::slotUpdate()
{
    update();
}

void ServiceTab::disableInterface(QString message)
{
    serviceListView->setEnabled(false);
    enableButton->setEnabled(false);
    disableButton->setEnabled(false);
    configureButton->setEnabled(false);
    KMessageBox::error(this, message);
}

void ServiceTab::update()
{
    QCheckListItem *item = (QCheckListItem*)serviceListView->firstChild();
    QString selectedService = QString::null;
    while (item != NULL) {
        QString serviceName = item->text(0);
        bool bEnabled = isEnabled(serviceName);
        item->setText(1, bEnabled?i18n("Enabled"):i18n("Disabled"));
#if (QT_VERSION >= 0x030200)
        item->setState(bEnabled?QCheckListItem::On:QCheckListItem::Off);
#else
        item->setOn(bEnabled?true:false);
#endif
        QString resourceDesc = "";
        QStringList resourceTypes = getResourceTypes(serviceName);
        for (unsigned int r=0; r<resourceTypes.count(); ++r) {
            QString res = getResource(serviceName, resourceTypes[r]);
            resourceDesc += i18n("%1=%2 ")
                .arg(resourceTypes[r]).arg(res);
        }
        item->setText(2, resourceDesc);

        item = (QCheckListItem*)item->nextSibling();
    }

    updateControls();
}

void ServiceTab::updateControls()
{
    bool canEnable = false;
    bool canDisable = false;
    bool bDirty = false;
    QCheckListItem *item = (QCheckListItem*)serviceListView->firstChild();
    int numSelected = 0;
    QCheckListItem* lastSelected = NULL;
    bool authenticateOn(false);
    bool authenticateOff(false);
    bool encryptOn(false);
    bool encryptOff(false);
    
    while (item != NULL) {
        QString serviceName = item->text(0);
        if (item->isSelected()) {
            numSelected++;
            lastSelected = item;
#if (QT_VERSION >= 0x030200)
        if (item->state() == QCheckListItem::Off) {
#else
        if (!item->isOn()) {
#endif
                canEnable = true;
                if (isEnabled(item->text(0)) == true) {
                    bDirty = true;
                }
            }
            else {
                canDisable = true;
                if (isEnabled(item->text(0)) == false) {
                    bDirty = true;
                }
            }
        }
        
        if (item->isSelected()) {
            if (authenticateState[serviceName]) authenticateOn = true;
            else authenticateOff = true;
            
            if (encryptState[serviceName]) encryptOn = true;
            else encryptOff = true;
        }
        
        item = (QCheckListItem*)item->nextSibling();
    }

    // Set encyption/authetication checkboxes
    if (authenticateOn) {
        if (authenticateOff) {
            authenticationButton->setTristate(true);
            authenticationButton->setNoChange();
        }
        else {
            authenticationButton->setTristate(false);
            authenticationButton->setChecked(true);            
        }
        authenticationButton->setEnabled(true);
    }
    else {
        if (authenticateOff) {
            authenticationButton->setEnabled(true);        
        }
        else {
            authenticationButton->setEnabled(false);                
        }
        authenticationButton->setChecked(false);
        authenticationButton->setTristate(false);
    }
    kdDebug() << "authOn=" << authenticateOn << " authOff=" << authenticateOff << endl;
    
    if (encryptOn) {
        if (encryptOff) {
            encryptionButton->setTristate(true);
            encryptionButton->setNoChange();
        }
        else {
            encryptionButton->setTristate(false);
            encryptionButton->setChecked(true);            
        }
        encryptionButton->setEnabled(true);
    }
    else {
        if (encryptOff) {
            encryptionButton->setEnabled(true);        
        }
        else {
            encryptionButton->setEnabled(false);                
        }
        encryptionButton->setChecked(false);
        encryptionButton->setTristate(false);
    }
    //kdDebug() << "encOn=" << encryptOn << " encOff=" << encryptOff << endl;
    //kdDebug() << endl;
        
    if (bDirty) emit dirty();
    enableButton->setEnabled(canEnable);
    disableButton->setEnabled(canDisable);
    configureButton->setEnabled(false);
    
    if (numSelected == 1) {
        QString serviceName = lastSelected->text(0);
        QString docPath = getDocPath(serviceName);
        QString description = getDescription(serviceName);
        descriptionLabel->setText(description);
        if (docPath != QString::null) {
            docUrlLabel->setText(i18n("Open documentation for %1.")
                .arg(serviceName));
            docUrlLabel->setURL(QString("help:/%1").arg(docPath));
            docUrlLabel->setEnabled(true);
        }
        else {
            docUrlLabel->setText(i18n("No documentation available for %1.")
                .arg(serviceName));
            docUrlLabel->setEnabled(false);
        }
        if (canConfigure(serviceName)) {
            configureButton->setEnabled(true);
        }
        else {
            configureButton->setEnabled(false);
        }
    }
    else {
        descriptionLabel->setText("");
        docUrlLabel->setText(i18n("Service Documentation"));
        docUrlLabel->setEnabled(false);
    }
}

void ServiceTab::slotEnableService()
{
    QCheckListItem *item = (QCheckListItem*)serviceListView->firstChild();
    while (item != NULL) {
        if (item->isSelected()) {
#if (QT_VERSION >= 0x030200)
          item->setState(QCheckListItem::On);
#else
          item->setOn(true);
#endif
        }
        item = (QCheckListItem*)item->nextSibling();
    }
    updateControls();
}

void ServiceTab::slotDisableService()
{
    QCheckListItem *item = (QCheckListItem*)serviceListView->firstChild();
    while (item != NULL) {
        if (item->isSelected()) {
#if (QT_VERSION >= 0x030200)
          item->setState(QCheckListItem::Off);
#else
          item->setOn(false);
#endif
        }
        item = (QCheckListItem*)item->nextSibling();
    }
    updateControls();
}

QString ServiceTab::getDocPath(QString serviceName)
{
    DCOPCall dcop(client, "kbluetoothd", "MetaServer");
    dcop.args() << serviceName;
    if (dcop.call("docPath(QString)") == "QString") {
        QString docPath;
        dcop.ret() >> docPath;
        return docPath;
    }
    else {
        disableInterface(i18n("DCOP error when calling docPath()"));
        return QString::null;
    }
}

QString ServiceTab::getDescription(QString serviceName)
{
    DCOPCall dcop(client, "kbluetoothd", "MetaServer");
    dcop.args() << serviceName;
    if (dcop.call("description(QString)") == "QString") {
        QString desc;
        dcop.ret() >> desc;
        return desc;
    }
    else {
        disableInterface(i18n("DCOP error when calling description()"));
        return QString::null;
    }
}

bool ServiceTab::canConfigure(QString serviceName)
{
    return getMetaServerBoolValue(serviceName, "canConfigure");
}

bool ServiceTab::getAuthentication(QString serviceName)
{
    return getMetaServerBoolValue(serviceName, "getAuthentication");
}

bool ServiceTab::getEncryption(QString serviceName)
{
    return getMetaServerBoolValue(serviceName, "getEncryption");
}

bool ServiceTab::getMetaServerBoolValue(QString serviceName, QString function)
{
    DCOPCall dcop(client, "kbluetoothd", "MetaServer");
    dcop.args() << serviceName;
    if (dcop.call(function+"(QString)") == "bool") {
        bool ret;
        dcop.ret() >> ret;
        return ret;
    }
    else {
        disableInterface(i18n("DCOP error when calling %1()").arg(function));
        return false;
    }
}

void ServiceTab::setMetaServerBoolValue(QString serviceName, 
    QString function, bool bVal)
{
    DCOPCall dcop(client, "kbluetoothd", "MetaServer");
    dcop.args() << serviceName << bVal;
    if (dcop.call(function+"(QString, bool)") != "void") {
        disableInterface(i18n("DCOP error when calling %1()").arg(function));
    }
}

void ServiceTab::configure(QString serviceName)
{
    DCOPCall dcop(client, "kbluetoothd", "MetaServer");
    dcop.args() << serviceName;
    if (dcop.call("configure(QString)") != "void") {
        disableInterface(i18n("DCOP error when calling docPath()"));
    }
}


QStringList ServiceTab::getResourceTypes(QString serviceName)
{
    DCOPCall dcop(client, "kbluetoothd", "MetaServer");
    dcop.args() << serviceName;
    if (dcop.call("resourceTypes(QString)") == "QStringList") {
        QStringList resourceTypes;
        dcop.ret() >> resourceTypes;
        return resourceTypes;
    }
    else {
        disableInterface(i18n("DCOP error when calling resourceTypes()"));
        return QStringList();
    }
}

QString ServiceTab::getResource(QString serviceName, QString resourceType)
{
    DCOPCall dcop(client, "kbluetoothd", "MetaServer");
    dcop.args() << serviceName << resourceType;
    if (dcop.call("resources(QString,QString)") == "QString") {
        QString res;
        dcop.ret() >> res;
        return res;
    }
    else {
        disableInterface(i18n("DCOP error: resources() failed."));
        return QString::null;
    }
}

bool ServiceTab::isEnabled(QString serviceName)
{
    return getMetaServerBoolValue(serviceName, "isEnabled");
}


QStringList ServiceTab::getServiceList()
{
    DCOPCall dcop(client, "kbluetoothd", "MetaServer");
    if (dcop.call("services()")!="QStringList") {
        disableInterface(i18n("DCOP error when calling services()"));
        return QStringList();
    }
    else {
        QStringList services;
        dcop.ret() >> services;
        return services;
    }
}

void ServiceTab::apply()
{
    QCheckListItem *item = (QCheckListItem*)serviceListView->firstChild();
    QString selectedService = QString::null;
    while (item != NULL) {
        QString serviceName = item->text(0);
        bool bEnabled = isEnabled(serviceName);
#if (QT_VERSION >= 0x030200)
        bool bChecked = (item->state()==QCheckListItem::On);
#else
        bool bChecked = (item->isOn());
#endif
        if (bEnabled != bChecked) {
            DCOPCall dcop(client, "kbluetoothd", "MetaServer");
            dcop.args() << serviceName << bChecked;
            dcop.call("setEnabled(QString,bool)");
            dcop.args() << serviceName << true;
            dcop.call("setServiceRegistrationEnabled(QString,bool)");
        }
        item = (QCheckListItem*)item->nextSibling();
    }
    
    for (uint n=0; n<authenticateState.size(); ++n) {
        setMetaServerBoolValue(m_services[n], 
            "setAuthentication", authenticateState[m_services[n]]);
    }
    for (uint n=0; n<encryptState.size(); ++n) {
        setMetaServerBoolValue(m_services[n], 
            "setEncryption", encryptState[m_services[n]]);
    }
    
    update();
}

void ServiceTab::slotItemClicked()
{
    updateControls();
}


void ServiceTab::defaults()
{
    KMessageBox::information(this, i18n("Not implemented"));
}

void ServiceTab::slotSelectionChanged()
{
    updateControls();
}

void ServiceTab::slotClickedHelpURL()
{
    new KRun(KURL(docUrlLabel->url()), 0, false, false);
}

void ServiceTab::slotConfigure()
{
    QCheckListItem *item = (QCheckListItem*)serviceListView->firstChild();
    while (item != NULL) {
        if (item->isSelected()) {
            configure(item->text(0));        
        }
        item = (QCheckListItem*)item->nextSibling();
    }
}

void ServiceTab::slotEncryptChanged() 
{
    QCheckListItem *item = (QCheckListItem*)serviceListView->firstChild();
    while (item != NULL) {
        QString service = item->text(0);
        if (item->isSelected()) {
            switch (encryptionButton->state()) {
            case QButton::NoChange: break;
            case QButton::On: encryptState[service] = true; break;
            case QButton::Off: encryptState[service] = false; break;
            }
        }
        item = (QCheckListItem*)item->nextSibling();
    }    
    emit dirty();
}

void ServiceTab::slotAuthenticateChanged()
{
    kdDebug() << "slotAutehChanged" << endl;
    QCheckListItem *item = (QCheckListItem*)serviceListView->firstChild();
    while (item != NULL) {
        QString service = item->text(0);
        if (item->isSelected()) {
            switch (authenticationButton->state()) {
            case QButton::NoChange: break;
            case QButton::On: authenticateState[service] = true; break;
            case QButton::Off: authenticateState[service] = false; break;
            }
            kdDebug() << "slotAuthChanged " << service << 
                " is " << authenticateState[service] << endl;
        }
        item = (QCheckListItem*)item->nextSibling();
    }
    emit dirty();
}

ServiceTab::~ServiceTab()
{
}


#include "servicetab.moc"
