/*****************************************************************************
 * Copyright (C) 2004-2009 Christoph Thielecke <crissi99@gmx.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.                                       *
 *                                                                           *
 * This package is distributed in the hope that it will be useful,           *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 * GNU General Public License for more details.                              *
 *                                                                           *
 * You should have received a copy of the GNU General Public License         *
 * along with this package; if not, write to the Free Software               *
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA *
 *****************************************************************************/

#include "newprofiledialog.h"

#include <QtCore/QObject>
#include <QtGui/QCheckBox>
#include <QtGui/QLabel>

#include <kcombobox.h>
#include <klineedit.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <knuminput.h>
#include <ktextedit.h>
#include <kurlrequester.h>

#include "importcertificatedialog.h"
#include "importprofiledialog.h"
#include "networkinterface.h"
#include "utils.h"
#include "vpnaccountdata.h"

NewProfileDialog::NewProfileDialog(QApplication *app, QWidget *parent, const QString& caption, KVpncConfig *GlobalConfig)
        : KDialog(parent)
{
    Q_UNUSED(caption);

    setupUi(this);
    this->GlobalConfig = GlobalConfig;

    connect(ConnectionTypeComboBox, SIGNAL(activated(const QString&)), this, SLOT(connectiontypeChanged(const QString&)));
    connect(AuthTypeComboBox , SIGNAL(activated(const QString&)), this, SLOT(authTypeChanged(const QString&)));
    // connect( buttonCancel , SIGNAL( clicked () ), this, SLOT( reject() ) );
    connect(ImportCertificatePushButton, SIGNAL(clicked()), this, SLOT(importCertificate()));
    connect(AdvancedSettingsPushButton, SIGNAL(clicked()), this, SLOT(advancedSettingsClicked()));
    connect(ImportPcfProfilePushButton , SIGNAL(clicked()), this, SLOT(importPcfFileClicked()));
    connect(GroupPasswordEdit, SIGNAL(textChanged(const QString&)), this, SLOT(groupPasswordContentChanged()));
    connect(PasswordEdit, SIGNAL(textChanged(const QString&)), this, SLOT(passwordContentChanged()));
    newProfileCreated = false;
    Name = "";

    // currently static for new profile
    VpnAccountData::ConnectionType ConnType = VpnAccountData::ConnectionType(VpnAccountData::other);
    Port = 500;
    Gateway = "";
    ID = "";
    Username = "";
    UserPassword = "";
    PreSharedKey = "";
    ApplicationVersion = "";
    NtDomainName = "";
    PerfectForwardSecrecy = "";
    IkeGroup = "";
    Description = "";
    useApplicationVersion = false;
    useGlobalIpsecSecret = false;
    useIkeGroup = false;
    useLocalPort = false;
    useNtDomainName = false;
    useSingleDes = false;
    useAdvancedSettings = false;
    usePerfectSecrecy = false;
    saveUserPassword = false;
    savePsk = false;
    useUdp = false;
    useUdpPort = false;
    useDnsServer = false;
    DnsServer = "";
    useGetDnsFromPeer = true;
    refuse40BitEncryption = true;
    refuse128BitEncryption = false;
    allowStatefulMode = false;
    requireMppe = true;
    refuseEap = false;
    useNoBsdComp = true;
    useNoDeflate = true;
    savePsk = false;

    profileData = new VpnAccountData(ConnType, Name);
    profileData->setGateway(Gateway);
    profileData->setID(ID);
    profileData->setPreSharedKey(PreSharedKey);
    profileData->setSavePsk(savePsk);
    profileData->setUserName(Username);
    profileData->setUserPassword(UserPassword);
    profileData->setSaveUserPassword(saveUserPassword);
    profileData->setSavePsk(savePsk);
    profileData->setApplicationVersion(ApplicationVersion);
    profileData->setUseLocalPort(useLocalPort);
    profileData->setLocalPort(Port);
    profileData->setUseSingleDes(useSingleDes);
    profileData->setPerfectForwardSecrety(PerfectForwardSecrecy);
    profileData->setIkeGroup(IkeGroup);
    profileData->setUseGlobalIpsecSecret(useGlobalIpsecSecret);
    profileData->setUseIkeGroup(useIkeGroup);
    profileData->setNtDomainName(NtDomainName);
    profileData->setUseAdvancedSettings(useAdvancedSettings);
    profileData->setUsePerfectForwardSecrety(usePerfectSecrecy);

    NetworkInterface iface(GlobalConfig, app);
    QStringList list = iface.getAllNetworkInterfaces();
    int NetworkDeviceIdx = 0;
    NetworkDeviceComboBox->insertItem(NetworkDeviceIdx, "default");
    for (QStringList::Iterator it = list.begin(); it != list.end(); ++it) {
        NetworkDeviceComboBox->insertItem(NetworkDeviceIdx, QString(*it));
        NetworkDeviceIdx++;
    }
    NetworkDeviceComboBox->setEnabled(true);
    NetworkDeviceComboBox->setCurrentItem("default");

    certpathURLRequester->setUrl(QString("/etc/racoon/certs"));
    certpathURLRequester->setMode(KFile::Directory);   // directory

    ConnectionTypeComboBox->insertItem(0, i18n("Cisco (vpnc)"));
    ConnectionTypeComboBox->insertItem(1, i18n("IPSec (racoon)"));
    ConnectionTypeComboBox->insertItem(2, i18n("IPSec (FreeS/WAN)"));
    ConnectionTypeComboBox->insertItem(3, i18n("PPTP"));
    ConnectionTypeComboBox->insertItem(4, i18n("OpenVPN"));
    AuthTypeComboBox->setCurrentIndex(0);  // cisco

    RemoteNetMaskComboBox->setCurrentIndex(16); //24

    authTypeChanged("");
    connectiontypeChanged("");
}

NewProfileDialog::~NewProfileDialog()
{
}

void NewProfileDialog::accept()
{
    int connectionTypeIndex = ConnectionTypeComboBox->currentIndex();
    switch (connectionTypeIndex) {
    case VpnAccountData::cisco:
        profileData->setConnectionType(VpnAccountData::cisco);
        UdpPort = 10000;
        break;
    case VpnAccountData::racoon:
        profileData->setConnectionType(VpnAccountData::racoon);

        if (AuthTypeComboBox->currentIndex() == VpnAccountData::cert) {
            profileData->setAuthType(VpnAccountData::cert);
        } else {
            profileData->setAuthType(VpnAccountData::psk);
        }

        profileData->setX509Certificate(x509certURLRequester->url().toLocalFile());
        profileData->setCertPath(certpathURLRequester->url().toLocalFile());

        UdpPort = 4500;
        break;
    case VpnAccountData::freeswan:
        profileData->setConnectionType(VpnAccountData::freeswan);
        UdpPort = 4500;
        break;
    case VpnAccountData::pptp:
        profileData->setConnectionType(VpnAccountData::pptp);
        break;
    case VpnAccountData::openvpn:
        profileData->setConnectionType(VpnAccountData::openvpn);
        break;
    default:
        profileData->setConnectionType(VpnAccountData::other);
        break;
    }

    bool canSave = true;
    bool validAddr = true;

    if (profileData->getConnectionType() != VpnAccountData::cisco &&
            profileData->getConnectionType() != VpnAccountData::openvpn) {
        if (RemoteNetAddrLineEdit->text().contains('.') != 3) {
            KMessageBox::error(this,
                               i18n("No IP address for remote network entered."),
                               i18n("No IP Address"));
            GlobalConfig->appendLogEntry(i18n("No IP address for remote network entered."),
                                         KVpncEnum::error);
            validAddr = false;
            canSave = false;
        } else {
            if (!Utils(GlobalConfig).isValidIPv4Address(RemoteNetAddrLineEdit->text())) {
                KMessageBox::error(this,
                                   i18n("IP address of remote network is not valid."),
                                   i18n("Invalid IP Address"));
                GlobalConfig->appendLogEntry(i18n("IP address of remote network is not valid."),
                                             KVpncEnum::error);
                validAddr = false;
                canSave = false;
            }

            if (validAddr) {
                profileData->setRemoteNetAddr(RemoteNetAddrLineEdit->text());
                profileData->setRemoteNetMask(RemoteNetMaskComboBox->currentText());
            }
        }
    }

    // profileData->setSavePsk( CheckGroupPass->isChecked() );
    // profileData->setSaveUserPassword( CheckUserPass->isChecked () );
    profileData->setSavePsk(!PSKLineEdit->text().isEmpty());
    profileData->setSaveUserPassword(!PasswordEdit->text().isEmpty());
    profileData->setID(IDLineEdit->text());

    profileData->setDescription(DescriptionLineEdit->text());

    profileData->setUserName(UsernameLineEdit->text());

    if (CheckUserPass->isChecked()) {
        profileData->setUserPassword(PasswordEdit->text());
        profileData->setSaveUserPassword(true);
    }

    profileData->setGateway(gatewayLineEdit->text());

    if (CheckGroupPass->isChecked()) {
        if (!profileData->getConnectionType() == VpnAccountData::cisco) {
            profileData->setPreSharedKey(PSKLineEdit->text());
        } else {
            profileData->setPreSharedKey(GroupPasswordEdit->text());
        }
        profileData->setSavePsk(true);
    }

    profileData->setX509Certificate(x509certURLRequester->url().toLocalFile());
    profileData->setCertPath(certpathURLRequester->url().toLocalFile());
    profileData->setNetworkDevice(NetworkDeviceComboBox->currentText());
    if (AuthTypeComboBox->currentIndex() == VpnAccountData::cert) {
        profileData->setAuthType(VpnAccountData::cert);
    } else {
        profileData->setAuthType(VpnAccountData::psk);
    }

    if (canSave) {
        bool nameOk = true;
        Name = ProfileLineEdit->text();

        if (Name.contains(' ')) {
            KMessageBox::error(this,
                               i18n("Profile name cannot contain spaces."),
                               i18n("Spaces Not Allowed"));
            GlobalConfig->appendLogEntry(i18n("Profile name cannot contain spaces."),
                                         KVpncEnum::error);
            nameOk = false;
        }

        if (Name.isEmpty()) {
            KMessageBox::error(this,
                               i18n("Profile name cannot be empty."),
                               i18n("No Name Entered"));
            GlobalConfig->appendLogEntry(i18n("Profile name cannot be empty."),
                                         KVpncEnum::error);

            nameOk = false;
        }
        for (int accountIdx = 0; accountIdx < GlobalConfig->AccountList->size(); ++accountIdx) {
            if (GlobalConfig->AccountList->at(accountIdx)->getName() == Name) {
                KMessageBox::error(this,
                                   i18n("Profile name already exists."),
                                   i18n("Name Already Exists"));
                GlobalConfig->appendLogEntry(i18n("Profile name already exists."),
                                             KVpncEnum::error);
                nameOk = false;
                break;
            }
        }

        if (nameOk) {
            profileData->setName(Name);
            GlobalConfig->AccountList->append(profileData);
            newProfileCreated = true;
            KDialog::accept();
        }
    }
}

void NewProfileDialog::importCertificate()
{
    // FIXME make dynamically
    ImportCertificateDialog importdlg(this,
                                      i18n("Import certificate...").toAscii(),
                                      GlobalConfig);
    // dlg.resize(dlg.height(),600);
    // int result =
    importdlg.exec();
}

void NewProfileDialog::connectiontypeChanged(const QString & text)
{
    Q_UNUSED(text);
    // First we should set a type
    // buttonOk->setEnabled(false);
    AdvancedSettingsPushButton->setEnabled(false);

    int connectionTypeIndex = ConnectionTypeComboBox->currentIndex();
    switch (connectionTypeIndex) {
    case VpnAccountData::cisco:
        if (GlobalConfig->KvpncDebugLevel > 0) {
            GlobalConfig->appendLogEntry(i18n("New type: cisco"), KVpncEnum::debug);
        }

        profileData->setConnectionType(VpnAccountData::cisco);

        CheckGroupPass->setEnabled(true);
        CheckUserPass->setEnabled(true);

        IDLineEdit->setEnabled(true);
        LabelID->setEnabled(true);

        UsernameLineEdit->setEnabled(true);
        LabelUsername->setEnabled(true);

        PasswordEdit->setEnabled(true);
        LabelPassword->setEnabled(true);

        AdvancedSettingsPushButton->setEnabled(true);

        x509certURLRequester->setEnabled(false);
        LabelCertificate->setEnabled(false);

        certpathURLRequester->setEnabled(false);
        LabelCertificatePath->setEnabled(false);

        NetworkDeviceComboBox->setEnabled(false);
        LabelNetworkDevice->setEnabled(false);
        AuthTypeComboBox->setEnabled(false);
        LabelAuthType->setEnabled(false);

        PSKLineEdit->setEnabled(false);
        LabelPsk->setEnabled(false);

        // buttonCancel->setEnabled(true);
        // buttonOk->setEnabled(true);

        RemoteNetAddrLineEdit->setEnabled(false);
        LabelRemoteNetwork->setEnabled(false);

        RemoteNetMaskComboBox->setEnabled(false);

        break;
    case VpnAccountData::racoon:
        if (GlobalConfig->KvpncDebugLevel > 0) {
            GlobalConfig->appendLogEntry(i18n("New type: racoon"), KVpncEnum::debug);
        }
        // KUrlRequester* x509certURLRequester;
        // KComboBox* AuthTypeComboBox;
        // KPushButton* ImportCertificatePushButton;
        // KLineEdit* PSKLineEdit;

        profileData->setConnectionType(VpnAccountData::racoon);

        x509certURLRequester->setEnabled(true);
        LabelCertificate->setEnabled(true);

        certpathURLRequester->setEnabled(true);
        LabelCertificatePath->setEnabled(true);

        NetworkDeviceComboBox->setEnabled(true);
        LabelNetworkDevice->setEnabled(true);

        AuthTypeComboBox->setEnabled(true);
        LabelAuthType->setEnabled(true);

        PSKLineEdit->setEnabled(true);
        LabelPsk->setEnabled(true);

        RemoteNetAddrLineEdit->setEnabled(true);
        LabelRemoteNetwork->setEnabled(true);

        RemoteNetMaskComboBox->setEnabled(true);

        PasswordEdit->setEnabled(false);
        LabelPassword->setEnabled(false);

        CheckGroupPass->setEnabled(false);
        CheckUserPass->setEnabled(false);

        IDLineEdit->setEnabled(false);
        LabelID->setEnabled(false);

        UsernameLineEdit->setEnabled(false);
        LabelUsername->setEnabled(false);

        GroupPasswordEdit->setEnabled(false);
        LabelGroupPassword->setEnabled(false);

        // buttonCancel->setEnabled(true);
        // buttonOk->setEnabled(true);
        AdvancedSettingsPushButton->setEnabled(true);

        break;
    case VpnAccountData::freeswan:
        if (GlobalConfig->KvpncDebugLevel > 0) {
            GlobalConfig->appendLogEntry(i18n("New type: freeswan"), KVpncEnum::debug);
        }
        // KUrlRequester* x509certURLRequester;
        // KComboBox* AuthTypeComboBox;
        // KPushButton* ImportCertificatePushButton;
        // KLineEdit* PSKLineEdit;

        profileData->setConnectionType(VpnAccountData::freeswan);

        x509certURLRequester->setEnabled(true);
        LabelCertificate->setEnabled(true);

        certpathURLRequester->setEnabled(true);
        LabelCertificatePath->setEnabled(true);

        NetworkDeviceComboBox->setEnabled(true);
        LabelNetworkDevice->setEnabled(true);

        AuthTypeComboBox->setEnabled(true);
        LabelAuthType->setEnabled(true);

        PSKLineEdit->setEnabled(true);
        LabelPsk->setEnabled(true);

        RemoteNetAddrLineEdit->setEnabled(true);
        LabelRemoteNetwork->setEnabled(true);

        RemoteNetMaskComboBox->setEnabled(true);

        CheckGroupPass->setEnabled(false);
        CheckUserPass->setEnabled(false);

        IDLineEdit->setEnabled(false);
        LabelID->setEnabled(false);

        PasswordEdit->setEnabled(false);
        LabelPassword->setEnabled(false);

        UsernameLineEdit->setEnabled(false);
        LabelUsername->setEnabled(false);

        GroupPasswordEdit->setEnabled(false);
        LabelGroupPassword->setEnabled(false);

        // buttonCancel->setEnabled(true);
        // buttonOk->setEnabled(true);
        AdvancedSettingsPushButton->setEnabled(true);

        break;
    case VpnAccountData::pptp:
        if (GlobalConfig->KvpncDebugLevel > 0) {
            GlobalConfig->appendLogEntry(i18n("New type: pptp"), KVpncEnum::debug);
        }
        // KUrlRequester* x509certURLRequester;
        // KComboBox* AuthTypeComboBox;
        // KPushButton* ImportCertificatePushButton;
        // KLineEdit* PSKLineEdit;

        profileData->setConnectionType(VpnAccountData::pptp);

        x509certURLRequester->setEnabled(false);
        LabelCertificate->setEnabled(false);

        certpathURLRequester->setEnabled(false);
        LabelCertificatePath->setEnabled(false);

        NetworkDeviceComboBox->setEnabled(false);
        LabelNetworkDevice->setEnabled(false);

        AuthTypeComboBox->setEnabled(false);
        LabelAuthType->setEnabled(false);

        PSKLineEdit->setEnabled(false);
        LabelPsk->setEnabled(false);

        RemoteNetAddrLineEdit->setEnabled(true);
        LabelRemoteNetwork->setEnabled(true);

        RemoteNetMaskComboBox->setEnabled(true);

        CheckGroupPass->setEnabled(false);
        CheckUserPass->setEnabled(true);

        IDLineEdit->setEnabled(false);
        LabelID->setEnabled(false);

        PasswordEdit->setEnabled(true);
        LabelPassword->setEnabled(true);

        UsernameLineEdit->setEnabled(true);
        LabelUsername->setEnabled(true);

        GroupPasswordEdit->setEnabled(false);
        LabelGroupPassword->setEnabled(false);

        // buttonCancel->setEnabled(true);
        // buttonOk->setEnabled(true);
        AdvancedSettingsPushButton->setEnabled(true);

        break;
    case VpnAccountData::openvpn:
        if (GlobalConfig->KvpncDebugLevel > 0) {
            GlobalConfig->appendLogEntry(i18n("New type: openvpn"), KVpncEnum::debug);
        }
        // KUrlRequester* x509certURLRequester;
        // KComboBox* AuthTypeComboBox;
        // KPushButton* ImportCertificatePushButton;
        // KLineEdit* PSKLineEdit;

        profileData->setConnectionType(VpnAccountData::openvpn);

        x509certURLRequester->setEnabled(true);
        LabelCertificate->setEnabled(true);

        certpathURLRequester->setEnabled(true);
        LabelCertificatePath->setEnabled(true);

        NetworkDeviceComboBox->setEnabled(true);
        LabelNetworkDevice->setEnabled(true);

        AuthTypeComboBox->setEnabled(true);
        LabelAuthType->setEnabled(true);

        PSKLineEdit->setEnabled(true);
        LabelPsk->setEnabled(true);

        RemoteNetAddrLineEdit->setEnabled(false);
        LabelRemoteNetwork->setEnabled(false);

        RemoteNetMaskComboBox->setEnabled(true);

        PasswordEdit->setEnabled(false);
        LabelPassword->setEnabled(false);

        CheckGroupPass->setEnabled(false);
        CheckUserPass->setEnabled(false);

        IDLineEdit->setEnabled(false);
        LabelID->setEnabled(false);


        UsernameLineEdit->setEnabled(false);
        LabelUsername->setEnabled(false);

        GroupPasswordEdit->setEnabled(false);
        LabelGroupPassword->setEnabled(false);

        // buttonCancel->setEnabled(true);
        // buttonOk->setEnabled(true);
        AdvancedSettingsPushButton->setEnabled(true);

        break;
    default:
        if (GlobalConfig->KvpncDebugLevel > 0) {
            GlobalConfig->appendLogEntry(i18n("New type: other"), KVpncEnum::debug);
        }
        // x509certURLRequester->setEnabled(false);
        // AuthTypeComboBox->setEnabled(false);
        // PSKLineEdit->setEnabled(false);
        //
        // CheckGroupPass->setEnabled(false);
        // CheckUserPass->setEnabled(false);
        // IDLineEdit->setEnabled(false);
        // UsernameLineEdit->setEnabled(false);
        // AdvancedSettingsPushButton->setEnabled(false);
        // buttonCancel->setEnabled(false);
        // buttonOk->setEnabled(false);

        break;
    }
}

void NewProfileDialog::authTypeChanged(const QString & text)
{
    Q_UNUSED(text);

    int authTypeIndex = AuthTypeComboBox->currentIndex();
    if (authTypeIndex == VpnAccountData::cert) {
        PSKLineEdit->setEnabled(false);
        LabelPsk->setEnabled(false);

        x509certURLRequester->setEnabled(true);
        LabelCertificate->setEnabled(true);

        certpathURLRequester->setEnabled(true);
        LabelCertificatePath->setEnabled(true);
    }

    if (authTypeIndex == VpnAccountData::psk) {
        PSKLineEdit->setEnabled(true);
        LabelPsk->setEnabled(true);

        x509certURLRequester->setEnabled(false);
        LabelCertificate->setEnabled(false);

        certpathURLRequester->setEnabled(false);
        LabelCertificatePath->setEnabled(false);
    }
}

void NewProfileDialog::reject()
{
    KDialog::reject();
}

void NewProfileDialog::profileNameChanged(const QString&)
{
#if 0
    LogOutput->append("text changed!");

    if (ProfileLineEdit->text().isEmpty()) {
        buttonOk->setEnabled(false);
    } else {
        buttonOk->setEnabled(true);
    }
#endif
}

QString NewProfileDialog::getName()
{
    return Name;
}

void NewProfileDialog::importPcfFileClicked()
{
    ImportProfileDialog dlg(GlobalConfig,
                            this,
                            i18n("Import Cisco PCF Profile..."),
                            "");
    dlg.exec();
    dlg.resize(800, dlg.height());
}

void NewProfileDialog::groupPasswordContentChanged()
{
    if (!GroupPasswordEdit->text().isEmpty()) {
        CheckGroupPass->setChecked(true);
    } else {
        CheckGroupPass->setChecked(false);
    }
}

void NewProfileDialog::passwordContentChanged()
{
    if (!PasswordEdit->text().isEmpty()) {
        CheckUserPass ->setChecked(true);
    } else {
        CheckUserPass->setChecked(false);
    }
}

#include "newprofiledialog.moc"
