/*
 * Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
 *
 * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
 *
 * Privacy Browser PC 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 3 of the License, or
 * (at your option) any later version.
 *
 * Privacy Browser PC 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 Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>.
 */

// Application headers.
#include "AddOrEditCookieDialog.h"
#include "ui_AddOrEditCookieDialog.h"
#include "databases/CookiesDatabase.h"

// KDE Framework headers.
#include <KLocalizedString>

// Qt toolkit header.
#include <QPushButton>
#include <QUrl>

// Define the public static constants.
const int AddOrEditCookieDialog::AddCookie = 0;
const int AddOrEditCookieDialog::EditCookie = 1;

// Construct the class.
AddOrEditCookieDialog::AddOrEditCookieDialog(const int &dialogType, const QNetworkCookie *cookiePointer, const bool &isDurable) : QDialog(nullptr)
{
    // Set the dialog window title according to the dialog type.
    if (dialogType == AddCookie)
        setWindowTitle(i18nc("The add cookie dialog window title.", "Add Cookie"));
    else
        setWindowTitle(i18nc("The edit cookie dialog window title.", "Edit Cookie"));

    // Populate the class variables.
    isEditDialog = (dialogType == EditCookie);
    originalIsDurable = isDurable;

    // Set the window modality.
    setWindowModality(Qt::WindowModality::ApplicationModal);

    // Instantiate the cookie settings dialog UI.
    Ui::AddOrEditCookieDialog addOrEditCookieDialogUi;

    // Setup the UI.
    addOrEditCookieDialogUi.setupUi(this);

    // Get handles for the widgets.
    domainLineEditPointer = addOrEditCookieDialogUi.domainLineEdit;
    nameLineEditPointer = addOrEditCookieDialogUi.nameLineEdit;
    durableCheckBoxPointer = addOrEditCookieDialogUi.durableCheckBox;
    expirationCheckBoxPointer = addOrEditCookieDialogUi.expirationCheckBox;
    expirationDateTimeEditPointer = addOrEditCookieDialogUi.expirationDateTimeEdit;
    pathLineEditPointer = addOrEditCookieDialogUi.pathLineEdit;
    httpOnlyCheckBoxPointer = addOrEditCookieDialogUi.httpOnlyCheckBox;
    secureCheckBoxPointer = addOrEditCookieDialogUi.secureCheckBox;
    valueLineEditPointer = addOrEditCookieDialogUi.valueLineEdit;
    QDialogButtonBox *dialogButtonBoxPointer = addOrEditCookieDialogUi.dialogButtonBox;
    saveButtonPointer = dialogButtonBoxPointer->button(QDialogButtonBox::Save);

    // Populate the dialog if editing a cookie.
    if (isEditDialog)
    {
        // Store the old cookie.
        originalCookie = *cookiePointer;

        // Populate the widgets.
        domainLineEditPointer->setText(originalCookie.domain());
        durableCheckBoxPointer->setChecked(originalIsDurable);
        nameLineEditPointer->setText(originalCookie.name());
        pathLineEditPointer->setText(originalCookie.path());
        httpOnlyCheckBoxPointer->setChecked(originalCookie.isHttpOnly());
        secureCheckBoxPointer->setChecked(originalCookie.isSecure());
        valueLineEditPointer->setText(originalCookie.value());

        // Populate the expiration date if it exists.
        if (!originalCookie.isSessionCookie())
        {
            // Check the expiration box.
            expirationCheckBoxPointer->setChecked(true);

            // Enable the expiration date time edit.
            expirationDateTimeEditPointer->setEnabled(true);

            // Set the expiration date.
            expirationDateTimeEditPointer->setDateTime(originalCookie.expirationDate());
        }
    }

    // Connect the line edits.
    connect(domainLineEditPointer, SIGNAL(textEdited(QString)), this, SLOT(updateUi()));
    connect(nameLineEditPointer, SIGNAL(textEdited(QString)), this, SLOT(updateUi()));
    connect(pathLineEditPointer, SIGNAL(textEdited(QString)), this, SLOT(updateUi()));
    connect(valueLineEditPointer, SIGNAL(textEdited(QString)), this, SLOT(updateUi()));

    // Connect the check boxes.
    connect(expirationCheckBoxPointer, SIGNAL(stateChanged(int)), this, SLOT(updateExpirationDateTimeState(int)));

    // Connect the buttons.
    connect(dialogButtonBoxPointer, SIGNAL(accepted()), this, SLOT(saveCookie()));
    connect(dialogButtonBoxPointer, SIGNAL(rejected()), this, SLOT(reject()));

    // Update the UI.
    updateUi();
}

void AddOrEditCookieDialog::saveCookie()
{
    // Delete the old cookie if this is an edit dialog.
    if (isEditDialog)
        emit deleteCookie(originalCookie);

    // Create the variables.
    QNetworkCookie cookie;

    // Populate the cookie.
    cookie.setDomain(domainLineEditPointer->text().toLower());
    cookie.setName(nameLineEditPointer->text().toUtf8());
    cookie.setPath(pathLineEditPointer->text());
    cookie.setHttpOnly(httpOnlyCheckBoxPointer->isChecked());
    cookie.setSecure(secureCheckBoxPointer->isChecked());
    cookie.setValue(valueLineEditPointer->text().toUtf8());

    // Populate the expiration date if it is specified.
    if (expirationCheckBoxPointer->isChecked()) cookie.setExpirationDate(expirationDateTimeEditPointer->dateTime());

    // Get the durable status.
    const bool isDurable = durableCheckBoxPointer->isChecked();

    // Update the durable cookies database.
    if (originalIsDurable)  // The cookie is currently in the durable cookies database.
    {
        if (isDurable)  // Update the cookie in the database.
        {
            qDebug() << "Updating a durable cookie.";

            // Update the cookie in the durable cookies database.
            CookiesDatabase::updateCookie(originalCookie, cookie);
        }
        else  // Delete the cookie from the database.
        {
            qDebug() << "Deleting a durable cookie.";

            // Delete the cookie from the durable cookies database.
            CookiesDatabase::deleteCookie(originalCookie);
        }
    }
    else if (isDurable)  // The cookie is being added to the durable cookies database.
    {
        qDebug() << "Adding a durable cookie.";

        // Add the cookie to the durable cookies database.
        CookiesDatabase::addCookie(cookie);
    }

    // Add the cookie to the store, the list, and the tree.
    emit addCookie(cookie, isDurable);

    // Close the dialog.
    reject();
}

void AddOrEditCookieDialog::updateExpirationDateTimeState(const int &newState) const
{
    // Update the state of the of the expiration date time edit.
    switch (newState)
    {
        case Qt::Unchecked:
            // Disable the expiration date time.
            expirationDateTimeEditPointer->setEnabled(false);

            break;

        case Qt::Checked:
            // Enable the expiration date time edit.
            expirationDateTimeEditPointer->setEnabled(true);

            break;
    }
}

void AddOrEditCookieDialog::updateUi() const
{
    // Update the state of the save button based on all the required fields containing text.
    saveButtonPointer->setDisabled(domainLineEditPointer->text().isEmpty() || nameLineEditPointer->text().isEmpty() || pathLineEditPointer->text().isEmpty() ||
                                    valueLineEditPointer->text().isEmpty());
}
