/* SPDX-License-Identifier: GPL-3.0-or-later
 * SPDX-FileCopyrightText: 2022-2024 Soren Stoutner <soren@stoutner.com>
 *
 * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc/>.
 *
 * 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 3 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, see <https://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(QWidget *parentWidgetPointer, const int dialogType, const QNetworkCookie *cookiePointer, const bool isDurable) : QDialog(parentWidgetPointer)
{
    // 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 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(QLatin1String(originalCookie.name()));
        pathLineEditPointer->setText(originalCookie.path());
        httpOnlyCheckBoxPointer->setChecked(originalCookie.isHttpOnly());
        secureCheckBoxPointer->setChecked(originalCookie.isSecure());
        valueLineEditPointer->setText(QLatin1String(originalCookie.value()));

        // Scroll to the beginning of the line edits.
        domainLineEditPointer->setCursorPosition(0);
        nameLineEditPointer->setCursorPosition(0);
        pathLineEditPointer->setCursorPosition(0);
        valueLineEditPointer->setCursorPosition(0);

        // 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)
        Q_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.
    Q_EMIT addCookie(cookie, isDurable);

    // Close the dialog.
    close();
}

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());
}

