/*
 *   This file is part of Dianara
 *   Copyright 2012-2016  JanKusanagi JRR <jancoding@gmx.com>
 *
 *   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 "accountdialog.h"

AccountDialog::AccountDialog(PumpController *pumpController, QWidget *parent) : QWidget(parent)
{
    this->setWindowTitle(tr("Account Configuration") + " - Dianara");
    this->setWindowIcon(QIcon::fromTheme("dialog-password",
                                         QIcon(":/images/button-password.png")));
    this->setWindowFlags(Qt::Dialog);
    this->setWindowModality(Qt::ApplicationModal);
    this->setMinimumSize(640, 520);

    this->pController = pumpController;

    connect(pController, SIGNAL(openingAuthorizeURL(QUrl)),
            this, SLOT(showAuthorizationURL(QUrl)));
    connect(pController, SIGNAL(authorizationStatusChanged(bool)),
            this, SLOT(showAuthorizationStatus(bool)));

    QFont helpFont;
    helpFont.setPointSize(helpFont.pointSize() - 1);

    this->helpMessage1Label = new QLabel(tr("First, enter your Webfinger ID, "
                                            "your pump.io address.") + "<br>"
                                         + tr("Your address looks like "
                                              "username@pumpserver.org, and "
                                              "you can find it in your profile, "
                                              "in the web interface.") + "<br>"
                                         + tr("If your profile is at "
                                              "https://pump.example/yourname, then "
                                              "your address is yourname@pump.example")
                                         + "<br><br>"
                                         + tr("If you don't have an account yet, "
                                              "you can sign up for one at %1. "
                                              "This link will take you to a "
                                              "random public server.",
                                              "1=link to website")
                                           .arg("<a href=\"http://pump.io/tryit.html\">"
                                                "pump.io/tryit.html</a>")
                                         + "<br><br>"
                                         + tr("If you need help: %1")
                                           .arg("<a href=\"https://pumpio.readthedocs.io"
                                                "/en/latest/userguide.html\">"
                                                + tr("Pump.io User Guide")
                                                + "</a>"),
                                         this);
    helpMessage1Label->setWordWrap(true);
    helpMessage1Label->setFont(helpFont);
    helpMessage1Label->setOpenExternalLinks(true);

    userIDIconLabel = new QLabel(this);
    userIDIconLabel->setPixmap(QIcon::fromTheme("preferences-desktop-user",
                                                QIcon(":/images/no-avatar.png"))
                               .pixmap(64,64)
                               .scaledToWidth(64, Qt::SmoothTransformation));
    userIdLabel = new QLabel("<b>" + tr("Your Pump.io address:") + "</b>",
                             this);
    userIdLineEdit = new QLineEdit(this);
    QString userIdTooltip = tr("Your address, like username@pumpserver.org");
    userIdLineEdit->setPlaceholderText(userIdTooltip);
    userIdLineEdit->setToolTip("<b></b>" + userIdTooltip); // HTMLized for wordwrap
    connect(userIdLineEdit, SIGNAL(returnPressed()),
            this, SLOT(askForToken()));

    getVerifierButton = new QPushButton(QIcon::fromTheme("object-unlocked"),
                                        tr("Get &Verifier Code"),
                                        this);
    getVerifierButton->setToolTip("<b></b>" +
                                  tr("After clicking this button, a web "
                                     "browser will open, requesting "
                                     "authorization for Dianara"));
    connect(getVerifierButton, SIGNAL(clicked()),
            this, SLOT(askForToken()));

    this->separatorLine = new QFrame(this);
    separatorLine->setFrameStyle(QFrame::HLine);


    this->helpMessage2Label = new QLabel(tr("Once you have authorized Dianara "
                                            "from your Pump server web "
                                            "interface, you'll receive a code "
                                            "called VERIFIER.\n"
                                            "Copy it and paste it into the "
                                            "field below.",
                                            // Comment for translators
                                            "Don't translate the VERIFIER word!"),
                                         this);
    helpMessage2Label->setWordWrap(true);
    helpMessage2Label->setFont(helpFont);


    verifierIconLabel = new QLabel(this);
    verifierIconLabel->setPixmap(QIcon::fromTheme("dialog-password",
                                                  QIcon(":/images/button-password.png"))
                                 .pixmap(64,64)
                                 .scaledToWidth(64, Qt::SmoothTransformation));

    verifierLabel = new QLabel("<b>" + tr("Verifier code:") + "</b>",
                               this);

    QString verifierTooltip = tr("Enter or paste the verifier code provided "
                                 "by your Pump server here");
    verifierLineEdit = new QLineEdit(this);
    verifierLineEdit->setPlaceholderText(verifierTooltip);
    verifierLineEdit->setToolTip("<b></b>" + verifierTooltip);
    connect(verifierLineEdit, SIGNAL(returnPressed()),
            this, SLOT(setVerifierCode()));


    authorizeApplicationButton = new QPushButton(QIcon::fromTheme("security-high"),
                                                 tr("&Authorize Application"),
                                                 this);
    connect(authorizeApplicationButton, SIGNAL(clicked()),
            this, SLOT(setVerifierCode()));



    // To notify invalid ID or empty verifier code
    // Cleared when typing in any of the two fields
    errorsLabel = new QLabel(this);
    errorsLabel->setOpenExternalLinks(true);
    connect(userIdLineEdit, SIGNAL(textChanged(QString)),
            errorsLabel, SLOT(clear()));
    connect(verifierLineEdit, SIGNAL(textChanged(QString)),
            errorsLabel, SLOT(clear()));


    QFont authorizationStatusFont;
    authorizationStatusFont.setPointSize(authorizationStatusFont.pointSize() + 2);
    authorizationStatusFont.setBold(true);

    authorizationStatusLabel = new QLabel(this);
    authorizationStatusLabel->setFont(authorizationStatusFont);


    saveButton = new QPushButton(QIcon::fromTheme("document-save",
                                                  QIcon(":/images/button-save.png")),
                                 tr("&Save Details"),
                                 this);
    saveButton->setDisabled(true); // Disabled initially
    connect(saveButton, SIGNAL(clicked()),
            this, SLOT(saveDetails()));

    cancelButton = new QPushButton(QIcon::fromTheme("dialog-cancel",
                                                    QIcon(":/images/button-cancel.png")),
                                   tr("&Cancel"),
                                   this);
    connect(cancelButton, SIGNAL(clicked()),
            this, SLOT(hide()));


    // Unlock button, visible when the account is already authorized, + info
    this->unlockExplanationLabel = new QLabel("<b>"
                                              + tr("Your account is properly "
                                                   "configured.")
                                              + "</b>"
                                                "<br><br>"
                                              + tr("Press Unlock if you wish "
                                                   "to configure a different "
                                                   "account.")
                                              + "<hr>",
                                              this);
    unlockExplanationLabel->setAlignment(Qt::AlignHCenter);

    this->unlockButton = new QPushButton(QIcon::fromTheme("object-unlocked"),
                                         tr("&Unlock"),
                                         this);
    connect(unlockButton, SIGNAL(clicked()),
            this, SLOT(unlockDialog()));


    //////////////////////////////////////////////////////////////////// Layout
    this->idLayout = new QHBoxLayout();
    idLayout->addWidget(userIDIconLabel);
    idLayout->addSpacing(4);
    idLayout->addWidget(userIdLabel);
    idLayout->addWidget(userIdLineEdit);
    idLayout->addWidget(getVerifierButton);

    this->verifierLayout = new QHBoxLayout();
    verifierLayout->addWidget(verifierIconLabel);
    verifierLayout->addSpacing(4);
    verifierLayout->addWidget(verifierLabel);
    verifierLayout->addWidget(verifierLineEdit);
    verifierLayout->addWidget(authorizeApplicationButton);


    this->buttonsLayout = new QHBoxLayout();
    buttonsLayout->setAlignment(Qt::AlignRight);
    buttonsLayout->addWidget(saveButton);
    buttonsLayout->addWidget(cancelButton);


    this->mainLayout = new QVBoxLayout();
    mainLayout->addWidget(unlockExplanationLabel, 6);
    mainLayout->addWidget(unlockButton, 0, Qt::AlignHCenter);

    mainLayout->addWidget(helpMessage1Label, 6);
    mainLayout->addSpacing(2);
    mainLayout->addStretch(1);
    mainLayout->addLayout(idLayout, 2);
    mainLayout->addSpacing(4);
    mainLayout->addStretch(1);
    mainLayout->addWidget(separatorLine);
    mainLayout->addStretch(1);
    mainLayout->addSpacing(4);
    mainLayout->addWidget(helpMessage2Label, 2);
    mainLayout->addSpacing(2);
    mainLayout->addStretch(1);
    mainLayout->addLayout(verifierLayout, 2);
    mainLayout->addWidget(errorsLabel,              1, Qt::AlignCenter);
    mainLayout->addSpacing(1);
    mainLayout->addWidget(authorizationStatusLabel, 1, Qt::AlignCenter);
    mainLayout->addStretch(2);
    mainLayout->addSpacing(8);
    mainLayout->addLayout(buttonsLayout, 1);
    this->setLayout(mainLayout);


    QSettings settings;  // Load saved User ID
    userIdLineEdit->setText(settings.value("userID").toString());

    this->showAuthorizationStatus(settings.value("isApplicationAuthorized",
                                                 false).toBool());


    // Disable verifier input field and button initially
    // They will be used after requesting a token
    verifierLineEdit->setDisabled(true);
    authorizeApplicationButton->setDisabled(true);


    qDebug() << "Account dialog created";
}


AccountDialog::~AccountDialog()
{
    qDebug() << "Account dialog destroyed";
}


void AccountDialog::setLockMode(bool locked)
{
    if (locked)
    {
        this->helpMessage1Label->hide();
        this->separatorLine->hide();
        this->helpMessage2Label->hide();

        this->unlockExplanationLabel->show();
        this->unlockButton->show();

        this->verifierLineEdit->setDisabled(true);
        this->authorizeApplicationButton->setDisabled(true);
    }
    else
    {
        this->helpMessage1Label->show();
        this->separatorLine->show();
        this->helpMessage2Label->show();

        this->unlockExplanationLabel->hide();
        this->unlockButton->hide();
    }

    this->userIdLineEdit->setDisabled(locked);
    this->getVerifierButton->setDisabled(locked);
}



//////////////////////////////////////////////////////////////////////////////
///////////////////////////////////// SLOTS //////////////////////////////////
//////////////////////////////////////////////////////////////////////////////



void AccountDialog::askForToken()
{
    QSettings settings;
    settings.setValue("isApplicationAuthorized", false); // Until steps are completed

    // Don't fail if there're spaces before or after the ID, they're only human ;)
    userIdLineEdit->setText(userIdLineEdit->text().trimmed());

    // Match username@server.tld AND check for only 1 @ sign
    if (QRegExp("\\S+@\\S+\\.\\S+").exactMatch(this->userIdLineEdit->text())
     && userIdLineEdit->text().count("@") == 1)
    {
        // Clear verifier field and re-enable it and the button
        this->verifierLineEdit->clear();
        this->verifierLineEdit->setEnabled(true);
        this->authorizeApplicationButton->setEnabled(true);


        // Show message about the web browser that will be started
        this->errorsLabel->setText("[ "
                                   + tr("A web browser will start now, "
                                        "where you can get the verifier code")
                                   + " ]");

        this->pController->setNewUserId(userIdLineEdit->text());
        this->pController->getToken();
    }
    else // userID does not match user@hostname.domain
    {
        this->errorsLabel->setText("[ "
                                   + tr("Your Pump address is invalid")
                                   + " ]");
        qDebug() << "userID is invalid!";
    }
}



void AccountDialog::setVerifierCode()
{
    qDebug() << "AccountDialog::setVerifierCode()"
             << this->verifierLineEdit->text();

    if (!this->verifierLineEdit->text().trimmed().isEmpty())
    {
        this->pController->authorizeApplication(this->verifierLineEdit->text().trimmed());
        this->saveButton->setEnabled(true);
    }
    else
    {
        this->errorsLabel->setText("[ " + tr("Verifier code is empty") + " ]");
    }
}




void AccountDialog::showAuthorizationStatus(bool authorized)
{
    if (authorized)
    {
        this->authorizationStatusLabel->setText(QString::fromUtf8("\342\234\224 ") // Check mark
                                                + tr("Dianara is authorized to "
                                                     "access your data"));
    }
    else
    {
        this->authorizationStatusLabel->clear();
    }

    this->setLockMode(this->pController->currentlyAuthorized());
}


/*
 * Show the authorization URL in a label,
 * in case the browser doesn't open automatically
 *
 */
void AccountDialog::showAuthorizationURL(QUrl url)
{
    QString message = tr("If the browser doesn't open automatically, "
                         "copy this address manually")
                      + ":<br><a href=\""
                      + url.toString()
                      + "\">"
                      + url.toString()
                      + "</a>";
    this->errorsLabel->setText(message);
}





/*
 * Save the new userID and inform other parts of the program about it
 *
 */
void AccountDialog::saveDetails()
{
    QString newUserId = this->userIdLineEdit->text().trimmed();
    if (newUserId.isEmpty() || !newUserId.contains("@"))
    {
        return;  // If no user ID, or with no "@", ignore // FIXME
    }

    QSettings settings;
    settings.setValue("userID", newUserId);
    settings.sync();

    emit userIDChanged(newUserId);


    this->errorsLabel->clear(); // Clear previous error messages, if any

    // If it's authorized, disable the Save Details button
    if (this->pController->currentlyAuthorized())
    {
        this->saveButton->setDisabled(true);
    }

    this->hide(); // close() would end program if main window was hidden
}


void AccountDialog::unlockDialog()
{
    this->setLockMode(false);
}



//////////////////////////////////////////////////////////////////////////////
/////////////////////////////////// PROTECTED ////////////////////////////////
//////////////////////////////////////////////////////////////////////////////


void AccountDialog::hideEvent(QHideEvent *event)
{
    this->setLockMode(this->pController->currentlyAuthorized());

    event->accept();
}
