/*
 * Copyright (C) 2014-2021 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 <QDir>
#include <Qt> /* enum Qt::ToolButtonStyle */

#include "src/datovka_shared/identifiers/account_id.h"
#include "src/datovka_shared/log/log.h"
#include "src/datovka_shared/settings/prefs.h"
#include "src/datovka_shared/settings/prefs_helper.h"
#include "src/settings/prefs_specific.h"
#include "src/settings/registry.h"

bool PrefsSpecific::messageDbOnDisk(const Prefs &prefs)
{
	bool val = false;
	return prefs.boolVal("storage.database.messages.on_disk.enabled",
	    val) && val;
}

bool PrefsSpecific::accountDbOnDisk(const Prefs &prefs)
{
	bool val = false;
	return prefs.boolVal("storage.database.accounts.on_disk.enabled",
	    val) && val;
}

bool PrefsSpecific::backgroundSync(const Prefs &prefs)
{
	bool val = false;
	return prefs.boolVal(
	    "window.main.action.sync_all_accounts.background.enabled", val) && val;
}

int PrefsSpecific::backgroundSyncTimerMinutes(const Prefs &prefs)
{
	qint64 val = 10;
	if (Q_UNLIKELY(!prefs.intVal(
	        "window.main.action.sync_all_accounts.background.timer.period.minutes",
	        val))) {
		Q_ASSERT(0);
		return 10;
	}
	return val;
}

void PrefsSpecific::setBackgroundSyncTimerMinutes(Prefs &prefs, int val)
{
	if (val < 5) {
		val = 5;
	}
	prefs.setIntVal(
	    "window.main.action.sync_all_accounts.background.timer.period.minutes",
	    val);
}

int PrefsSpecific::shadowSyncTimerMinutes(const Prefs &prefs)
{
	qint64 val = 10;
	if (Q_UNLIKELY(!prefs.intVal(
	        "window.main.action.shadow_sync_all_accounts.background.timer.period.minutes",
	        val))) {
		Q_ASSERT(0);
		return 10;
	}
	return val;
}

void PrefsSpecific::setShadowSyncTimerMinutes(Prefs &prefs, int val)
{
	if (val < 5) {
		val = 5;
	}
	prefs.setIntVal(
	    "window.main.action.shadow_sync_all_accounts.background.timer.period.minutes",
	    val);
}

bool PrefsSpecific::checkNewVersionsDefault(void)
{
#ifdef DISABLE_VERSION_CHECK_BY_DEFAULT
	return false;
#else /* !DISABLE_VERSION_CHECK_BY_DEFAULT */
	return true;
#endif /* DISABLE_VERSION_CHECK_BY_DEFAULT */
}

bool PrefsSpecific::canConfigureCheckNewVersions(void)
{
#if defined(DISABLE_VERSION_NOTIFICATION)
	return false;
#elif defined(Q_OS_WIN) /* !DISABLE_VERSION_NOTIFICATION */
	/* Registry settings can override the default behaviour. */
	return !(
	    RegPreferences::haveEntry(RegPreferences::LOC_POL,
	        RegPreferences::ENTR_DISABLE_VER_NOTIF) ||
	    RegPreferences::haveEntry(RegPreferences::LOC_SYS,
	        RegPreferences::ENTR_DISABLE_VER_NOTIF) ||
	    RegPreferences::haveEntry(RegPreferences::LOC_USR,
	        RegPreferences::ENTR_DISABLE_VER_NOTIF));
#else /* !Q_OS_WIN */
	return true;
#endif /* Q_OS_WIN */
}

bool PrefsSpecific::checkNewVersions(const Prefs &prefs)
{
	if (canConfigureCheckNewVersions()) {
		bool val = false;
		return prefs.boolVal(
		    "application.version.check.enabled", val) && val;
	} else {
#if defined(DISABLE_VERSION_NOTIFICATION)
		logInfoNL("%s",
		    "Version notification disabled at compile time.");
		return false;
#elif defined(Q_OS_WIN) /* !DISABLE_VERSION_NOTIFICATION */
		if (RegPreferences::haveEntry(RegPreferences::LOC_POL,
		        RegPreferences::ENTR_DISABLE_VER_NOTIF)) {
			return !RegPreferences::disableVersionNotification(
			    RegPreferences::LOC_POL);
		} else if (RegPreferences::haveEntry(RegPreferences::LOC_SYS,
		        RegPreferences::ENTR_DISABLE_VER_NOTIF)) {
			return !RegPreferences::disableVersionNotification(
			    RegPreferences::LOC_SYS);
		} else if (RegPreferences::haveEntry(RegPreferences::LOC_USR,
		        RegPreferences::ENTR_DISABLE_VER_NOTIF)) {
			return !RegPreferences::disableVersionNotification(
			    RegPreferences::LOC_USR);
		} else {
			/*
			 * The value could be deleted manually in between
			 * the calls.
			 */
			return checkNewVersionsDefault();
		}
#else /* !Q_OS_WIN */
		return checkNewVersionsDefault();
#endif /* Q_OS_WIN */
	}
}

void PrefsSpecific::setCheckNewVersions(Prefs &prefs, bool val)
{
	prefs.setBoolVal("application.version.check.enabled", val);
}

bool PrefsSpecific::sendStatsWithVersionChecks(const Prefs &prefs)
{
	bool val = false;
	return prefs.boolVal(
	    "application.version.check.stats.send.enabled", val) && val;
}

void PrefsSpecific::setSendStatsWithVersionChecks(Prefs &prefs, bool val)
{
	prefs.setBoolVal("application.version.check.stats.send.enabled", val);
}

int PrefsSpecific::checkNewVersionsCooldown(const Prefs &prefs)
{
	qint64 val = 14400;
	if (Q_UNLIKELY(!prefs.intVal(
	        "application.version.check.timeout.seconds",
	        val))) {
		Q_ASSERT(0);
		return 14400;
	}
	return val;
}

void PrefsSpecific::setCheckNewVersionsCooldown(Prefs &prefs, int val)
{
	if (val < 0) {
		val = 0;
	}
	prefs.setIntVal("application.version.check.timeout.seconds", val);
}

bool PrefsSpecific::canAutoDownloadUpdate(const Prefs &prefs)
{
	bool val = false;
	return prefs.boolVal(
	    "application.update.automatic_download.enabled", val) && val;
}

void PrefsSpecific::setCanAutoDownloadUpdate(Prefs &prefs, bool val)
{
	prefs.setBoolVal("application.update.automatic_download.enabled", val);
}

int PrefsSpecific::autoDownloadUpdateAttemptMax(const Prefs &prefs)
{
	qint64 val = 2;
	if (Q_UNLIKELY(!prefs.intVal(
	        "application.update.automatic_download.attempt.max",
	        val))) {
		Q_ASSERT(0);
		return 2;
	}
	return val;
}

void PrefsSpecific::setAutoDownloadUpdateAttemptMax(Prefs &prefs, int val)
{
	if (val <= 0) {
		val = 0;
	}
	prefs.setIntVal("application.update.automatic_download.attempt.max", val);
}

QString PrefsSpecific::downloadedPkgVersion(const Prefs &prefs)
{
	QString val;
	prefs.strVal("application.update.downloaded_package.version", val);
	/* Has default value set. */
	return val;
}

void PrefsSpecific::setDownloadedPkgVersion(Prefs &prefs, const QString &val)
{
	prefs.setStrVal("application.update.downloaded_package.version", val);
}

QString PrefsSpecific::downloadedPkgSha256Sum(const Prefs &prefs)
{
	QString val;
	prefs.strVal("application.update.downloaded_package.sha256sum", val);
	/* Has default value set. */
	return val;
}

void PrefsSpecific::setDownloadedPkgSha256Sum(Prefs &prefs, const QString &val)
{
	prefs.setStrVal("application.update.downloaded_package.sha256sum", val);
}

QString PrefsSpecific::downloadedPkgPath(const Prefs &prefs)
{
	QString val;
	prefs.strVal("application.update.downloaded_package.path", val);
	/* Has default value set. */
	return val;
}

void PrefsSpecific::setDownloadedPkgPath(Prefs &prefs, const QString &val)
{
	prefs.setStrVal("application.update.downloaded_package.path", val);
}

int PrefsSpecific::isdsDownloadTimeoutMs(const Prefs &prefs)
{
	qint64 val = 0;
	if (Q_UNLIKELY(!prefs.intVal("network.isds.communication.timeout.ms",
	        val))) {
		Q_ASSERT(0);
		return 600000;
	}
	return val;
}

enum PrefsSpecific::CertValDate PrefsSpecific::certValDate(const Prefs &prefs)
{
	qint64 val = DOWNLOAD_DATE;
	if (Q_UNLIKELY(!prefs.intVal("crypto.message.validation.date.type",
	        val))) {
		Q_ASSERT(0);
		return DOWNLOAD_DATE;
	}
	switch (val) {
	case DOWNLOAD_DATE:
		return DOWNLOAD_DATE;
		break;
	case CURRENT_DATE:
		return CURRENT_DATE;
		break;
	default:
		Q_ASSERT(0);
		return DOWNLOAD_DATE;
		break;
	}
}

bool PrefsSpecific::checkCrl(const Prefs &prefs)
{
	bool val = false;
	return prefs.boolVal("crypto.crl.check.enabled", val) && val;
}

bool PrefsSpecific::useGlobalPaths(const Prefs &prefs)
{
	bool val = false;
	return prefs.boolVal("global.path.enabled", val) && val;
}

void PrefsSpecific::setUseGlobalPaths(Prefs &prefs, bool val)
{
	prefs.setBoolVal("global.path.enabled", val);
}

int PrefsSpecific::qtToolButtonStyle(int style)
{
	switch (style) {
	case ICON_ONLY:
		return Qt::ToolButtonIconOnly;
		break;
	case TEXT_BESIDE_ICON:
		return Qt::ToolButtonTextBesideIcon;
		break;
	case TEXT_UNDER_ICON:
		return Qt::ToolButtonTextUnderIcon;
		break;
	default:
		Q_ASSERT(0);
		return Qt::ToolButtonTextUnderIcon; /* Default. */
		break;
	}
}

bool PrefsSpecific::recMgmtAutoUpload(const Prefs &prefs)
{
	bool val = false;
	return prefs.boolVal("records_management.action.automatic_upload.enabled", val) && val;
}

void PrefsSpecific::setRecMgmtAutoUpload(Prefs &prefs, bool val)
{
	prefs.setBoolVal("records_management.action.automatic_upload.enabled", val);
}

bool PrefsSpecific::recMgmtAutoAcntStatusUpload(const Prefs &prefs)
{
	bool val = true;
	return prefs.boolVal("records_management.action.automatic_account_status_upload.enabled", val) && val;
}

QString PrefsSpecific::saveAttachDir(const Prefs &prefs)
{
	QString val;
	prefs.strVal("global.path.save.attachment", val);
	/* Has default value set. */
	return val;
}

void PrefsSpecific::setSaveAttachDir(Prefs &prefs, const QString &val)
{
	prefs.setStrVal("global.path.save.attachment", val);
}

QString PrefsSpecific::loadAttachDir(const Prefs &prefs)
{
	QString val;
	prefs.strVal("global.path.load.attachment", val);
	/* Has default value set. */
	return val;
}

void PrefsSpecific::setLoadAttachDir(Prefs &prefs, const QString &val)
{
	prefs.setStrVal("global.path.load.attachment", val);
}

QString PrefsSpecific::viewZfoDir(const Prefs &prefs)
{
	QString val;
	prefs.strVal("global.path.load.zfo", val);
	if (val.isEmpty()) {
		val = QDir::homePath();
	}
	return val;
}

void PrefsSpecific::setViewZfoDir(Prefs &prefs, const QString &val)
{
	prefs.setStrVal("global.path.load.zfo", val);
}

QString PrefsSpecific::importDbDir(const Prefs &prefs)
{
	QString val;
	prefs.strVal("global.path.import.database", val);
	if (val.isEmpty()) {
		val = QDir::homePath();
	}
	return val;
}

void PrefsSpecific::setImportDbDir(Prefs &prefs, const QString &val)
{
	prefs.setStrVal("global.path.import.database", val);
}

QString PrefsSpecific::importDbZfo(const Prefs &prefs)
{
	QString val;
	prefs.strVal("global.path.import.zfo", val);
	if (val.isEmpty()) {
		val = QDir::homePath();
	}
	return val;
}

void PrefsSpecific::setImportDbZfo(Prefs &prefs, const QString &val)
{
	prefs.setStrVal("global.path.import.zfo", val);
}

/*!
 * @brief Get account-related string entry.
 *
 * @param[in] prefs Preferences.
 * @param[in] acntId Account identifier.
 * @param[in] suff Suffix of the key.
 * @param[in] dflt Default value if no entry found.
 * @return String entry, null string on error.
 */
static
QString acntStrEntry(const Prefs &prefs, const AcntId &acntId,
    const QString &suff, const QString &dflt)
{
	if (Q_UNLIKELY((!acntId.isValid()) || suff.isEmpty())) {
		Q_ASSERT(0);
		return QString();
	}

	QString val;
	const QString accountId = PrefsHelper::accountIdentifier(
	    acntId.username(), acntId.testing());
	/* key = "account." + accountId + suff */
	prefs.strVal("account." + accountId + suff, val);
	if (val.isEmpty()) {
		val = dflt;
	}
	return val;
}

/*!
 * @brief Set account-related string entry.
 *
 * @param[in,out] prefs Preferences.
 * @param[in] acntId Account identifier.
 * @param[in] suff Suffix of the key.
 * @param[in] val Value to be set.
 */
static
void setAcntStrEntry(Prefs &prefs, const AcntId &acntId,
    const QString &suff, const QString &val)
{
	if (Q_UNLIKELY((!acntId.isValid()) || suff.isEmpty())) {
		Q_ASSERT(0);
		return;
	}

	const QString accountId = PrefsHelper::accountIdentifier(
	    acntId.username(), acntId.testing());
	prefs.setStrVal("account." + accountId + suff, val);
}

QString PrefsSpecific::acntSaveAttachDir(const Prefs &prefs,
    const AcntId &acntId)
{
	return acntStrEntry(prefs, acntId, ".last.path.save.attachment",
	    QDir::homePath());
}

void PrefsSpecific::setAcntSaveAttachDir(Prefs &prefs, const AcntId &acntId,
    const QString &val)
{
	setAcntStrEntry(prefs, acntId, ".last.path.save.attachment", val);
}

QString PrefsSpecific::anctLoadAttachDir(const Prefs &prefs,
    const AcntId &acntId)
{
	return acntStrEntry(prefs, acntId, ".last.path.load.attachment",
	    QDir::homePath());
}

void PrefsSpecific::setAnctLoadAttachDir(Prefs &prefs, const AcntId &acntId,
    const QString &val)
{
	setAcntStrEntry(prefs, acntId, ".last.path.load.attachment", val);
}

QString PrefsSpecific::acntCorrespondenceDir(const Prefs &prefs,
    const AcntId &acntId)
{
	return acntStrEntry(prefs, acntId,
	    ".last.path.save.correspondence_overview", QDir::homePath());
}

void PrefsSpecific::setAcntCorrespondenceDir(Prefs &prefs, const AcntId &acntId,
    const QString &val)
{
	setAcntStrEntry(prefs, acntId,
	    ".last.path.save.correspondence_overview", val);
}

QString PrefsSpecific::acntZfoDir(const Prefs &prefs, const AcntId &acntId)
{
	return acntStrEntry(prefs, acntId, ".last.path.save.zfo",
	    QDir::homePath());
}

void PrefsSpecific::setAcntZfoDir(Prefs &prefs, const AcntId &acntId,
    const QString &val)
{
	setAcntStrEntry(prefs, acntId, ".last.path.save.zfo", val);
}

bool PrefsSpecific::showPdzNotification(const Prefs &prefs)
{
	bool val = true;
	return prefs.boolVal("window.create_message.notification.send_pdz.enabled", val) && val;
}

void PrefsSpecific::setShowPdzNotification(Prefs &prefs, bool val)
{
	prefs.setBoolVal("window.create_message.notification.send_pdz.enabled", val);
}

bool PrefsSpecific::showUpdateQuitAppNotification(const Prefs &prefs)
{
	bool val = true;
	return prefs.boolVal("window.about.notification.update.quit_app.enabled", val) && val;
}

void PrefsSpecific::setShowUpdateQuitAppNotification(Prefs &prefs, bool val)
{
	prefs.setBoolVal("window.about.notification.update.quit_app.enabled", val);
}

int PrefsSpecific::sentMsgDownloadWaitIntervalMs(const Prefs &prefs)
{
	qint64 val = 5000;
	if (Q_UNLIKELY(!prefs.intVal(
	        "action.send_message.tie.action.download_message.timeout.ms", val))) {
		Q_ASSERT(0);
		return 5000;
	}
	return val;
}
