/***************************************************************************
 *                                                                         *
 *   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 <sys/types.h>
#include <sys/stat.h>

#include <kiconloader.h>
#include <kconfig.h>
#include <kwinmodule.h>
#include <kwin.h>
#include <netwm_def.h>

#include <qvbox.h>
#include <qhbox.h>
#include <qlabel.h>
#include <qstring.h>
#include <qradiobutton.h>
#include <qpushbutton.h>
#include <qcombobox.h>
#include <qbuttongroup.h>
#include <qgroupbox.h>
#include <qcheckbox.h>

#include "configdialog.h"
#include "timerthread.h"
#include "wm_arch.h"

ConfigDialog::ConfigDialog(QWidget *parent, KProcess **helperP,
                           FILE **helperFifoP)
    : KDialogBase(IconList, "Configure KWirelessMonitor",
                  Ok | Cancel | Apply, Ok, parent, 0, false)
{
    mHelperP = helperP;
    mHelperFifoP = helperFifoP;

    KIconLoader *loader = KGlobal::iconLoader();
    KConfig *config = KGlobal::config();
    config->setGroup("KWirelessMonitor Settings");
    
    /* interface page */
    mInterfacePage
        = addVBoxPage((const QString&) "Interface",
                      (const QString&) "Interface Selection",
                      loader->loadIcon("hwinfo", KIcon::NoGroup, 32));
    
    mRBDetect = new QRadioButton("Detect wireless interface automatically",
                                 mInterfacePage);
    
    QHBox *hbox1 = new QHBox(mInterfacePage);
    QLabel *label1_1 = new QLabel(hbox1);
    label1_1->setFixedWidth(20);
    mDetectButton = new QPushButton("&Detect", hbox1);
    QLabel *label1_2 = new QLabel(hbox1);
    label1_2->setText("   Detected interfaces: ");
    mInterfaceCombo = new QComboBox(FALSE, hbox1);
    connect(mDetectButton, SIGNAL(clicked()), this, SLOT(slotDetectClicked()));
    slotDetectClicked();
    
    mRBManual = new QRadioButton("Set wireless interface manually",
                                 mInterfacePage);
    
    QHBox *hbox2 = new QHBox(mInterfacePage);
    QLabel *label2_1 = new QLabel(hbox2);
    label2_1->setFixedWidth(20);
    QLabel *label2_2 = new QLabel(hbox2);
    label2_2->setText("Wireless interface name: ");
    QString ifName = config->readEntry("Interface", "eth0");
    mInterfaceBox = new QLineEdit(ifName, hbox2);
    mInterfaceBox->setMaxLength(20);

    mRBGroup = new QButtonGroup();
    mRBGroup->insert(mRBDetect, DetectMode);
    mRBGroup->insert(mRBManual, ManualMode);
    mCurrentMode = -1;
    mRBDetect->setChecked(TRUE);
    slotRBClicked(DetectMode);
    connect(mRBGroup, SIGNAL(clicked(int)), this, SLOT(slotRBClicked(int)));

    /* spacing */
    QLabel *dummy1 = new QLabel(mInterfacePage);
    mInterfacePage->setStretchFactor(dummy1, 1);

    /* settings page */
    mSettingsPage
        = addVBoxPage((const QString&) "Settings",
                      (const QString&) "Wireless Settings",
                      loader->loadIcon("kcontrol", KIcon::NoGroup, 32));

    QGroupBox *pmGroup = new QGroupBox(1, Qt::Horizontal,
                                       "Power management", mSettingsPage);
    
    QRadioButton *mPMManual = new QRadioButton("Manual setting", pmGroup);

    QHBox *hboxa1_1 = new QHBox(pmGroup);
    QLabel *labela1_1 = new QLabel(hboxa1_1);
    labela1_1->setFixedWidth(20);
    mPMEnableButton = new QPushButton("&Enable", hboxa1_1);
    QLabel *labela1_1a = new QLabel(hboxa1_1);
    labela1_1a->setText("  (Lower power consumption)");
    hboxa1_1->setStretchFactor(mPMEnableButton, 1);
    hboxa1_1->setStretchFactor(labela1_1a, 2);
    /*
    mPMOn = new QRadioButton(
                    "Enable power management (lower power consumption)",
                    hboxa1_1);
    */
    QHBox *hboxa1_2 = new QHBox(pmGroup);
    QLabel *labela1_2 = new QLabel(hboxa1_2);
    labela1_2->setFixedWidth(20);
    mPMDisableButton = new QPushButton("&Disable", hboxa1_2);
    QLabel *labela1_2a = new QLabel(hboxa1_2);
    labela1_2a->setText("  (Higher performance)");
    hboxa1_2->setStretchFactor(mPMDisableButton, 1);
    hboxa1_2->setStretchFactor(labela1_2a, 2);
    /*
    mPMOff = new QRadioButton(
                    "Disable power management (higher performance)",
                   hboxa1_2);
    
    mPMGroup = new QButtonGroup();
    mPMGroup->insert(mPMOn, PMOn);
    mPMGroup->insert(mPMOff, PMOff);
    
    int pmIdx = config->readNumEntry("PM", PMOn);
    pmIdx = ((pmIdx < PMOn) || (pmIdx > PMOff)) ? PMOn : pmIdx;
    ((QRadioButton *) mPMGroup->find(pmIdx))->setChecked(TRUE);
    */
    connect(mPMEnableButton, SIGNAL(clicked()),
            this, SLOT(slotPMEnableClicked()));
    connect(mPMDisableButton, SIGNAL(clicked()),
            this, SLOT(slotPMDisableClicked()));

    QRadioButton *mPMAuto = new QRadioButton("Auto setting", pmGroup);
   
    QHBox *hboxa2_1 = new QHBox(pmGroup);
    QLabel *labela2_1 = new QLabel(hboxa2_1);
    labela2_1->setFixedWidth(20);
    mPMBattery = new QCheckBox(
      "Automatically enable when using battery power",
      hboxa2_1);
    mPMBattery->setChecked(config->readBoolEntry("PMBattery", false));
    
    QHBox *hboxa2_2 = new QHBox(pmGroup);
    QLabel *labela2_2 = new QLabel(hboxa2_2);
    labela2_2->setFixedWidth(20);
    mPMTransfer= new QCheckBox(
      "Automatically disable during data transfer",
      hboxa2_2);
    mPMTransfer->setChecked(config->readBoolEntry("PMTransfer", false));
    
    mPMMGroup = new QButtonGroup();
    mPMMGroup->insert(mPMManual, PMManual);
    mPMMGroup->insert(mPMAuto, PMAuto);
    connect(mPMManual, SIGNAL(clicked()), this, SLOT(slotPMMClicked()));
    connect(mPMAuto, SIGNAL(clicked()), this, SLOT(slotPMAClicked()));

    int pmmIdx = config->readNumEntry("PMM", PMManual);
    if (pmmIdx == PMManual) {
        mPMManual->setChecked(TRUE);
        slotPMMClicked();
    } else {
        mPMAuto->setChecked(TRUE);
        slotPMAClicked();
    }

    QGroupBox *brGroup = new QGroupBox(1, Qt::Horizontal,
                                       "Bitrate selection", mSettingsPage);
    QHBox *hbox3 = new QHBox(brGroup);
    mBRAuto = new QRadioButton(
                "Auto selection (let the interface determine the best bitrate)",
                hbox3);
    QHBox *hbox4 = new QHBox(brGroup);
    mBRManual = new QRadioButton("Manual selection", hbox4);
    mBRCombo = new QComboBox(FALSE, hbox4);
    mBRCombo->insertStringList(availableBitrateStrList, numAvailableBitrates);
    int abrIdx = config->readNumEntry("ABR", numAvailableBitrates - 1);
    abrIdx = ((abrIdx < 0) || (abrIdx > (numAvailableBitrates - 1)))
                ? (numAvailableBitrates - 1) : abrIdx;
    mBRCombo->setCurrentItem(abrIdx);

    /* spacing */
    QLabel *dummy2 = new QLabel(hbox4);
    hbox4->setStretchFactor(dummy2, 1);

    mBRGroup = new QButtonGroup();
    mBRGroup->insert(mBRAuto, BRAuto);
    mBRGroup->insert(mBRManual, BRManual);
    connect(mBRGroup, SIGNAL(clicked(int)), this, SLOT(slotBRClicked()));
    
    int brIdx = config->readNumEntry("BR", BRAuto);
    brIdx = ((brIdx < BRAuto) || (brIdx > BRManual)) ? BRAuto : brIdx;
    ((QRadioButton *) mBRGroup->find(brIdx))->setChecked(TRUE);
    slotBRClicked();
    
    QLabel *brNote = new QLabel(brGroup);
    brNote->setText(
            "Note: some wireless interfaces ignore manual bitrate settings");

    /* spacing */
    QLabel *dummy3 = new QLabel(mSettingsPage);
    mSettingsPage->setStretchFactor(dummy3, 1);
    
    /* network page */
    mNetworkPage
        = addVBoxPage((const QString&) "Network",
                      (const QString&) "Network Settings (Experimental)",
                      loader->loadIcon("kcontrol", KIcon::NoGroup, 32));
    
    QHBox *nhbox = new QHBox(mNetworkPage);
    QLabel *labeln = new QLabel(nhbox);
    labeln->setText("Wireless network name: ");
    QString netName = config->readEntry("Network", "");
    mESSIDBox = new QLineEdit(netName, nhbox);
    mESSIDBox->setMaxLength(20);
    mESSIDBox->setText(((KWirelessMonitor *) parentWidget())->getESSID());

    /* spacing */
    QLabel *dummy4 = new QLabel(mNetworkPage);
    mNetworkPage->setStretchFactor(dummy4, 1);

    /* finally */
    disableResize();
   
    disableSettings();
    connect(this, SIGNAL(aboutToShowPage(QWidget *)),
            SLOT(slotShowingPage(QWidget *)));

    mKWinModule = new KWinModule();
    connect(mKWinModule, SIGNAL(windowAdded(WId)),
            this, SLOT(slotWMWindowAdded(WId)));
}

void ConfigDialog::disableSettings()
{
    mSettingsPage->setDisabled(true);
    mNetworkPage->setDisabled(true);
    if ((activePageIndex() == pageIndex(mSettingsPage)) ||
        (activePageIndex() == pageIndex(mNetworkPage))) {
        enableButtonOK(false);
        enableButtonApply(false);
    }
}

void ConfigDialog::enableSettings()
{
    mSettingsPage->setEnabled(true);
    mNetworkPage->setEnabled(true);
    if (!wm_capACPower()) {
        mPMBattery->setEnabled(false);
    }
    enableButtonOK(true);
    enableButtonApply(true);
    ((KWirelessMonitor *) parentWidget())->disableMenuSettings();
    applyClicked();
}

void ConfigDialog::menuEnableSettings()
{
    slotShowingPage(mSettingsPage);
}

void ConfigDialog::slotDetectClicked()
{
    KConfig *config = KGlobal::config();
    config->setGroup("KWirelessMonitor Settings");

    QStringList ifList;
    mInterfaceCombo->clear();
    int rv = wm_getWirelessInterfaces(ifList);
    if (rv == 0) {
        mInterfaceCombo->insertStringList(ifList);
    }
    int i = 0;
    for (QStringList::Iterator it = ifList.begin(); it != ifList.end();
         it += 1, i += 1) {
        QString str = (*it);
        if (str.compare(config->readEntry("Interface", "eth0")) == 0) {
            mInterfaceCombo->setCurrentItem(i);
            break;
        }
    }
}

void ConfigDialog::slotPMEnableClicked()
{
    ((KWirelessMonitor *) parentWidget())->setPMModeHelper(PMOn);
}

void ConfigDialog::slotPMDisableClicked()
{
    ((KWirelessMonitor *) parentWidget())->setPMModeHelper(PMOff);
}

void ConfigDialog::slotRBClicked(int id)
{
    if (mRBDetect->isChecked() && (mCurrentMode != id)) {
        mDetectButton->setEnabled(TRUE);
        mInterfaceCombo->setEnabled(TRUE);
        mInterfaceBox->setEnabled(FALSE);
        mCurrentMode = id;
    } else if (mRBManual->isChecked() && (mCurrentMode != id)) {
        mDetectButton->setEnabled(FALSE);
        mInterfaceCombo->setEnabled(FALSE);
        mInterfaceBox->setEnabled(TRUE);
        mCurrentMode = id;
    }
}

void ConfigDialog::slotBRClicked()
{
    if (mBRAuto->isChecked()) {
        mBRCombo->setEnabled(FALSE);
    } else {
        mBRCombo->setEnabled(TRUE);
    }
}

void ConfigDialog::slotPMMClicked()
{
    mPMEnableButton->setEnabled(TRUE);
    mPMDisableButton->setEnabled(TRUE);
    /*
    mPMOn->setEnabled(TRUE);
    mPMOff->setEnabled(TRUE);
    */
    mPMBattery->setEnabled(FALSE);
    mPMTransfer->setEnabled(FALSE);
}

void ConfigDialog::slotPMAClicked()
{
    mPMEnableButton->setEnabled(FALSE);
    mPMDisableButton->setEnabled(FALSE);
    /*
    mPMOn->setEnabled(FALSE);
    mPMOff->setEnabled(FALSE);
    */
    mPMBattery->setEnabled(TRUE);
    mPMTransfer->setEnabled(TRUE);
}

ConfigDialog::HelperSyncThread::HelperSyncThread(ConfigDialog *cd) : QThread()
{
    mConfigDialog = cd;
}

void ConfigDialog::HelperSyncThread::run()
{
    char buf[32];
    fgets(buf, 16, *(mConfigDialog->mHelperFifoP));
    if (*(mConfigDialog->mHelperP) != 0) {
        mConfigDialog->enableSettings();
    }
}

void ConfigDialog::slotHelperExited(KProcess *)
{
    disableSettings();
    mHelperSyncThread->terminate();
    delete (*mHelperP);
    (*mHelperP) = 0;
}

void ConfigDialog::slotShowingPage(QWidget *page)
{
    if ((page != mSettingsPage) && (page != mNetworkPage)) {
        enableButtonOK(true);
        enableButtonApply(true);
        return;
    }
    
    if (!settingsEnabled()) {
        enableButtonOK(false);
        enableButtonApply(false);
    }

    if ((*mHelperP) != 0) {
        return;
    }
    disableSettings();

    if (!wm_capSettings()) {
        return;
    }

    unlink(HELPER_FIFO);
    if (mkfifo(HELPER_FIFO, S_IRUSR | S_IWUSR) == 0) {
        (*mHelperP) = new KProcess();
        *(*mHelperP) << "kdesu";
        *(*mHelperP) << "kwirelessmonitor-helper";
        connect(*mHelperP, SIGNAL(processExited(KProcess *)),
                this, SLOT(slotHelperExited(KProcess *)));
        (*mHelperP)->start();

        (*mHelperFifoP) = fopen(HELPER_FIFO, "r+");
        if ((*mHelperFifoP) != NULL) {
            mHelperSyncThread = new HelperSyncThread(this);
            mHelperSyncThread->start();
        }
    }
}

void ConfigDialog::slotWMWindowAdded(WId id)
{
    // XXX KWin::info is deprecated in 3.2, use KWin::WindowInfo
    if (KWin::info(id).name.startsWith("Run as root - KDE su")) {
        KWin::setState(id, NET::StaysOnTop);
    }
    // Config window: "Configure KWirelessMonitor"
}

QString ConfigDialog::getInterfaceName()
{
    QString ret("");
    if (mRBDetect->isChecked()) {
        ret += mInterfaceCombo->currentText();
    } else {
        ret += mInterfaceBox->text();
    }
    return ret;
}

#if 0
int ConfigDialog::getPMMode()
{
    /* QButtonGroup::selectedId() not available before 3.2! */
    int pmIdx = mPMGroup->id(mPMGroup->selected());
    return (pmIdx == -1) ? PMOn : pmIdx;
}
#endif

int ConfigDialog::getPMM()
{
    int pmm = mPMMGroup->id(mPMMGroup->selected());
    return (pmm == -1) ? PMManual : pmm;
}

int ConfigDialog::getBRMode()
{
    int brIdx = mBRGroup->id(mBRGroup->selected());
    return (brIdx == -1) ? BRAuto : brIdx;
}

int ConfigDialog::getBRManualIdx()
{
    return mBRCombo->currentItem();
}

