/* 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 "RequestsDialog.h"
#include "GlobalVariables.h"
#include "RequestDetailDialog.h"
#include "ui_RequestsDialog.h"

// Qt toolkit headers.
#include <QDebug>

// KDE Frameworks headers.
#include <KColorScheme>

// Construct the class.
RequestsDialog::RequestsDialog(QWidget *parentWidgetPointer, QList<RequestStruct *> *requestsListPointer) : QDialog(parentWidgetPointer)
{
    // Set the window title.
    setWindowTitle(i18nc("The requests dialog window title", "Requests"));

    // Instantiate the requests dialog UI.
    Ui::RequestsDialog requestsDialogUi;

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

    // Get handles for the views.
    tableWidgetPointer = requestsDialogUi.tableWidget;
    QDialogButtonBox *dialogButtonBoxPointer = requestsDialogUi.dialogButtonBox;

    // Create the columns.
    tableWidgetPointer->setColumnCount(5);

    // Create the table headers.
    QTableWidgetItem *dispositionHeaderItemPointer = new QTableWidgetItem(i18nc("Request disposition header", "Disposition"));
    QTableWidgetItem *requestMethodHeaderItemPointer = new QTableWidgetItem(i18nc("Request method header", "Request Method"));
    QTableWidgetItem *navigationTypeHeaderItemPointer = new QTableWidgetItem(i18nc("Navigation type header", "Navigation Type"));
    QTableWidgetItem *resourceTypeHeaderItemPointer = new QTableWidgetItem(i18nc("Resource type header", "Resource Type"));
    QTableWidgetItem *requestUrlHeaderItemPointer = new QTableWidgetItem(i18nc("Request URL header", "Request URL"));

    // Set the horizontal headers.
    tableWidgetPointer->setHorizontalHeaderItem(0, dispositionHeaderItemPointer);
    tableWidgetPointer->setHorizontalHeaderItem(1, requestMethodHeaderItemPointer);
    tableWidgetPointer->setHorizontalHeaderItem(2, navigationTypeHeaderItemPointer);
    tableWidgetPointer->setHorizontalHeaderItem(3, resourceTypeHeaderItemPointer);
    tableWidgetPointer->setHorizontalHeaderItem(4, requestUrlHeaderItemPointer);

    // Create the palette.
    QPalette negativePalette = QPalette();
    QPalette positivePalette = QPalette();

    // Adjust the background colors of the palettes.
    KColorScheme::adjustBackground(negativePalette, KColorScheme::NegativeBackground);
    KColorScheme::adjustBackground(positivePalette, KColorScheme::PositiveBackground);

    // Prepare the background brushes.
    QBrush negativeBackgroundBrush = negativePalette.base();
    QBrush positiveBackgroundBrush = positivePalette.base();

    // Initialize the row counter.
    int rowCounter = 0;

    for (RequestStruct *requestStructPointer : *requestsListPointer)
    {
        // Add a new row.
        tableWidgetPointer->insertRow(rowCounter);

        // Create the entry items.
        QTableWidgetItem *dispositionItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getDispositionString(requestStructPointer->dispositionInt));
        QTableWidgetItem *requestMethodItemPointer = new QTableWidgetItem(requestStructPointer->requestMethodString);
        QTableWidgetItem *navigationTypeItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getNavigationTypeString(requestStructPointer->navigationTypeInt));
        QTableWidgetItem *resourceTypeItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getResourceTypeString(requestStructPointer->resourceTypeInt));
        QTableWidgetItem *requestUrlItemPointer = new QTableWidgetItem(requestStructPointer->urlString);

        // Create a request struct byte array.
        QByteArray *requestStructByteArrayPointer = new QByteArray();

        // Create a request struct data stream.
        QDataStream requestStructDataStream(requestStructByteArrayPointer, QIODevice::WriteOnly);

        // Populate the request struct data stream.  The order needs to match what is populated from the data stream in RequestDetailDialog.cpp.
        requestStructDataStream << requestStructPointer->dispositionInt;
        requestStructDataStream << requestStructPointer->filterListEntryStruct.originalEntryString;
        requestStructDataStream << requestStructPointer->filterListEntryStruct.originalFilterOptionsString;
        requestStructDataStream << requestStructPointer->filterListEntryStruct.appliedEntryList;
        requestStructDataStream << requestStructPointer->filterListEntryStruct.appliedFilterOptionsList;
        requestStructDataStream << requestStructPointer->filterListEntryStruct.domainList;
        requestStructDataStream << requestStructPointer->filterListEntryStruct.finalMatch;
        requestStructDataStream << requestStructPointer->filterListEntryStruct.hasRequestOptions;
        requestStructDataStream << requestStructPointer->filterListEntryStruct.initialMatch;
        requestStructDataStream << requestStructPointer->filterListEntryStruct.domain;
        requestStructDataStream << requestStructPointer->filterListEntryStruct.font;
        requestStructDataStream << requestStructPointer->filterListEntryStruct.image;
        requestStructDataStream << requestStructPointer->filterListEntryStruct.mainFrame;
        requestStructDataStream << requestStructPointer->filterListEntryStruct.media;
        requestStructDataStream << requestStructPointer->filterListEntryStruct.object;
        requestStructDataStream << requestStructPointer->filterListEntryStruct.other;
        requestStructDataStream << requestStructPointer->filterListEntryStruct.ping;
        requestStructDataStream << requestStructPointer->filterListEntryStruct.script;
        requestStructDataStream << requestStructPointer->filterListEntryStruct.styleSheet;
        requestStructDataStream << requestStructPointer->filterListEntryStruct.subFrame;
        requestStructDataStream << requestStructPointer->filterListEntryStruct.thirdParty;
        requestStructDataStream << requestStructPointer->filterListEntryStruct.webSocket;
        requestStructDataStream << requestStructPointer->filterListEntryStruct.xmlHttpRequest;
        requestStructDataStream << requestStructPointer->filterListTitle;
        requestStructDataStream << requestStructPointer->isThirdPartyRequest;
        requestStructDataStream << requestStructPointer->matchedUrlType;
        requestStructDataStream << requestStructPointer->navigationTypeInt;
        requestStructDataStream << requestStructPointer->requestMethodString;
        requestStructDataStream << requestStructPointer->resourceTypeInt;
        requestStructDataStream << requestStructPointer->sublistInt;
        requestStructDataStream << requestStructPointer->truncatedUrlString;
        requestStructDataStream << requestStructPointer->truncatedUrlStringWithSeparators;
        requestStructDataStream << requestStructPointer->urlString;
        requestStructDataStream << requestStructPointer->urlStringWithSeparators;
        requestStructDataStream << requestStructPointer->webPageUrlString;

        // Add the request struct to the disposition item.
        dispositionItemPointer->setData(Qt::UserRole, *requestStructByteArrayPointer);

        // Colorize the background according to the disposition.
        if (requestStructPointer->dispositionInt == FilterListHelper::BLOCKED)  // The request was blocked.
        {
            // Set the background to be red.
            dispositionItemPointer->setBackground(negativeBackgroundBrush);
            requestMethodItemPointer->setBackground(negativeBackgroundBrush);
            navigationTypeItemPointer->setBackground(negativeBackgroundBrush);
            resourceTypeItemPointer->setBackground(negativeBackgroundBrush);
            requestUrlItemPointer->setBackground(negativeBackgroundBrush);
        }
        else if (requestStructPointer->dispositionInt == FilterListHelper::ALLOWED)  // The request was allowed.
        {
            // Set the background to be green.
            dispositionItemPointer->setBackground(positiveBackgroundBrush);
            requestMethodItemPointer->setBackground(positiveBackgroundBrush);
            navigationTypeItemPointer->setBackground(positiveBackgroundBrush);
            resourceTypeItemPointer->setBackground(positiveBackgroundBrush);
            requestUrlItemPointer->setBackground(positiveBackgroundBrush);
        }

        // Add the entries to the table.
        tableWidgetPointer->setItem(rowCounter, 0, dispositionItemPointer);
        tableWidgetPointer->setItem(rowCounter, 1, requestMethodItemPointer);
        tableWidgetPointer->setItem(rowCounter, 2, navigationTypeItemPointer);
        tableWidgetPointer->setItem(rowCounter, 3, resourceTypeItemPointer);
        tableWidgetPointer->setItem(rowCounter, 4, requestUrlItemPointer);

        // Increment the row counter.
        ++rowCounter;
    }

    // Select an entire row at a time.
    tableWidgetPointer->setSelectionBehavior(QAbstractItemView::SelectRows);

    // Get the table header view.
    QHeaderView *headerViewPointer = tableWidgetPointer->horizontalHeader();

    // Resize the header to fit the contents.
    headerViewPointer->resizeSections(QHeaderView::ResizeToContents);

    // Connect changes in the sort order.
    connect(headerViewPointer, SIGNAL(sortIndicatorChanged(int, Qt::SortOrder)), this, SLOT(sortTable(int, Qt::SortOrder)));

    // Connect the buttons.
    connect(dialogButtonBoxPointer, SIGNAL(rejected()), this, SLOT(close()));

    // Open the request detail dialog when a cell is clicked.
    connect(tableWidgetPointer, SIGNAL(cellClicked(int, int)), this, SLOT(showRequestDetailDialog(int)));
}

void RequestsDialog::showRequestDetailDialog(int row)
{
    // Instantiate the request details dialog.
    RequestDetailDialog *requestDetailDialogPointer = new RequestDetailDialog(this, tableWidgetPointer, row);

    // Show the dialog.
    requestDetailDialogPointer->show();
}

void RequestsDialog::sortTable(int column, Qt::SortOrder sortOrder) const
{
    // Sort the table.
    tableWidgetPointer->sortItems(column, sortOrder);
}
