// qpwgraph_options.cpp
//
/****************************************************************************
   Copyright (C) 2021-2026, rncbc aka Rui Nuno Capela. All rights reserved.

   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 2
   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, write to the Free Software Foundation, Inc.,
   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

*****************************************************************************/

#include "config.h"

#include "qpwgraph_options.h"

#include "qpwgraph_main.h"
#include "qpwgraph_config.h"
#include "qpwgraph_palette.h"

#include <QMessageBox>
#include <QPushButton>

#include <QLineEdit>

#ifdef CONFIG_SYSTEM_TRAY
#include <QSystemTrayIcon>
#endif

#include <QStyleFactory>


// Default (empty/blank) name.
static const char *DefaultName  = "(default)";


//----------------------------------------------------------------------------
// qpwgraph_options -- UI wrapper form.

// Constructor.
qpwgraph_options::qpwgraph_options ( qpwgraph_main *parent )
	: QDialog(parent)
{
	// Setup UI struct...
	m_ui.setupUi(this);

	// Initialize dirty control state.
	m_dirty = 0;

	m_dirty_filter = 0;
	m_dirty_merger = 0;

	m_style = nullptr;

	// Setup current options...
	qpwgraph_config *config = parent->config();
	if (config) {
		config->loadComboBoxHistory(m_ui.MergerNodesNameComboBox);
		config->loadComboBoxHistory(m_ui.FilterNodesNameComboBox);
	#ifdef CONFIG_SYSTEM_TRAY
		m_ui.SystemTrayEnabledCheckBox->setChecked(
			config->isSystemTrayEnabled());
		m_ui.SystemTrayQueryCloseCheckBox->setChecked(
			config->isSystemTrayQueryClose());
		m_ui.SystemTrayStartMinimizedCheckBox->setChecked(
			config->isStartMinimized());
	#endif
		m_ui.PatchbayQueryQuitCheckBox->setChecked(
			config->isPatchbayQueryQuit());
	#ifdef CONFIG_ALSA_MIDI
		m_ui.AlsaMidiEnabledCheckBox->setChecked(
			config->isAlsaMidiEnabled());
	#endif
		resetCustomColorThemes(config->customColorTheme());
		resetCustomStyleThemes(config->customStyleTheme());
	}

#ifdef CONFIG_SYSTEM_TRAY
	if (!QSystemTrayIcon::isSystemTrayAvailable()) {
		m_ui.SystemTrayEnabledCheckBox->setEnabled(false);
		m_ui.SystemTrayQueryCloseCheckBox->setEnabled(false);
		m_ui.SystemTrayStartMinimizedCheckBox->setChecked(false);
	}
#else
	m_ui.SystemTrayEnabledCheckBox->hide();
	m_ui.SystemTrayQueryCloseCheckBox->hide();
	m_ui.SystemTrayStartMinimizedCheckBox->hide();
#endif

#ifndef CONFIG_ALSA_MIDI
	m_ui.AlsaMidiEnabledCheckBox->hide();
#endif

	// Filter/hide list management...
	//
	if (config) {
		m_ui.FilterNodesEnabledCheckBox->setChecked(
			config->isFilterNodesEnabled());
		m_ui.FilterNodesNameComboBox->lineEdit()->setClearButtonEnabled(true);
		m_ui.FilterNodesNameComboBox->lineEdit()->setPlaceholderText(
			m_ui.FilterNodesNameComboBox->toolTip());
		m_ui.FilterNodesNameComboBox->setCurrentText(QString());
		m_ui.FilterNodesListWidget->clear();
		m_ui.FilterNodesListWidget->addItems(
			config->filterNodesList());
	}

	// Merger/unify list management...
	//
	if (config) {
		m_ui.MergerNodesEnabledCheckBox->setChecked(
			config->isMergerNodesEnabled());
		m_ui.MergerNodesNameComboBox->lineEdit()->setClearButtonEnabled(true);
		m_ui.MergerNodesNameComboBox->lineEdit()->setPlaceholderText(
			m_ui.MergerNodesNameComboBox->toolTip());
		m_ui.MergerNodesNameComboBox->setCurrentText(QString());
		m_ui.MergerNodesListWidget->clear();
		m_ui.MergerNodesListWidget->addItems(
			config->mergerNodesList());
	}

	// Try to restore old window positioning.
	adjustSize();

	// UI connections...
#ifdef CONFIG_SYSTEM_TRAY
	QObject::connect(m_ui.SystemTrayEnabledCheckBox,
		SIGNAL(stateChanged(int)),
		SLOT(changed()));
	QObject::connect(m_ui.SystemTrayQueryCloseCheckBox,
		SIGNAL(stateChanged(int)),
		SLOT(changed()));
	QObject::connect(m_ui.SystemTrayStartMinimizedCheckBox,
		SIGNAL(stateChanged(int)),
		SLOT(changed()));
#endif
	QObject::connect(m_ui.PatchbayQueryQuitCheckBox,
		SIGNAL(stateChanged(int)),
		SLOT(changed()));
#ifdef CONFIG_ALSA_MIDI
	QObject::connect(m_ui.AlsaMidiEnabledCheckBox,
		SIGNAL(stateChanged(int)),
		SLOT(changed()));
#endif

	QObject::connect(m_ui.FilterNodesEnabledCheckBox,
		SIGNAL(stateChanged(int)),
		SLOT(changedFilterNodes()));
	QObject::connect(m_ui.FilterNodesNameComboBox,
		SIGNAL(editTextChanged(const QString&)),
		SLOT(stabilize()));
	QObject::connect(m_ui.FilterNodesAddToolButton,
		SIGNAL(clicked()),
		SLOT(addFilterNodes()));
	QObject::connect(m_ui.FilterNodesListWidget,
		SIGNAL(itemSelectionChanged()),
		SLOT(selectFilterNodes()));
	QObject::connect(m_ui.FilterNodesRemoveToolButton,
		SIGNAL(clicked()),
		SLOT(removeFilterNodes()));
	QObject::connect(m_ui.FilterNodesClearToolButton,
		SIGNAL(clicked()),
		SLOT(clearFilterNodes()));

	QObject::connect(m_ui.MergerNodesEnabledCheckBox,
		SIGNAL(stateChanged(int)),
		SLOT(changedMergerNodes()));
	QObject::connect(m_ui.MergerNodesNameComboBox,
		SIGNAL(editTextChanged(const QString&)),
		SLOT(stabilize()));
	QObject::connect(m_ui.MergerNodesAddToolButton,
		SIGNAL(clicked()),
		SLOT(addMergerNodes()));
	QObject::connect(m_ui.MergerNodesListWidget,
		SIGNAL(itemSelectionChanged()),
		SLOT(selectMergerNodes()));
	QObject::connect(m_ui.MergerNodesRemoveToolButton,
		SIGNAL(clicked()),
		SLOT(removeMergerNodes()));
	QObject::connect(m_ui.MergerNodesClearToolButton,
		SIGNAL(clicked()),
		SLOT(clearMergerNodes()));

	QObject::connect(m_ui.CustomColorThemeComboBox,
		SIGNAL(activated(int)),
		SLOT(customColorThemeChanged(int)));
	QObject::connect(m_ui.CustomColorThemeToolButton,
		SIGNAL(clicked()),
		SLOT(editCustomColorThemes()));
	QObject::connect(m_ui.CustomStyleThemeComboBox,
		SIGNAL(activated(int)),
		SLOT(customStyleThemeChanged(int)));

	QObject::connect(m_ui.DialogButtonBox,
		SIGNAL(accepted()),
		SLOT(accept()));
	QObject::connect(m_ui.DialogButtonBox,
		SIGNAL(rejected()),
		SLOT(reject()));

	// Ready?
	stabilize();
}


// Destructor.
qpwgraph_options::~qpwgraph_options (void)
{
	if (m_style)
		delete m_style;
}


// Reject options (Cancel button slot).
void qpwgraph_options::reject (void)
{
	bool ret = true;

	// Check if there's any pending changes...
	if (m_dirty > 0) {
		switch (QMessageBox::warning(this,
			tr("Warning"),
			tr("Some options have been changed.") + "\n\n" +
			tr("Do you want to apply the changes?"),
			QMessageBox::Apply | QMessageBox::Discard | QMessageBox::Cancel)) {
		case QMessageBox::Apply:
			accept();
			return;
		case QMessageBox::Discard:
			break;
		default: // Cancel.
			ret = false;
		}
	}

	if (ret)
		QDialog::reject();
}


// Accept options (OK button slot).
void qpwgraph_options::accept (void)
{
	qpwgraph_config *config = nullptr;
	qpwgraph_main *parent = qobject_cast<qpwgraph_main *> (parentWidget());
	if (parent)
		config = parent->config();
	if (config) {
	#ifdef CONFIG_SYSTEM_TRAY
		config->setSystemTrayEnabled(
			m_ui.SystemTrayEnabledCheckBox->isChecked());
		config->setSystemTrayQueryClose(
			m_ui.SystemTrayQueryCloseCheckBox->isChecked());
		config->setStartMinimized(
			m_ui.SystemTrayStartMinimizedCheckBox->isChecked());
	#endif
		config->setPatchbayQueryQuit(
			m_ui.PatchbayQueryQuitCheckBox->isChecked());
	#ifdef CONFIG_ALSA_MIDI
		config->setAlsaMidiEnabled(
			m_ui.AlsaMidiEnabledCheckBox->isChecked());
	#endif
		if (m_dirty_filter > 0) {
			config->setFilterNodesEnabled(
				m_ui.FilterNodesEnabledCheckBox->isChecked());
			QStringList nodes;
			const int n = m_ui.FilterNodesListWidget->count();
			for (int i = 0; i < n; ++i) {
				QListWidgetItem *item = m_ui.FilterNodesListWidget->item(i);
				if (item)
					nodes.append(item->text());
			}
			config->setFilterNodesList(nodes);
			config->setFilterNodesDirty(true);
			m_dirty_filter = 0;
		}
		config->saveComboBoxHistory(m_ui.FilterNodesNameComboBox);
		if (m_dirty_merger > 0) {
			config->setMergerNodesEnabled(
				m_ui.MergerNodesEnabledCheckBox->isChecked());
			QStringList nodes;
			const int n = m_ui.MergerNodesListWidget->count();
			for (int i = 0; i < n; ++i) {
				QListWidgetItem *item = m_ui.MergerNodesListWidget->item(i);
				if (item)
					nodes.append(item->text());
			}
			config->setMergerNodesList(nodes);
			config->setMergerNodesDirty(true);
			m_dirty_merger = 0;
		}
		config->saveComboBoxHistory(m_ui.MergerNodesNameComboBox);
		// Custom themeing...
		int nrestart = 0;
		const QString& old_style_theme
			= config->customStyleTheme();
		QString style_theme;
		if (m_ui.CustomStyleThemeComboBox->currentIndex() > 0)
			style_theme = m_ui.CustomStyleThemeComboBox->currentText();
		if (style_theme != old_style_theme) {
			if (style_theme.isEmpty())
				++nrestart;
			config->setCustomStyleTheme(style_theme);
			config->setCustomStyleDirty(true);
		}
		const QString& old_color_theme
			= config->customColorTheme();
		QString color_theme;
		if (m_ui.CustomColorThemeComboBox->currentIndex() > 0)
			color_theme = m_ui.CustomColorThemeComboBox->currentText();
		if (color_theme != old_color_theme) {
			if (color_theme.isEmpty())
				++nrestart;
			config->setCustomColorTheme(color_theme);
			config->setCustomColorDirty(true);
		}
		// Show restart message if needed...
		if (nrestart > 0) {
			QMessageBox::information(this,
				tr("Information"),
				tr("Some settings may be only effective\n"
				"next time you start this application."));
		}
		// Realize options...
		parent->updateOptions(true);
	}

	QDialog::accept();
}


// Dirty up options.
void qpwgraph_options::changed (void)
{
	++m_dirty;

	stabilize();
}


// Filter/hide list management...
//
void qpwgraph_options::changedFilterNodes (void)
{
	++m_dirty_filter;

	changed();
}


void qpwgraph_options::selectFilterNodes (void)
{
	QListWidgetItem *item = m_ui.FilterNodesListWidget->currentItem();
	if (item)
		m_ui.FilterNodesNameComboBox->setEditText(item->text());

	stabilize();
}


void qpwgraph_options::addFilterNodes (void)
{
	const QString& node_name
		= m_ui.FilterNodesNameComboBox->currentText();
	if (node_name.isEmpty())
		return;

	m_ui.FilterNodesListWidget->addItem(node_name);
	m_ui.FilterNodesListWidget->setCurrentRow(
		m_ui.FilterNodesListWidget->count() - 1);

	const int i = m_ui.FilterNodesNameComboBox->findText(node_name);
	if (i >= 0)
		m_ui.FilterNodesNameComboBox->removeItem(i);
	m_ui.FilterNodesNameComboBox->insertItem(0, node_name);
	m_ui.FilterNodesNameComboBox->setEditText(QString());

	m_ui.FilterNodesListWidget->setFocus();

	changedFilterNodes();
}


void qpwgraph_options::removeFilterNodes (void)
{
	const int i	= m_ui.FilterNodesListWidget->currentRow();
	if (i < 0)
		return;

	QListWidgetItem *item = m_ui.FilterNodesListWidget->takeItem(i);
	if (item)
		delete item;

	changedFilterNodes();
}


void qpwgraph_options::clearFilterNodes (void)
{
	m_ui.FilterNodesListWidget->clear();

	changedFilterNodes();
}


// Merger/unify list management...
//
void qpwgraph_options::changedMergerNodes (void)
{
	++m_dirty_merger;

	changed();
}


void qpwgraph_options::selectMergerNodes (void)
{
	QListWidgetItem *item = m_ui.MergerNodesListWidget->currentItem();
	if (item)
		m_ui.MergerNodesNameComboBox->setEditText(item->text());

	stabilize();
}


void qpwgraph_options::addMergerNodes (void)
{
	const QString& node_name
		= m_ui.MergerNodesNameComboBox->currentText();
	if (node_name.isEmpty())
		return;

	m_ui.MergerNodesListWidget->addItem(node_name);
	m_ui.MergerNodesListWidget->setCurrentRow(
		m_ui.MergerNodesListWidget->count() - 1);

	const int i = m_ui.MergerNodesNameComboBox->findText(node_name);
	if (i >= 0)
		m_ui.MergerNodesNameComboBox->removeItem(i);
	m_ui.MergerNodesNameComboBox->insertItem(0, node_name);
	m_ui.MergerNodesNameComboBox->setEditText(QString());

	m_ui.MergerNodesListWidget->setFocus();

	changedMergerNodes();
}


void qpwgraph_options::removeMergerNodes (void)
{
	const int i	= m_ui.MergerNodesListWidget->currentRow();
	if (i < 0)
		return;

	QListWidgetItem *item = m_ui.MergerNodesListWidget->takeItem(i);
	if (item)
		delete item;

	changedMergerNodes();
}


void qpwgraph_options::clearMergerNodes (void)
{
	m_ui.MergerNodesListWidget->clear();

	changedMergerNodes();
}


// Custom color palette theme manager.
void qpwgraph_options::editCustomColorThemes (void)
{
	qpwgraph_config *config = nullptr;
	qpwgraph_main *parent = qobject_cast<qpwgraph_main *> (parentWidget());
	if (parent)
		config = parent->config();
	if (config == nullptr)
		return;

	qpwgraph_palette form(this);
	form.setSettings(config->settings());

	QString color_theme;
	int color_dirty = 0;

	const int color_index
		= m_ui.CustomColorThemeComboBox->currentIndex();
	if (color_index > 0) {
		color_theme = m_ui.CustomColorThemeComboBox->itemText(color_index);
		form.setPaletteName(color_theme);
	}

	if (form.exec() == QDialog::Accepted) {
		color_theme = form.paletteName();
		++color_dirty;
	}

	if (color_dirty > 0 || form.isDirty()) {
		resetCustomColorThemes(color_theme);
		if (!color_theme.isEmpty()) {
			customColorThemeChanged(
				m_ui.CustomColorThemeComboBox->findText(color_theme));
		}
	}
}


void qpwgraph_options::customColorThemeChanged ( int color_index )
{
	qpwgraph_config *config = nullptr;
	qpwgraph_main *parent = qobject_cast<qpwgraph_main *> (parentWidget());
	if (parent)
		config = parent->config();
	if (config == nullptr)
		return;

	QString color_theme;
	if (color_index > 0)
		color_theme = m_ui.CustomColorThemeComboBox->currentText();
	else
		color_theme = config->customColorTheme();
	if (!color_theme.isEmpty()) {
		QPalette pal;
		if (qpwgraph_palette::namedPalette(
				config->settings(), color_theme, pal)) {
			m_ui.CustomPreviewFrame->setPalette(pal);
		}
	}

	changed();
}


void qpwgraph_options::customStyleThemeChanged ( int style_index )
{
	qpwgraph_config *config = nullptr;
	qpwgraph_main *parent = qobject_cast<qpwgraph_main *> (parentWidget());
	if (parent)
		config = parent->config();
	if (config == nullptr)
		return;

	QString style_theme;
	if (style_index > 0)
		style_theme = m_ui.CustomStyleThemeComboBox->currentText();
	else
		style_theme = config->customStyleTheme();
	if (!style_theme.isEmpty()) {
		if (m_style)
			delete m_style;
		m_style = QStyleFactory::create(style_theme);
		m_ui.CustomPreviewWidget->setStyle(m_style);
		const QList<QWidget *>& widgets
			= m_ui.CustomPreviewWidget->findChildren<QWidget *>();
		foreach (QWidget *widget, widgets)
			widget->setStyle(m_style);
	}

	changed();
}


// Custom color palette themes settler.
void qpwgraph_options::resetCustomColorThemes ( const QString& color_theme )
{
	m_ui.CustomColorThemeComboBox->clear();
	m_ui.CustomColorThemeComboBox->addItem(tr(DefaultName));
	qpwgraph_config *config = nullptr;
	qpwgraph_main *parent = qobject_cast<qpwgraph_main *> (parentWidget());
	if (parent)
		config = parent->config();
	if (config) m_ui.CustomColorThemeComboBox->addItems(
		qpwgraph_palette::namedPaletteList(config->settings()));

	int color_index = 0;
	if (!color_theme.isEmpty()) {
		color_index = m_ui.CustomColorThemeComboBox->findText(color_theme);
		if (color_index < 0)
			color_index = 0;
	}
	m_ui.CustomColorThemeComboBox->setCurrentIndex(color_index);
}


// Custom widget style themes settler.
void qpwgraph_options::resetCustomStyleThemes ( const QString& style_theme )
{
	m_ui.CustomStyleThemeComboBox->clear();
	m_ui.CustomStyleThemeComboBox->addItem(tr(DefaultName));
	m_ui.CustomStyleThemeComboBox->addItems(QStyleFactory::keys());

	int style_index = 0;
	if (!style_theme.isEmpty()) {
		style_index = m_ui.CustomStyleThemeComboBox->findText(style_theme);
		if (style_index < 0)
			style_index = 0;
	}
	m_ui.CustomStyleThemeComboBox->setCurrentIndex(style_index);
}


// Stabilize current form state.
void qpwgraph_options::stabilize (void)
{
#ifdef CONFIG_SYSTEM_TRAY
	const bool systray = m_ui.SystemTrayEnabledCheckBox->isChecked();
	m_ui.SystemTrayQueryCloseCheckBox->setEnabled(systray);
	m_ui.SystemTrayStartMinimizedCheckBox->setEnabled(systray);
#endif

	if (m_ui.FilterNodesEnabledCheckBox->isChecked()) {
		m_ui.FilterNodesNameComboBox->setEnabled(true);
		m_ui.FilterNodesListWidget->setEnabled(true);
		const QString& node_name
			= m_ui.FilterNodesNameComboBox->currentText();
		m_ui.FilterNodesAddToolButton->setEnabled(!node_name.isEmpty() &&
			m_ui.FilterNodesListWidget->findItems(node_name, Qt::MatchFixedString).isEmpty());
		const int i	= m_ui.FilterNodesListWidget->currentRow();
		m_ui.FilterNodesRemoveToolButton->setEnabled(i >= 0);
		m_ui.FilterNodesClearToolButton->setEnabled(
			m_ui.FilterNodesListWidget->count() > 0);
	} else {
		m_ui.FilterNodesNameComboBox->setEnabled(false);
		m_ui.FilterNodesListWidget->setEnabled(false);
		m_ui.FilterNodesAddToolButton->setEnabled(false);
		m_ui.FilterNodesRemoveToolButton->setEnabled(false);
		m_ui.FilterNodesClearToolButton->setEnabled(false);
	}

	if (m_ui.MergerNodesEnabledCheckBox->isChecked()) {
		m_ui.MergerNodesNameComboBox->setEnabled(true);
		m_ui.MergerNodesListWidget->setEnabled(true);
		const QString& node_name
			= m_ui.MergerNodesNameComboBox->currentText();
		m_ui.MergerNodesAddToolButton->setEnabled(!node_name.isEmpty() &&
			m_ui.MergerNodesListWidget->findItems(node_name, Qt::MatchFixedString).isEmpty());
		const int i	= m_ui.MergerNodesListWidget->currentRow();
		m_ui.MergerNodesRemoveToolButton->setEnabled(i >= 0);
		m_ui.MergerNodesClearToolButton->setEnabled(
			m_ui.MergerNodesListWidget->count() > 0);
	} else {
		m_ui.MergerNodesNameComboBox->setEnabled(false);
		m_ui.MergerNodesListWidget->setEnabled(false);
		m_ui.MergerNodesAddToolButton->setEnabled(false);
		m_ui.MergerNodesRemoveToolButton->setEnabled(false);
		m_ui.MergerNodesClearToolButton->setEnabled(false);
	}

	m_ui.DialogButtonBox->button(QDialogButtonBox::Ok)->setEnabled(m_dirty > 0);
}


// end of qpwgraph_options.cpp
