///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2024 Jon Beniston, M7RCE <jon@beniston.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 as 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 V3 for more details.                               //
//                                                                               //
// You should have received a copy of the GNU General Public License             //
// along with this program. If not, see <http://www.gnu.org/licenses/>.          //
///////////////////////////////////////////////////////////////////////////////////

#include <QFileDialog>
#include <QPushButton>

#include "remotetcpsinksettingsdialog.h"
#include "ui_remotetcpsinksettingsdialog.h"

RemoteTCPSinkSettingsDialog::RemoteTCPSinkSettingsDialog(RemoteTCPSinkSettings *settings, QWidget* parent) :
    QDialog(parent),
    ui(new Ui::RemoteTCPSinkSettingsDialog),
    m_settings(settings),
    m_availableRotatorHandler({"sdrangel.feature.gs232controller"})
{
    ui->setupUi(this);

    ui->maxClients->setValue(m_settings->m_maxClients);
    ui->timeLimit->setValue(m_settings->m_timeLimit);
    ui->maxSampleRate->setValue(m_settings->m_maxSampleRate);
    if (m_settings->m_protocol == RemoteTCPSinkSettings::RTL0)
    {
        ui->iqOnly->setChecked(true);
        ui->iqOnlyLabel->setEnabled(false);
        ui->iqOnly->setEnabled(false);
    }
    else
    {
        ui->iqOnly->setChecked(m_settings->m_iqOnly);
    }

    ui->compressor->setCurrentIndex((int) m_settings->m_compression);
    ui->compressionLevel->setValue(m_settings->m_compressionLevel);
    ui->blockSize->setCurrentIndex(ui->blockSize->findText(QString::number(m_settings->m_blockSize)));

    ui->certificate->setText(m_settings->m_certificate);
    ui->key->setText(m_settings->m_key);
    if (m_settings->m_protocol != RemoteTCPSinkSettings::SDRA_WSS) {
        ui->sslSettingsGroup->setEnabled(false);
    }

    ui->publicListing->setChecked(m_settings->m_public);
    ui->publicAddress->setText(m_settings->m_publicAddress);
    ui->publicPort->setValue(m_settings->m_publicPort);
    ui->minFrequency->setValue(m_settings->m_minFrequency / 1000000);
    ui->maxFrequency->setValue(m_settings->m_maxFrequency / 1000000);
    ui->antenna->setText(m_settings->m_antenna);
    ui->location->setText(m_settings->m_location);
    ui->isotropic->setChecked(m_settings->m_isotropic);
    ui->azimuth->setValue(m_settings->m_azimuth);
    ui->elevation->setValue(m_settings->m_elevation);
    ui->rotator->setCurrentText(m_settings->m_rotator);

    for (const auto& ip : m_settings->m_ipBlacklist) {
        ui->ipBlacklist->addItem(ip);
    }

    QObject::connect(
        &m_availableRotatorHandler,
        &AvailableChannelOrFeatureHandler::channelsOrFeaturesChanged,
        this,
        &RemoteTCPSinkSettingsDialog::rotatorsChanged
    );
    m_availableRotatorHandler.scanAvailableChannelsAndFeatures();
}

RemoteTCPSinkSettingsDialog::~RemoteTCPSinkSettingsDialog()
{
    delete ui;
}

void RemoteTCPSinkSettingsDialog::accept()
{
    if (!isValid()) {
        return;
    }

    QDialog::accept();

    if (ui->maxClients->value() != m_settings->m_maxClients)
    {
        m_settings->m_maxClients = ui->maxClients->value();
        m_settingsKeys.append("maxClients");
    }
    if (ui->timeLimit->value() != m_settings->m_timeLimit)
    {
        m_settings->m_timeLimit = ui->timeLimit->value();
        m_settingsKeys.append("timeLimit");
    }
    if (ui->maxSampleRate->value() != m_settings->m_maxSampleRate)
    {
        m_settings->m_maxSampleRate = ui->maxSampleRate->value();
        m_settingsKeys.append("maxSampleRate");
    }
    if (m_settings->m_protocol != RemoteTCPSinkSettings::RTL0)
    {
        if (ui->iqOnly->isChecked() != m_settings->m_iqOnly)
        {
            m_settings->m_iqOnly = ui->iqOnly->isChecked();
            m_settingsKeys.append("iqOnly");
        }
    }
    RemoteTCPSinkSettings::Compressor compressor = (RemoteTCPSinkSettings::Compressor) ui->compressor->currentIndex();
    if (compressor != m_settings->m_compression)
    {
        m_settings->m_compression = compressor;
        m_settingsKeys.append("compression");
    }
    if (ui->compressionLevel->value() != m_settings->m_compressionLevel)
    {
        m_settings->m_compressionLevel = ui->compressionLevel->value();
        m_settingsKeys.append("compressionLevel");
    }
    int blockSize = ui->blockSize->currentText().toInt();
    if (blockSize != m_settings->m_blockSize)
    {
        m_settings->m_blockSize = blockSize;
        m_settingsKeys.append("blockSize");
    }
    if (ui->certificate->text() != m_settings->m_certificate)
    {
        m_settings->m_certificate = ui->certificate->text();
        m_settingsKeys.append("certificate");
    }
    if (ui->key->text() != m_settings->m_key)
    {
        m_settings->m_key = ui->key->text();
        m_settingsKeys.append("key");
    }
    if (ui->publicListing->isChecked() != m_settings->m_public)
    {
        m_settings->m_public = ui->publicListing->isChecked();
        m_settingsKeys.append("public");
    }
    if (ui->publicAddress->text() != m_settings->m_publicAddress)
    {
        m_settings->m_publicAddress = ui->publicAddress->text();
        m_settingsKeys.append("publicAddress");
    }
    if (ui->publicPort->value() != m_settings->m_publicPort)
    {
        m_settings->m_publicPort = ui->publicPort->value();
        m_settingsKeys.append("publicPort");
    }
    qint64 minFrequency = ui->minFrequency->value() * 1000000;
    if (minFrequency != m_settings->m_minFrequency)
    {
        m_settings->m_minFrequency = minFrequency;
        m_settingsKeys.append("minFrequency");
    }
    qint64 maxFrequency = ui->maxFrequency->value() * 1000000;
    if (maxFrequency != m_settings->m_maxFrequency)
    {
        m_settings->m_maxFrequency = maxFrequency;
        m_settingsKeys.append("maxFrequency");
    }
    if (ui->antenna->text() != m_settings->m_antenna)
    {
        m_settings->m_antenna = ui->antenna->text();
        m_settingsKeys.append("antenna");
    }
    if (ui->location->text() != m_settings->m_location)
    {
        m_settings->m_location = ui->location->text();
        m_settingsKeys.append("location");
    }
    if (ui->isotropic->isChecked() != m_settings->m_isotropic)
    {
        m_settings->m_isotropic = ui->isotropic->isChecked();
        m_settingsKeys.append("isotropic");
    }
    if (ui->azimuth->value() != m_settings->m_azimuth)
    {
        m_settings->m_azimuth = ui->azimuth->value();
        m_settingsKeys.append("azimuth");
    }
    if (ui->elevation->value() != m_settings->m_elevation)
    {
        m_settings->m_elevation = ui->elevation->value();
        m_settingsKeys.append("elevation");
    }
    if (ui->rotator->currentText() != m_settings->m_rotator)
    {
        m_settings->m_rotator = ui->rotator->currentText();
        m_settingsKeys.append("rotator");
    }
    QStringList ipBlacklist;
    for (int i = 0; i < ui->ipBlacklist->count(); i++)
    {
        QString ip = ui->ipBlacklist->item(i)->text().trimmed();
        if (!ip.isEmpty()) {
            ipBlacklist.append(ip);
        }
    }
    if (ipBlacklist != m_settings->m_ipBlacklist)
    {
        m_settings->m_ipBlacklist = ipBlacklist;
        m_settingsKeys.append("ipBlacklist");
    }
}

void RemoteTCPSinkSettingsDialog::on_browseCertificate_clicked()
{
    QString fileName = QFileDialog::getOpenFileName(this, tr("Select SSL Certificate"),
                                                "",
                                                tr("SSL certificate (*.cert *.pem)"));
    if (!fileName.isEmpty()) {
        ui->certificate->setText(fileName);
    }
}

void RemoteTCPSinkSettingsDialog::on_browseKey_clicked()
{
    QString fileName = QFileDialog::getOpenFileName(this, tr("Select SSL Key"),
                                                "",
                                                tr("SSL key (*.key *.pem)"));
    if (!fileName.isEmpty()) {
        ui->key->setText(fileName);
    }
}

void RemoteTCPSinkSettingsDialog::on_addIP_clicked()
{
    QListWidgetItem *item = new QListWidgetItem("1.1.1.1");
    item->setFlags(Qt::ItemIsEditable | item->flags());
    ui->ipBlacklist->addItem(item);
    item->setSelected(true);
}

void RemoteTCPSinkSettingsDialog::on_removeIP_clicked()
{
    qDeleteAll(ui->ipBlacklist->selectedItems());
}

void RemoteTCPSinkSettingsDialog::on_publicListing_toggled()
{
    displayValid();
    displayEnabled();
}

void RemoteTCPSinkSettingsDialog::on_publicAddress_textChanged()
{
    displayValid();
}

void RemoteTCPSinkSettingsDialog::on_compressor_currentIndexChanged(int index)
{
    if (index == 0)
    {
        // FLAC settings
        ui->compressionLevel->setMaximum(8);
        ui->blockSize->clear();
        ui->blockSize->addItem("4096");
        ui->blockSize->addItem("16384");
        ui->blockSize->setCurrentIndex(1);
    }
    else if (index == 1)
    {
        // zlib settings
        ui->compressionLevel->setMaximum(9);
        ui->blockSize->clear();
        ui->blockSize->addItem("4096");
        ui->blockSize->addItem("8192");
        ui->blockSize->addItem("16384");
        ui->blockSize->addItem("32768");
        ui->blockSize->setCurrentIndex(3);
    }
}

void RemoteTCPSinkSettingsDialog::on_iqOnly_toggled(bool checked)
{
    ui->compressionSettings->setEnabled(!checked);
}

void RemoteTCPSinkSettingsDialog::on_isotropic_toggled(bool checked)
{
    (void) checked;

    displayEnabled();
}

void RemoteTCPSinkSettingsDialog::on_rotator_currentIndexChanged(int index)
{
    (void) index;

    displayEnabled();
}

bool RemoteTCPSinkSettingsDialog::isValid()
{
    bool valid = true;

    if (ui->publicListing->isChecked() && ui->publicAddress->text().isEmpty()) {
        valid = false;
    }

    return valid;
}

void RemoteTCPSinkSettingsDialog::displayValid()
{
    bool valid = isValid();

    ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(valid);
}

void RemoteTCPSinkSettingsDialog::displayEnabled()
{
    bool enabled = ui->publicListing->isChecked();
    bool none = ui->rotator->currentText() == "None";
    bool isotropic = ui->isotropic->isChecked();

    ui->publicAddressLabel->setEnabled(enabled);
    ui->publicAddress->setEnabled(enabled);
    ui->publicPort->setEnabled(enabled);
    ui->frequencyLabel->setEnabled(enabled);
    ui->minFrequency->setEnabled(enabled);
    ui->maxFrequency->setEnabled(enabled);
    ui->frequencyUnits->setEnabled(enabled);
    ui->antennaLabel->setEnabled(enabled);
    ui->antenna->setEnabled(enabled);
    ui->locationLabel->setEnabled(enabled);
    ui->location->setEnabled(enabled);
    ui->isotropicLabel->setEnabled(enabled);
    ui->isotropic->setEnabled(enabled);
    ui->rotatorLabel->setEnabled(enabled && !isotropic);
    ui->rotator->setEnabled(enabled && !isotropic);
    ui->directionLabel->setEnabled(enabled && !isotropic && none);
    ui->azimuthLabel->setEnabled(enabled && !isotropic && none);
    ui->azimuth->setEnabled(enabled && !isotropic && none);
    ui->elevationLabel->setEnabled(enabled && !isotropic && none);
    ui->elevation->setEnabled(enabled && !isotropic && none);
}

void RemoteTCPSinkSettingsDialog::rotatorsChanged(const QStringList& renameFrom, const QStringList& renameTo)
{
    AvailableChannelOrFeatureList rotators = m_availableRotatorHandler.getAvailableChannelOrFeatureList();
    updateRotatorList(rotators, renameFrom, renameTo);
}

void RemoteTCPSinkSettingsDialog::updateRotatorList(const AvailableChannelOrFeatureList& rotators, const QStringList& renameFrom, const QStringList& renameTo)
{
    // Update rotator settting if it has been renamed
    if (renameFrom.contains(m_settings->m_rotator)) {
        m_settings->m_rotator = renameTo[renameFrom.indexOf(m_settings->m_rotator)];
    }

    // Update list of rotators
    ui->rotator->blockSignals(true);
    ui->rotator->clear();
    ui->rotator->addItem("None");

    for (const auto& rotator : rotators) {
        ui->rotator->addItem(rotator.getLongId());
    }

    // Rotator feature can be created after this plugin, so select it
    // if the chosen rotator appears
    int rotatorIndex = ui->rotator->findText(m_settings->m_rotator);

    if (rotatorIndex >= 0)
    {
        ui->rotator->setCurrentIndex(rotatorIndex);
    }
    else
    {
        ui->rotator->setCurrentIndex(0); // return to None
    }

    ui->rotator->blockSignals(false);

    displayEnabled();
}