/*
 * Copyright (C) 2014-2022 CZ.NIC
 *
 * 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 <http://www.gnu.org/licenses/>.
 *
 * In addition, as a special exception, the copyright holders give
 * permission to link the code of portions of this program with the
 * OpenSSL library under certain conditions as described in each
 * individual source file, and distribute linked combinations including
 * the two.
 */

#include <climits>
#include <QInputDialog>
#include <QMessageBox>

#include "src/datovka_shared/graphics/colour.h"
#include "src/datovka_shared/io/prefs_db.h"
#include "src/datovka_shared/settings/prefs.h"
#include "src/gui/dlg_prefs.h"
#include "src/views/table_home_end_filter.h"
#include "src/views/table_tab_ignore_filter.h"
#include "ui_dlg_prefs.h"

#define STACKED_WARNING 0 /* Warning page. */
#define STACKED_PREFS_LIST 1 /* Preferences list. */

DlgPrefs::DlgPrefs(Prefs &prefs, QWidget *parent)
    : QDialog(parent),
    m_ui(new (::std::nothrow) Ui::DlgPrefs),
    m_prefListProxyModel(this),
    m_prefTableModel(prefs, this)
{
	m_ui->setupUi(this);

	/* Set default line height for table views/widgets. */
	m_ui->prefTableView->setNarrowedLineHeight();
	m_ui->prefTableView->horizontalHeader()->setDefaultAlignment(
	    Qt::AlignLeft);
//	m_ui->prefTableView->setSelectionMode(
//	    QAbstractItemView::ExtendedSelection);
	m_ui->prefTableView->setSelectionBehavior(
	    QAbstractItemView::SelectRows);

	m_prefListProxyModel.setSortRole(Qt::DisplayRole);
	m_prefListProxyModel.setSourceModel(&m_prefTableModel);
	{
		QList<int> columnList;
		columnList.append(PrefsModel::COL_NAME);
		columnList.append(PrefsModel::COL_VALUE);
		m_prefListProxyModel.setFilterKeyColumns(columnList);
	}
	m_ui->prefTableView->setModel(&m_prefListProxyModel);

	m_ui->prefTableView->sortByColumn(PrefsModel::COL_NAME, Qt::AscendingOrder);
	m_ui->prefTableView->setSortingEnabled(true);
	m_ui->prefTableView->resizeColumnsToContents();

	m_ui->filterLine->setToolTip(tr("Enter sought expression"));
	m_ui->filterLine->setClearButtonEnabled(true);

	connect(m_ui->warningAcceptButton, SIGNAL(clicked()),
	    this, SLOT(viewPrefsList()));

	connect(m_ui->filterLine, SIGNAL(textChanged(QString)),
	    this, SLOT(filterPrefs(QString)));
	connect(m_ui->prefTableView, SIGNAL(doubleClicked(QModelIndex)),
	    this, SLOT(prefItemDoubleClicked(QModelIndex)));

	m_ui->prefTableView->installEventFilter(
	    new (::std::nothrow) TableHomeEndFilter(m_ui->prefTableView));
	m_ui->prefTableView->installEventFilter(
	    new (::std::nothrow) TableTabIgnoreFilter(m_ui->prefTableView));
}

DlgPrefs::~DlgPrefs(void)
{
	delete m_ui;
}

void DlgPrefs::modify(Prefs &prefs, QWidget *parent)
{
	DlgPrefs dlg(prefs, parent);
	dlg.exec();
}

void DlgPrefs::viewPrefsList(void)
{
	m_ui->stackedWidget->setCurrentIndex(STACKED_PREFS_LIST);
}

void DlgPrefs::filterPrefs(const QString &text)
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
	m_prefListProxyModel.setFilterRegularExpression(
	    QRegularExpression(QRegularExpression::escape(text),
	        QRegularExpression::CaseInsensitiveOption));
#else /* < Qt-5.15 */
	m_prefListProxyModel.setFilterRegExp(QRegExp(text,
	    Qt::CaseInsensitive, QRegExp::FixedString));
#endif /* >= Qt-5.15 */
	/* Set filter field background colour. */
	if (text.isEmpty()) {
		m_ui->filterLine->setStyleSheet(
		    SortFilterProxyModel::blankFilterEditStyle);
	} else if (m_prefListProxyModel.rowCount() != 0) {
		m_ui->filterLine->setStyleSheet(
		    SortFilterProxyModel::foundFilterEditStyle);
	} else {
		m_ui->filterLine->setStyleSheet(
		    SortFilterProxyModel::notFoundFilterEditStyle);
	}
}

void DlgPrefs::prefItemDoubleClicked(const QModelIndex &index)
{
	const QModelIndex srcIdx(m_prefListProxyModel.mapToSource(index));

	if (srcIdx.isValid() && (srcIdx.column() == PrefsModel::COL_VALUE)) {
		int row = srcIdx.row();
		switch (m_prefTableModel.type(row)) {
		case PrefsDb::VAL_BOOLEAN:
			m_prefTableModel.alterBool(row);
			break;
		case PrefsDb::VAL_INTEGER:
			{
				bool iOk = false;
				int val = m_prefTableModel.data(srcIdx).toString().toInt();
				int newVal = QInputDialog::getInt(this, tr("Enter a Value"),
				    m_prefTableModel.data(srcIdx.sibling(row, PrefsModel::COL_NAME)).toString(),
				    val, INT_MIN, INT_MAX, 1, &iOk);
				if (iOk && (val != newVal)) {
					m_prefTableModel.modifyInt(row, newVal);
				}
			}
			break;
		case PrefsDb::VAL_FLOAT:
			{
				bool iOk = false;
				double val = m_prefTableModel.data(srcIdx).toString().toDouble();
				double newVal = QInputDialog::getDouble(this, tr("Enter a Value"),
				    m_prefTableModel.data(srcIdx.sibling(row, PrefsModel::COL_NAME)).toString(),
				    val, INT_MIN, INT_MAX, 3, &iOk);
				if (iOk && (val != newVal)) {
					m_prefTableModel.modifyFloat(row, newVal);
				}
			}
			break;
		case PrefsDb::VAL_STRING:
			{
				bool iOk = false;
				QString val = m_prefTableModel.data(srcIdx).toString();
				QString newVal = QInputDialog::getText(this, tr("Enter a Value"),
				    m_prefTableModel.data(srcIdx.sibling(row, PrefsModel::COL_NAME)).toString(),
				    QLineEdit::Normal, val, &iOk);
				if (iOk && (val != newVal)) {
					m_prefTableModel.modifyString(row, newVal);
				}
			}
			break;
		case PrefsDb::VAL_COLOUR:
			{
				bool iOk = false;
				QString val = m_prefTableModel.data(srcIdx).toString();
				QString newVal = QInputDialog::getText(this, tr("Enter a Value"),
				    m_prefTableModel.data(srcIdx.sibling(row, PrefsModel::COL_NAME)).toString(),
				    QLineEdit::Normal, val, &iOk);
				if (iOk && (val != newVal)) {
					if (Colour::isValidColourStr(newVal)) {
						m_prefTableModel.modifyColour(row, newVal);
					} else {
						QMessageBox::warning(this, tr("Value Error"),
						    tr("Entered invalid value."),
						    QMessageBox::Ok);
					}
				}
			}
			break;
		case PrefsDb::VAL_DATETIME:
			{
				bool iOk = false;
				QString valStr = m_prefTableModel.data(srcIdx).toString();
				QString newValStr = QInputDialog::getText(this, tr("Enter a Value"),
				    m_prefTableModel.data(srcIdx.sibling(row, PrefsModel::COL_NAME)).toString(),
				    QLineEdit::Normal, valStr, &iOk);
				if (iOk && (valStr != newValStr)) {
					QDateTime newVal = PrefsDb::stringToDateTime(newValStr);
					if (newVal.isValid()) {
						m_prefTableModel.modifyDateTime(row, newVal);
					} else {
						QMessageBox::warning(this, tr("Value Error"),
						    tr("Entered invalid value."),
						    QMessageBox::Ok);
					}
				}
			}
			break;
		case PrefsDb::VAL_DATE:
			{
				bool iOk = false;
				QString valStr = m_prefTableModel.data(srcIdx).toString();
				QString newValStr = QInputDialog::getText(this, tr("Enter a Value"),
				    m_prefTableModel.data(srcIdx.sibling(row, PrefsModel::COL_NAME)).toString(),
				    QLineEdit::Normal, valStr, &iOk);
				if (iOk && (valStr != newValStr)) {
					QDate newVal = QDate::fromString(newValStr, Qt::ISODate);
					if (newVal.isValid()) {
						m_prefTableModel.modifyDate(row, newVal);
					} else {
						QMessageBox::warning(this, tr("Value Error"),
						    tr("Entered invalid value."),
						    QMessageBox::Ok);
					}
				}
			}
			break;
		default:
			break;
		}
	}
}
