/***************************************************************************
*   Copyright (C) 2009 Matthias Fuchs <mat69@gmx.net>                     *
*                                                                         *
*   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 program 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 program; if not, write to the                         *
*   Free Software Foundation, Inc.,                                       *
*   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA .        *
***************************************************************************/

#include "signaturedlg.h"

#include "core/filemodel.h"
#include "core/transferhandler.h"
#include "core/verifier.h"

#ifdef HAVE_QGPGME
#include <gpgme++/context.h>
#include <gpgme++/key.h>
#endif

#include <KLocale>

const QStringList SignatureDlg::OWNERTRUST = QStringList() << i18nc("trust level", "Unknown") << i18nc("trust level", "Undefined") << i18nc("trust level", "Never") << i18nc("trust level", "Marginal") << i18nc("trust level", "Full") << i18nc("trust level", "Ultimate");

SignatureDlg::SignatureDlg(TransferHandler *transfer, const KUrl &dest, QWidget *parent, Qt::WFlags flags)
  : KDialog(parent, flags),
    m_signature(transfer->signature(dest)),
    m_fileModel(transfer->fileModel())
{
    setCaption(i18nc("Signature here is meant in cryptographic terms, so the signature of a file.", "Signature of %1.", dest.fileName()));
    showButtonSeparator(true);
    QWidget *widget = new QWidget(this);
    ui.setupUi(widget);
    setMainWidget(widget);

    if (m_signature) {
        connect(ui.verify, SIGNAL(clicked()), this, SLOT(verifyClicked()));
        connect(ui.signature, SIGNAL(textChanged()), this, SLOT(updateSignature()));
        connect(m_signature, SIGNAL(verified(int)), this, SLOT(updateData()));

        if (m_fileModel) {
            m_file = m_fileModel->index(dest, FileItem::File);
            connect(m_fileModel, SIGNAL(fileFinished(KUrl)), this, SLOT(fileFinished(KUrl)));
        }

        updateData();
        updateButtons();
    } else {
        ui.information->setText(i18n("This option is not supported for the current transfer."));
        ui.sigGroup->hide();
        ui.keyGroup->hide();
    }
}

void SignatureDlg::fileFinished(const KUrl &file)
{
    if (m_fileModel && (m_fileModel->getUrl(m_file) == file)) {
        updateButtons();
    }
}

void SignatureDlg::updateSignature()
{
    if (m_signature) {
        m_signature->setSignature(ui.signature->toPlainText());

        clearData();
        updateButtons();
    }
}

void SignatureDlg::updateButtons()
{
    bool enableVerify = m_signature && m_signature->isVerifyable();
    if (!m_fileModel || !m_fileModel->downloadFinished(m_fileModel->getUrl(m_file))) {
        enableVerify = false;
    }
    ui.verify->setEnabled(enableVerify);
}

void SignatureDlg::updateData()
{
    if (!m_signature) {
        return;
    }

    const QString fingerprintString = m_signature->fingerprint();
    const QString signature = m_signature->signature();

    QStringList information;

    bool problem = false;
    bool error = false;
    if (signature.isEmpty()) {
        information << i18n("You need to define a signature.");
        problem = true;
    }
    if (fingerprintString.isEmpty()) {
        information << i18n("No fingerprint could be found, check if the signature is correct or verify the download.");//TODO get fingerprint from signature!
        problem = true;
    }

    ui.fingerprint->setText(fingerprintString);

    ui.signature->blockSignals(true);
    ui.signature->setText(signature);
    ui.signature->blockSignals(false);

    ui.keyGroup->setVisible(!signature.isEmpty());

    const int iconSize = KIconLoader::global()->currentSize(KIconLoader::Small);

#ifdef HAVE_QGPGME
    if (!fingerprintString.isEmpty()) {
        GpgME::initializeLibrary();
        GpgME::Error err = GpgME::checkEngine(GpgME::OpenPGP);
        QScopedPointer<GpgME::Context> context(GpgME::Context::createForProtocol(GpgME::OpenPGP));
        if (err) {
            kDebug(5001) << "OpenPGP not supported!";
        } else if (!context.data()) {
                kDebug(5001) << "Could not create context.";
        } else {
            QByteArray fingerprint = fingerprintString.toAscii();
            const GpgME::Key key = context->key(fingerprint.constData(), err);
            if (err || key.isNull() || !key.numUserIDs() || !key.numSubkeys()) {
                kDebug(5001) << "There was an error while loading the key:" << err;
            } else {
                if (key.isRevoked()) {
                    information << i18n("The key has been revoked.");
                    problem = true;
                }
                if (key.isDisabled()) {
                    information << i18n("The key is disabled.");
                    problem = true;
                }
                if (key.isInvalid()) {
                    information << i18n("The key is invalid.");
                    error = true;
                }
                ui.expirationIcon->clear();
                if (key.isExpired()) {
                    information << i18n("The key is expired.");
                    ui.expirationIcon->setPixmap(KIcon("dialog-warning").pixmap(iconSize));
                    ui.expirationIcon->show();
                    problem = true;
                } else {
                    ui.expirationIcon->hide();
                }


                //handle the trust of the key
                const GpgME::Key::OwnerTrust ownerTrust = key.ownerTrust();
                ui.trust->setText(OWNERTRUST.value(ownerTrust));

                switch (ownerTrust) {
                    case GpgME::Key::Never:
                        information.prepend(i18n("The key is not to be trusted."));
                        ui.trustIcon->setPixmap(KIcon("dialog-error").pixmap(iconSize));
                        ui.trustIcon->show();
                        error = true;
                        break;
                    case GpgME::Key::Marginal:
                        information.prepend(i18n("The key is to be trusted marginally."));
                        ui.trustIcon->setPixmap(KIcon("dialog-warning").pixmap(iconSize));
                        ui.trustIcon->show();
                        problem = true;
                        break;
                    case GpgME::Key::Full:
                        information.prepend(i18n("The key is to be trusted fully."));
                        ui.trustIcon->hide();
                        break;
                    case GpgME::Key::Ultimate:
                        information.prepend(i18n("The key is to be trusted ultimately."));
                        ui.trustIcon->hide();
                        break;
                    case GpgME::Key::Unknown:
                    case GpgME::Key::Undefined:
                    default:
                        information.prepend(i18n("Trust level of the key is unclear."));
                        ui.trustIcon->setPixmap(KIcon("dialog-warning").pixmap(iconSize));
                        ui.trustIcon->show();
                        problem = true;
                        break;
                }

                //issuer, issuer mail and comment
                if (key.numUserIDs()) {
                    const GpgME::UserID userID = key.userID(0);
                    ui.issuer->setText(userID.name());
                    ui.comment->setText(userID.comment());
                    ui.email->setText(userID.email());
                }

                //key creation/expiration-time
                if (key.numSubkeys()) {
                    const GpgME::Subkey subKey = key.subkey(0);

                    time_t creation = subKey.creationTime();
                    QDateTime creationTime;
                    creationTime.setTime_t(creation);
                    ui.creation->setText(creationTime.toString());

                    time_t expiration = subKey.expirationTime();
                    if (expiration) {
                        QDateTime expirationTime;
                        expirationTime.setTime_t(expiration);
                        ui.expiration->setText(expirationTime.toString());
                    } else {
                        ui.expiration->setText(i18n("Unlimited"));
                    }
                }
            }
        }
    }
#endif //HAVE_QGPGME

    const Signature::VerificationStatus verificationStatus = m_signature->status();

    //display the verification status
    ui.verificationIcon->hide();
    switch (verificationStatus) {
        case Signature::Verified:
            ui.verified->setText(i18nc("pgp signature is verified", "Verified"));
            ui.verificationIcon->setPixmap(KIcon("dialog-ok").pixmap(iconSize));
            ui.verificationIcon->show();
            information.prepend(i18n("The signature has been verified successfully."));
            break;
        case Signature::VerifiedInformation:
            ui.verificationIcon->setPixmap(KIcon("dialog-ok").pixmap(iconSize));
            ui.verificationIcon->show();
            ui.verified->setText(i18nc("pgp signature is verified", "Verified"));
            information.prepend(i18n("The signature has been verified successfully:"));
            break;
        case Signature::NotVerified:
            ui.verified->setText(i18nc("pgp signature is not verified", "Failed"));
            ui.verificationIcon->setPixmap(KIcon("dialog-error").pixmap(iconSize));
            ui.verificationIcon->show();
            information.prepend(i18n("Caution: Verification failed. Either you entered the wrong signature, or the data has been modified."));
            error = true;
            break;
        case Signature::NotWorked://TODO downloading state? --> currently downloading
            ui.verified->clear();//TODO
            information.prepend(i18n("Verification not possible. Check the entered data, whether gpg-agent is running, or whether you have an Internet connection (for retrieving keys.)"));
            problem = true;
            break;
        case Signature::NoResult:
            ui.verified->clear();//TODO
            break;
    }

#ifndef HAVE_QGPGME
    ui.sigGroup->hide();
    ui.keyGroup->hide();
    ui.verify->hide();
    information.clear();
    information << i18n("Feature is not supported, as KGet is not compiled with QPGME support.");
    resize(350, 200);
#endif //HAVE_QPGME

    //TODO more messages, e.g. from result etc.
    //TODO enter more error cases

    //change the icon of the titlewidget
    if (error) {
        ui.information->setText(i18n("Error:"), KTitleWidget::ErrorMessage);
    } else if (problem) {
        ui.information->setText(i18n("Problems:"), KTitleWidget::WarningMessage);
    } else {
        ui.information->setText(i18n("Information:"), KTitleWidget::InfoMessage);
    }
    ui.information->setComment(information.join(" "));
}

void SignatureDlg::verifyClicked()
{
    clearData();

    m_signature->verify();
}

void SignatureDlg::clearData()
{
    ui.verified->clear();
    ui.verificationIcon->clear();
    ui.issuer->clear();
    ui.email->clear();
    ui.comment->clear();
    ui.creation->clear();
    ui.expiration->clear();
    ui.expirationIcon->hide();
    ui.trust->clear();
    ui.trustIcon->hide();
    ui.fingerprint->clear();
}


#include "signaturedlg.moc"
