//-*-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 "confirmationtab.h"
#include <qtable.h>
#include <qheader.h>
#include "dcopcall.h"
#include <dcopclient.h>
#include <kapplication.h>
#include <kmessagebox.h>
#include <kpushbutton.h>
#include <klocale.h>
#include <libkbluetooth/deviceaddress.h>
#include <libkbluetooth/namecache.h>
#include <algorithm>
#include <vector>

using namespace std;
using namespace KBluetooth;

ConfirmationTab::ConfirmationTab(QWidget *parent, const char* name) :
    ConfirmationTabBase(parent, name),
    policyColumn(3),
    addrColumn(2),
    serviceColumn(0),
    nameColumn(1)
{
    client = KApplication::dcopClient();
    readRules();
    ruleTable->setRowMovingEnabled(true);
    connect(upButton, SIGNAL(clicked()), this, SLOT(moveUp()));
    connect(downButton, SIGNAL(clicked()), this, SLOT(moveDown()));
    connect(insertButton, SIGNAL(clicked()), this, SLOT(insertRule()));
    connect(deleteButton, SIGNAL(clicked()), this, SLOT(deleteRule()));
    connect(ruleTable, SIGNAL(valueChanged(int,int)), this, SLOT(valueChanged(int,int)));
    connect(ruleTable, SIGNAL(selectionChanged()), this, SLOT(selectionChanged()));
}


void ConfirmationTab::readRules()
{
    DCOPCall dcop(client, "kbluetoothd", "MetaServer");
    DCOPCall nameCache(client, "kbluetoothd", "DeviceNameCache");
        
    if (dcop.call("services()") == "QStringList") {
        dcop.ret() >> serviceList;
    }
    serviceList.append("*");
    
    if (dcop.call("getRulePolicyList()") == "QStringList") {
        dcop.ret() >> policyList;
    }
    
    if (dcop.call("numConnectionRules()") != "int") return;
    int numRules;
    dcop.ret() >> numRules;
    ruleTable->setNumRows(numRules);
    for (int n=0; n<numRules; ++n) {
        QString addrStr, service, policy;
        bool success = true;
        dcop.args() << n;
        success &= (dcop.call("getRuleAddress(int)") == "QString");
        dcop.ret() >> addrStr;
        dcop.args() << n;
        success &= (dcop.call("getRuleService(int)") == "QString");
        dcop.ret() >> service;
        dcop.args() << n;
        success &= (dcop.call("getRulePolicy(int)") == "QString");
        dcop.ret() >> policy;
        
        if (success) {
            setRow(n, policy, service, addrStr);
        }
    }  
}

void ConfirmationTab::apply()
{
    DCOPCall dcop(client, "kbluetoothd", "MetaServer");
    if (dcop.call("numConnectionRules()") != "int") return;
    int numRules, n;
    dcop.ret() >> numRules;

    for (n=0; n<numRules; ++n) {
        dcop.args() << 0;
        dcop.call("deleteConnectionRule(int)");
    }
    
    for (n=0; n<ruleTable->numRows(); ++n) {
        dcop.args() << n << ruleTable->text(n, addrColumn) 
            << ruleTable->text(n, serviceColumn) << ruleTable->text(n, policyColumn);
        dcop.call("insertConnectionRule(int,QString,QString,QString)");
    }
}

void ConfirmationTab::defaults()
{

}

void ConfirmationTab::setRow(int n, QString policy, QString service, QString addrStr)
{
    QComboTableItem *policyItem = new QComboTableItem(ruleTable, policy);
    policyItem->setStringList(policyList);
    ruleTable->setItem(n, policyColumn, policyItem);
    policyItem->setCurrentItem(max(0,policyList.findIndex(policy)));
    
    QComboTableItem *serviceItem = new QComboTableItem(ruleTable, service);
    serviceItem->setStringList(serviceList);
    ruleTable->setItem(n, serviceColumn, serviceItem);
    serviceItem->setCurrentItem(max(0,serviceList.findIndex(service)));
    
    QTableItem *deviceNameItem = new QTableItem(
        ruleTable, QTableItem::OnTyping, "");
    ruleTable->setItem(n, nameColumn, deviceNameItem);
    
    QTableItem *deviceAddrItem = new QTableItem(
        ruleTable, QTableItem::OnTyping, addrStr);
    ruleTable->setItem(n, addrColumn, deviceAddrItem);

    updateNameFromAddr(n);
}

void ConfirmationTab::removeRowSelection(int row)
{
    for (int n=ruleTable->numSelections(); n>=0; --n) {
        QTableSelection sel = ruleTable->selection(n);
        if (sel.topRow()<=row && sel.bottomRow()>=row) {
            ruleTable->removeSelection(n);
            if (sel.topRow()<row) {
                ruleTable->addSelection(QTableSelection(
                    sel.topRow(), sel.leftCol(), row-1, sel.rightCol()));
            }
            if (sel.bottomRow()>row) {
                ruleTable->addSelection(QTableSelection(
                    row+1, sel.leftCol(), sel.bottomRow(), sel.rightCol()));
            }
        }
    }
}

void ConfirmationTab::swapRows(int oldRow, int newRow)
{
    bool oldSelected(ruleTable->isRowSelected(oldRow));
    bool newSelected(ruleTable->isRowSelected(newRow));
    for (int col=0; col<ruleTable->numCols(); ++col) {
        QTableItem *oldItem = ruleTable->item(oldRow, col);
        QTableItem *newItem = ruleTable->item(newRow, col);
        ruleTable->takeItem(oldItem);
        ruleTable->takeItem(newItem);
        ruleTable->setItem(newRow, col, oldItem);
        ruleTable->setItem(oldRow, col, newItem);
    }
    int numCols = ruleTable->numCols();
    if (newSelected) {
        ruleTable->addSelection(QTableSelection(oldRow, 0, oldRow, numCols));
    }
    else {
        removeRowSelection(oldRow);
    }
    if (oldSelected) {
        ruleTable->addSelection(QTableSelection(newRow, 0, newRow, numCols));   
    }
    else {
        removeRowSelection(newRow);
    }
    if (ruleTable->currentRow() == oldRow) {
        ruleTable->setCurrentCell(newRow, ruleTable->currentColumn());
    }
    else if (ruleTable->currentRow() == newRow) {
        ruleTable->setCurrentCell(oldRow, ruleTable->currentColumn());
    }
}

void ConfirmationTab::moveUp()
{
    ruleTable->setUpdatesEnabled(false);
    for (int n=0; n<ruleTable->numRows()-1; ++n) {
        if (!ruleTable->isRowSelected(n) &&
            ruleTable->isRowSelected(n+1))
        {
            swapRows(n, n+1);    
        }
    }
    ruleTable->setUpdatesEnabled(true);
    ruleTable->repaint();
    selectionChanged();
    emit dirty();
}


void ConfirmationTab::moveDown()
{
    ruleTable->setUpdatesEnabled(false);
    for (int n=ruleTable->numRows()-2; n>=0; --n) {
        if (ruleTable->isRowSelected(n) &&
            !ruleTable->isRowSelected(n+1))
        {    
            swapRows(n, n+1);    
        }
    }
    ruleTable->setUpdatesEnabled(true);
    ruleTable->repaint();
    selectionChanged();
    emit dirty();
}

void ConfirmationTab::deleteRule()
{
    if (ruleTable->numSelections() == 0) return;
    if (KMessageBox::warningContinueCancel(NULL, i18n("Delete the selected rules?"),i18n("Delete Rules"),KGuiItem(i18n("&Delete"),"editdelete")) == KMessageBox::Continue) {
        for (int n=ruleTable->numSelections()-1; n>=0; --n) {
            QTableSelection sel = ruleTable->selection(n);
            for (int r=sel.bottomRow(); r>=sel.topRow(); --r) {
                ruleTable->removeRow(r);
            }            
        }
    }
    emit dirty();
}

void ConfirmationTab::insertRule()
{
    int row = 0;
    if (ruleTable->numSelections() > 0) {
        row = ruleTable->selection(0).anchorRow();
    }
    ruleTable->insertRows(row, 1);
    setRow(row, "ask", "*", QString(KBluetooth::DeviceAddress::invalid));
    ruleTable->clearSelection();
    ruleTable->selectRow(row);
    emit dirty();
}

void ConfirmationTab::updateNameFromAddr(int row)
{
    QString addrStr = ruleTable->text(row, addrColumn);
    if (addrStr.contains("*") || QString(KBluetooth::DeviceAddress::any) == addrStr) {
        ruleTable->setText(row, addrColumn, KBluetooth::DeviceAddress::any);
        ruleTable->setText(row, nameColumn, "*");
    }
    else {
        QString deviceName = "*";
        if (DeviceAddress(addrStr) != KBluetooth::DeviceAddress::any) {
            if (KBluetooth::NameCache::getCachedName(
                DeviceAddress(addrStr), deviceName)) {
                if (deviceName == "*") deviceName == "[*]";
            }
            if (DeviceAddress(deviceName) == DeviceAddress(addrStr)) {
                deviceName = QString("[%1]").arg(i18n("unknown"));
            }
        }
        ruleTable->setText(row, nameColumn, deviceName);
        ruleTable->setText(row, addrColumn, QString(DeviceAddress(addrStr)));
    }
}

void ConfirmationTab::valueChanged(int row, int col)
{
    if (col == nameColumn) {
        QString nameStr = ruleTable->text(row, nameColumn);
        if (nameStr == "*") {
            ruleTable->setText(row, addrColumn, KBluetooth::DeviceAddress::any);
        }
        else {
            DeviceAddress addr;
            if (KBluetooth::NameCache::resolveCachedName(nameStr, addr)) {
                ruleTable->setText(row, addrColumn, QString(addr));
            }
            else {
                updateNameFromAddr(row);
            }
        }    
    }
    
    if (col == addrColumn) {
        updateNameFromAddr(row);
    }
    emit dirty();
}

void ConfirmationTab::selectionChanged()
{
    bool hasSelection = (ruleTable->numSelections() > 0);
    upButton->setEnabled(hasSelection);
    downButton->setEnabled(hasSelection);
    deleteButton->setEnabled(hasSelection);
}

void ConfirmationTab::disableInterface(QString message)
{
    KMessageBox::error(this, message);
}


ConfirmationTab::~ConfirmationTab()
{

}


#include "confirmationtab.moc"
