/* SPDX-License-Identifier: GPL-3.0-or-later
 * SPDX-FileCopyrightText: 2024-2025 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 "FilterEntryDialog.h"
#include "GlobalVariables.h"
#include "ui_FilterEntryDialog.h"

// KDE Framework headers.
#include <KColorScheme>

// Qt toolkit headers.
#include <QShortcut>

// Construct the class.
FilterEntryDialog::FilterEntryDialog(QWidget *parentWidgetPointer, QTableWidget *tableWidgetPointer, const int initialRow, const QString &filterListTitle, const QString &sublistTitle,
                                     bool isAllowList) : QDialog(parentWidgetPointer), currentRow(initialRow), isAllowList(isAllowList), tableWidgetPointer(tableWidgetPointer)
{
    // Set the window modality.
    setWindowModality(Qt::WindowModality::ApplicationModal);

    // Instantiate the filter entry dialog UI.
    Ui::FilterEntryDialog filterEntryDialogUi;

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

    // Get handles for the views.
    QLineEdit *filterListLineEditPointer = filterEntryDialogUi.filterListLineEdit;
    QLineEdit *sublistLineEditPointer = filterEntryDialogUi.sublistListLineEdit;
    appliedEntryListLineEditPointer = filterEntryDialogUi.appliedEntryListLineEdit;
    domainLineEditPointer = filterEntryDialogUi.domainLineEdit;
    thirdPartyLineEditPointer = filterEntryDialogUi.thirdPartyLineEdit;
    initialMatchLineEditPointer = filterEntryDialogUi.initialMatchLineEdit;
    finalMatchLineEditPointer = filterEntryDialogUi.finalMatchLineEdit;
    domainListLineEditPointer = filterEntryDialogUi.domainListLineEdit;
    hasRequestOptionsCheckBoxPointer = filterEntryDialogUi.hasRequestOptionsCheckBox;
    fontLineEditPointer = filterEntryDialogUi.fontLineEdit;
    imageLineEditPointer = filterEntryDialogUi.imageLineEdit;
    mainFrameLineEditPointer = filterEntryDialogUi.mainFrameLineEdit;
    mediaLineEditPointer = filterEntryDialogUi.mediaLineEdit;
    objectLineEditPointer = filterEntryDialogUi.objectLineEdit;
    otherLineEditPointer = filterEntryDialogUi.otherLineEdit;
    pingLineEditPointer = filterEntryDialogUi.pingLineEdit;
    scriptLineEditPointer = filterEntryDialogUi.scriptLineEdit;
    styleSheetLineEditPointer = filterEntryDialogUi.styleSheetLineEdit;
    subFrameLineEditPointer = filterEntryDialogUi.subFrameLineEdit;
    webSocketLineEditPointer = filterEntryDialogUi.webSocketLineEdit;
    xmlHttpRequestLineEditPointer = filterEntryDialogUi.xmlHttpRequestLineEdit;
    appliedFilterOptionsLineEditPointer = filterEntryDialogUi.appliedFilterOptionsLineEdit;
    originalFilterOptionsLineEditPointer = filterEntryDialogUi.originalFilterOptionsLineEdit;
    originalEntryLineEditPointer = filterEntryDialogUi.originalEntryLineEdit;
    previousButtonPointer = filterEntryDialogUi.previousButton;
    nextButtonPointer = filterEntryDialogUi.nextButton;
    QDialogButtonBox *dialogButtonBoxPointer = filterEntryDialogUi.dialogButtonBox;
    QPushButton *closeButtonPointer = dialogButtonBoxPointer->button(QDialogButtonBox::StandardButton::Close);

    // Populate the views.
    filterListLineEditPointer->setText(filterListTitle);
    sublistLineEditPointer->setText(sublistTitle);

    // Disable changing the checkbox checked status.
    hasRequestOptionsCheckBoxPointer->setAttribute(Qt::WA_TransparentForMouseEvents);

    // Make the close button the default.
    closeButtonPointer->setDefault(true);

    // Get the disposition line edit palettes.
    normalBackgroundPalette = appliedEntryListLineEditPointer->palette();
    negativeBackgroundPalette = normalBackgroundPalette;
    positiveBackgroundPalette = normalBackgroundPalette;

    // Modify the palettes.
    KColorScheme::adjustBackground(negativeBackgroundPalette, KColorScheme::NegativeBackground);
    KColorScheme::adjustBackground(positiveBackgroundPalette, KColorScheme::PositiveBackground);

    // Set the background palettes.
    if (isAllowList)
    {
        // Set the background palettes to be positive.
        sublistLineEditPointer->setPalette(positiveBackgroundPalette);
        appliedEntryListLineEditPointer->setPalette(positiveBackgroundPalette);
    }
    else
    {
        // Set the background palettes to be negative.
        sublistLineEditPointer->setPalette(negativeBackgroundPalette);
        appliedEntryListLineEditPointer->setPalette(negativeBackgroundPalette);
    }

    // Connect the buttons.
    connect(previousButtonPointer, SIGNAL(clicked()), this, SLOT(previous()));
    connect(nextButtonPointer, SIGNAL(clicked()), this, SLOT(next()));
    connect(dialogButtonBoxPointer, SIGNAL(rejected()), this, SLOT(close()));

    // Create the keyboard shortcuts.
    QShortcut *previousShortcutPointer = new QShortcut(Qt::Key_Left, this);
    QShortcut *nextShortcutPointer = new QShortcut(Qt::Key_Right, this);

    // Connect the keyboard shortcuts to the buttons.
    connect(previousShortcutPointer, SIGNAL(activated()), previousButtonPointer, SLOT(click()));
    connect(nextShortcutPointer, SIGNAL(activated()), nextButtonPointer, SLOT(click()));

    // Populate the dialog.
    populateDialog(currentRow);
}

void FilterEntryDialog::populateDialog(const int row)
{
    // Set the window title.
    setWindowTitle(i18nc("The filter entry dialog window title", "Filter Entry %1 Detail", row + 1));

    // Select the row in the table widget (this displays the correct row highlighted in the background of the dialog).
    tableWidgetPointer->selectRow(row);

    // Determine if previous should be enabled.
    bool previousEnabled = (row > 0);

    // Determine if next should be enabled.
    bool nextEnabled = (row < (tableWidgetPointer->rowCount() - 1));

    // Populate the line edits.
    appliedEntryListLineEditPointer->setText(tableWidgetPointer->item(row, 0)->text());
    initialMatchLineEditPointer->setText(tableWidgetPointer->item(row, 1)->text());
    finalMatchLineEditPointer->setText(tableWidgetPointer->item(row, 2)->text());
    domainLineEditPointer->setText(tableWidgetPointer->item(row, 3)->text());
    domainListLineEditPointer->setText(tableWidgetPointer->item(row, 4)->text());
    thirdPartyLineEditPointer->setText(tableWidgetPointer->item(row, 5)->text());
    fontLineEditPointer->setText(tableWidgetPointer->item(row, 7)->text());
    imageLineEditPointer->setText(tableWidgetPointer->item(row, 8)->text());
    mainFrameLineEditPointer->setText(tableWidgetPointer->item(row, 9)->text());
    mediaLineEditPointer->setText(tableWidgetPointer->item(row, 10)->text());
    objectLineEditPointer->setText(tableWidgetPointer->item(row, 11)->text());
    otherLineEditPointer->setText(tableWidgetPointer->item(row, 12)->text());
    pingLineEditPointer->setText(tableWidgetPointer->item(row, 13)->text());
    scriptLineEditPointer->setText(tableWidgetPointer->item(row, 14)->text());
    styleSheetLineEditPointer->setText(tableWidgetPointer->item(row, 15)->text());
    subFrameLineEditPointer->setText(tableWidgetPointer->item(row, 16)->text());
    webSocketLineEditPointer->setText(tableWidgetPointer->item(row, 17)->text());
    xmlHttpRequestLineEditPointer->setText(tableWidgetPointer->item(row, 18)->text());
    appliedFilterOptionsLineEditPointer->setText(tableWidgetPointer->item(row, 19)->text());
    originalFilterOptionsLineEditPointer->setText(tableWidgetPointer->item(row, 20)->text());
    originalEntryLineEditPointer->setText(tableWidgetPointer->item(row, 21)->text());

    // Make a local copy of the has request options boolean.
    bool hasRequestOptions = tableWidgetPointer->item(row, 6)->text() == i18n("Yes");

    // Populate the check boxes.
    hasRequestOptionsCheckBoxPointer->setChecked(hasRequestOptions);

    // Set the initial and final match background palettes.
    setInitialAndFinalMatchBackgroundPalette(initialMatchLineEditPointer);
    setInitialAndFinalMatchBackgroundPalette(finalMatchLineEditPointer);

    // Set the request option background palettes.
    setFilterOptionBackgroundPalette(domainLineEditPointer);
    setFilterOptionBackgroundPalette(thirdPartyLineEditPointer);
    setFilterOptionBackgroundPalette(fontLineEditPointer);
    setFilterOptionBackgroundPalette(imageLineEditPointer);
    setFilterOptionBackgroundPalette(mainFrameLineEditPointer);
    setFilterOptionBackgroundPalette(mediaLineEditPointer);
    setFilterOptionBackgroundPalette(objectLineEditPointer);
    setFilterOptionBackgroundPalette(otherLineEditPointer);
    setFilterOptionBackgroundPalette(pingLineEditPointer);
    setFilterOptionBackgroundPalette(scriptLineEditPointer);
    setFilterOptionBackgroundPalette(styleSheetLineEditPointer);
    setFilterOptionBackgroundPalette(subFrameLineEditPointer);
    setFilterOptionBackgroundPalette(webSocketLineEditPointer);
    setFilterOptionBackgroundPalette(xmlHttpRequestLineEditPointer);

    // Set the request option status.
    fontLineEditPointer->setEnabled(hasRequestOptions);
    imageLineEditPointer->setEnabled(hasRequestOptions);
    mainFrameLineEditPointer->setEnabled(hasRequestOptions);
    mediaLineEditPointer->setEnabled(hasRequestOptions);
    objectLineEditPointer->setEnabled(hasRequestOptions);
    otherLineEditPointer->setEnabled(hasRequestOptions);
    pingLineEditPointer->setEnabled(hasRequestOptions);
    scriptLineEditPointer->setEnabled(hasRequestOptions);
    styleSheetLineEditPointer->setEnabled(hasRequestOptions);
    subFrameLineEditPointer->setEnabled(hasRequestOptions);
    webSocketLineEditPointer->setEnabled(hasRequestOptions);
    xmlHttpRequestLineEditPointer->setEnabled(hasRequestOptions);

    // Set the domain list line edit to have the same palette as the domain line edit.
    domainListLineEditPointer->setPalette(domainLineEditPointer->palette());

    // Set the button status.
    previousButtonPointer->setEnabled(previousEnabled);
    nextButtonPointer->setEnabled(nextEnabled);
}

void FilterEntryDialog::previous()
{
    // Update the current row.
    --currentRow;

    // Populate the dialog.
    populateDialog(currentRow);
}

void FilterEntryDialog::next()
{
    // Update the current row.
    ++currentRow;

    // Populate the dialog.
    populateDialog(currentRow);
}

void FilterEntryDialog::setFilterOptionBackgroundPalette(QLineEdit *lineEditPointer)
{
    // Set the background palette according to the text.
    if (lineEditPointer->text() == globalFilterListHelperPointer->getRequestOptionDispositionString(FilterOptionDisposition::Null))  // Not text is displayed.
    {
        // Set the normal background palette.
        lineEditPointer->setPalette(normalBackgroundPalette);
    }
    else if (lineEditPointer->text() == globalFilterListHelperPointer->getRequestOptionDispositionString(FilterOptionDisposition::Apply))  // `Apply` is displayed.
    {
        // Set the background palette according to the sublist type.
        if (isAllowList)
            lineEditPointer->setPalette(positiveBackgroundPalette);
        else
            lineEditPointer->setPalette(negativeBackgroundPalette);
    }
    else  // `Override` is displayed.
    {
        // Set the background palette according to the sublist type.
        if (isAllowList)
            lineEditPointer->setPalette(negativeBackgroundPalette);
        else
            lineEditPointer->setPalette(positiveBackgroundPalette);
    }
}

void FilterEntryDialog::setInitialAndFinalMatchBackgroundPalette(QLineEdit *lineEditPointer)
{
    // Set the background palette according to the text.
    if (lineEditPointer->text() == i18n("Yes"))  // `Yes` is displayed.
    {
        // Set the background palette according to the sublist type.
        if (isAllowList)
            lineEditPointer->setPalette(positiveBackgroundPalette);
        else
            lineEditPointer->setPalette(negativeBackgroundPalette);
    }
    else  // No text is displayed.
    {
        // Set the normal background palette.
        lineEditPointer->setPalette(normalBackgroundPalette);
    }
}
