/*
 * Cantata
 *
 * Copyright (c) 2011-2022 Craig Drummond <craig.p.drummond@gmail.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; 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; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "settings.h"
#include "db/librarydb.h"
#include "models/sqllibrarymodel.h"
#include "mpd-interface/mpdparseutils.h"
#include "support/fancytabwidget.h"
#include "support/globalstatic.h"
#include "support/utils.h"
#include "widgets/itemview.h"
#include <QDir>
#include <QFile>
#include <qglobal.h>

GLOBAL_STATIC(Settings, instance)

struct MpdDefaults {
	MpdDefaults()
		: host("localhost"), dir("/var/lib/mpd/music/"), port(6600)
	{
	}

	static QString getVal(const QString& line)
	{
		QStringList parts = line.split('\"');
		return parts.count() > 1 ? parts[1] : QString();
	}

	enum Details {
		DT_DIR = 0x01,
		DT_ADDR = 0x02,
		DT_PORT = 0x04,
		DT_PASSWD = 0x08,

		DT_ALL = DT_DIR | DT_ADDR | DT_PORT | DT_PASSWD
	};

	void read()
	{
		QFile f("/etc/mpd.conf");

		if (f.open(QIODevice::ReadOnly | QIODevice::Text)) {
			int details = 0;
			while (!f.atEnd()) {
				QString line = QString::fromUtf8(f.readLine()).trimmed();
				if (line.startsWith('#')) {
					continue;
				}
				else if (!(details & DT_DIR) && line.startsWith(QLatin1String("music_directory"))) {
					QString val = getVal(line);
					if (!val.isEmpty() && QDir(val).exists()) {
						dir = Utils::fixPath(val);
						details |= DT_DIR;
					}
				}
				else if (!(details & DT_ADDR) && line.startsWith(QLatin1String("bind_to_address"))) {
					QString val = getVal(line);
					if (!val.isEmpty() && val != QLatin1String("any")) {
						host = val;
						details |= DT_ADDR;
					}
				}
				else if (!(details & DT_PORT) && line.startsWith(QLatin1String("port"))) {
					int val = getVal(line).toInt();
					if (val > 0) {
						port = val;
						details |= DT_PORT;
					}
				}
				else if (!(details & DT_PASSWD) && line.startsWith(QLatin1String("password"))) {
					QString val = getVal(line);
					if (!val.isEmpty()) {
						QStringList parts = val.split('@');
						if (!parts.isEmpty()) {
							passwd = parts[0];
							details |= DT_PASSWD;
						}
					}
				}
				if (details == DT_ALL) {
					break;
				}
			}
		}
	}

	QString host;
	QString dir;
	QString passwd;
	int port;
};

static MpdDefaults mpdDefaults;

static QString getStartupStateStr(Settings::StartupState s)
{
	switch (s) {
	case Settings::SS_ShowMainWindow: return QLatin1String("show");
	case Settings::SS_HideMainWindow: return QLatin1String("hide");
	default:
	case Settings::SS_Previous: return QLatin1String("prev");
	}
}

static Settings::StartupState getStartupState(const QString& str)
{
	for (int i = 0; i <= Settings::SS_Previous; ++i) {
		if (getStartupStateStr((Settings::StartupState)i) == str) {
			return (Settings::StartupState)i;
		}
	}
	return Settings::SS_Previous;
}

Settings::Settings()
	: state(AP_Configured), ver(-1)
{
	// Call 'version' so that it initialises 'ver' and 'state'
	version();
	// Only need to read system defaults if we have not previously been configured...
	if (!cfg.hasGroup(MPDConnectionDetails::configGroupName())) {
		mpdDefaults.read();
	}
}

Settings::~Settings()
{
	save();
}

QString Settings::currentConnection()
{
	return cfg.get("currentConnection", QString());
}

MPDConnectionDetails Settings::connectionDetails(const QString& name)
{
	MPDConnectionDetails details;
	QString n = MPDConnectionDetails::configGroupName(name);
	details.name = name;
	if (!cfg.hasGroup(n)) {
		details.name = QString();
		n = MPDConnectionDetails::configGroupName(details.name);
	}
	if (cfg.hasGroup(n)) {
		Configuration grp(n);
		details.hostname = grp.get("host", name.isEmpty() ? mpdDefaults.host : QString());
		details.port = grp.get("port", name.isEmpty() ? mpdDefaults.port : 6600);
		details.dir = grp.getDirPath("dir", name.isEmpty() ? mpdDefaults.dir : "/var/lib/mpd/music");
		details.password = grp.get("passwd", name.isEmpty() ? mpdDefaults.passwd : QString());
		details.partition = grp.get("partition", QString());
#ifdef ENABLE_HTTP_STREAM_PLAYBACK
		details.streamUrl = grp.get("streamUrl", QString());
#endif
		details.replayGain = grp.get("replayGain", QString());
		details.applyReplayGain = grp.get("applyReplayGain", true);
		// if the setting hasn't been set before, we set it to true to allow
		// for easy migration of existing settings
		details.allowLocalStreaming = grp.get("allowLocalStreaming", true);
		details.autoUpdate = grp.get("autoUpdate", false);
	}
	else {
		details.hostname = mpdDefaults.host;
		details.port = mpdDefaults.port;
		details.dir = mpdDefaults.dir;
		details.password = mpdDefaults.passwd;
#ifdef ENABLE_HTTP_STREAM_PLAYBACK
		details.streamUrl = QString();
#endif
		details.applyReplayGain = true;
		details.allowLocalStreaming = true;
		details.autoUpdate = false;
	}
	details.setDirReadable();
	return details;
}

QList<MPDConnectionDetails> Settings::allConnections()
{
	QStringList groups = cfg.childGroups();
	QList<MPDConnectionDetails> connections;
	for (const QString& grp : groups) {
		if (cfg.hasGroup(grp) && grp.startsWith("Connection")) {
			connections.append(connectionDetails(grp == "Connection" ? QString() : grp.mid(11)));
		}
	}

	if (connections.isEmpty()) {
		// If we are empty, add at lease the default connection...
		connections.append(connectionDetails());
	}
	return connections;
}

bool Settings::showPlaylist()
{
	return cfg.get("showPlaylist", true);
}

bool Settings::showFullScreen()
{
	return cfg.get("showFullScreen", false);
}

QByteArray Settings::headerState(const QString& key)
{
	if (version() < CANTATA_MAKE_VERSION(1, 2, 54)) {
		return QByteArray();
	}
	return cfg.get(key + "HeaderState", QByteArray());
}

QByteArray Settings::splitterState()
{
	return cfg.get("splitterState", QByteArray());
}

bool Settings::splitterAutoHide()
{
	return cfg.get("splitterAutoHide", false);
}

QSize Settings::mainWindowSize()
{
	return cfg.get("mainWindowSize", QSize());
}

QSize Settings::mainWindowCollapsedSize()
{
	return cfg.get("mainWindowCollapsedSize", QSize());
}

QPoint Settings::mainWindowPos()
{
	return cfg.get("mainWindowPos", QPoint());
}

bool Settings::maximized()
{
	return cfg.get("maximized", false);
}

bool Settings::useSystemTray()
{
	return cfg.get("useSystemTray", false);
}

bool Settings::minimiseOnClose()
{
	return cfg.get("minimiseOnClose", true);
}

bool Settings::showPopups()
{
	return cfg.get("showPopups", false);
}

bool Settings::stopOnExit()
{
	return cfg.get("stopOnExit", false);
}

bool Settings::storeCoversInMpdDir()
{
	return cfg.get("storeCoversInMpdDir", false);
}

bool Settings::storeLyricsInMpdDir()
{
	return cfg.get("storeLyricsInMpdDir", false);
}

QString Settings::coverFilename()
{
	QString name = cfg.get("coverFilename", QString());
	// name is empty, so for old configs try to get from MPD settings
	if (name.isEmpty() && version() < CANTATA_MAKE_VERSION(2, 2, 51)) {
		QStringList groups = cfg.childGroups();
		QList<MPDConnectionDetails> connections;
		for (const QString& grp : groups) {
			if (cfg.hasGroup(grp) && grp.startsWith("Connection")) {
				Configuration cfg(grp);
				name = cfg.get("coverName", QString());
				if (!name.isEmpty()) {
					// Use 1st non-empty
					saveCoverFilename(name);
					return name;
				}
			}
		}
	}
	return name;
}

int Settings::sidebar()
{
	if (version() < CANTATA_MAKE_VERSION(1, 2, 52)) {
		return (int)(FancyTabWidget::Side | FancyTabWidget::Large);
	}
	else {
		return cfg.get("sidebar", (int)(FancyTabWidget::Side | FancyTabWidget::Large)) & FancyTabWidget::All_Mask;
	}
}

QSet<QString> Settings::composerGenres()
{
	return Utils::listToSet(cfg.get("composerGenres", Song::composerGenres().values()));
}

QSet<QString> Settings::singleTracksFolders()
{
	return Utils::listToSet(cfg.get("singleTracksFolders", QStringList()));
}

MPDParseUtils::CueSupport Settings::cueSupport()
{
	return MPDParseUtils::toCueSupport(cfg.get("cueSupport", MPDParseUtils::toStr(MPDParseUtils::Cue_Ignore)));
}

QStringList Settings::lyricProviders()
{
	return cfg.get("lyricProviders", QStringList() << "azlyrics.com"
	                                               << "chartlyrics.com"
	                                               << "lyrics.wikia.com");
}

QStringList Settings::wikipediaLangs()
{
	return cfg.get("wikipediaLangs", QStringList() << "en:en");
}

bool Settings::wikipediaIntroOnly()
{
	return cfg.get("wikipediaIntroOnly", true);
}

int Settings::contextBackdrop()
{
	return getBoolAsInt("contextBackdrop", 0);
}

int Settings::contextBackdropOpacity()
{
	return cfg.get("contextBackdropOpacity", 15, 0, 100);
}

int Settings::contextBackdropBlur()
{
	return cfg.get("contextBackdropBlur", 0, 0, 20);
}

QString Settings::contextBackdropFile()
{
	return cfg.getFilePath("contextBackdropFile", QString());
}

bool Settings::contextDarkBackground()
{
	return cfg.get("contextDarkBackground", false);
}

int Settings::contextZoom()
{
	return cfg.get("contextZoom", 0);
}

QString Settings::contextSlimPage()
{
	return cfg.get("contextSlimPage", QString());
}

QByteArray Settings::contextSplitterState()
{
	return version() < CANTATA_MAKE_VERSION(1, 3, 51) ? QByteArray() : cfg.get("contextSplitterState", QByteArray());
}

bool Settings::contextAlwaysCollapsed()
{
	return cfg.get("contextAlwaysCollapsed", false);
}

int Settings::contextSwitchTime()
{
	return cfg.get("contextSwitchTime", 0, 0, 5000);
}

bool Settings::contextAutoScroll()
{
	return cfg.get("contextAutoScroll", false);
}

int Settings::contextTrackView()
{
	return cfg.get("contextTrackView", 0);
}

QString Settings::page()
{
	return cfg.get("page", QString());
}

QStringList Settings::hiddenPages()
{
	QStringList config = cfg.get("hiddenPages", QStringList() << "PlayQueuePage"
	                                                          << "ContextPage");
	// If splitter auto-hide is enabled, then playqueue cannot be in sidebar!
	if (splitterAutoHide() && !config.contains("PlayQueuePage")) {
		config << "PlayQueuePage";
	}
	return config;
}

#ifdef ENABLE_DEVICES_SUPPORT
bool Settings::overwriteSongs()
{
	return cfg.get("overwriteSongs", false);
}

bool Settings::showDeleteAction()
{
	return cfg.get("showDeleteAction", false);
}
#endif

int Settings::version()
{
	if (-1 == ver) {
		state = cfg.hasEntry("version") ? AP_Configured : AP_FirstRun;
		QStringList parts = cfg.get("version", QLatin1String(PACKAGE_VERSION_STRING)).split('.');
		if (3 == parts.size()) {
			ver = CANTATA_MAKE_VERSION(parts.at(0).toInt(), parts.at(1).toInt(), parts.at(2).toInt());
		}
		else {
			ver = PACKAGE_VERSION;
			cfg.set("version", PACKAGE_VERSION_STRING);
		}
	}
	return ver;
}

int Settings::stopFadeDuration()
{
	return cfg.get("stopFadeDuration", (int)MPDConnection::DefaultFade, (int)MPDConnection::MinFade, (int)MPDConnection::MaxFade);
}

int Settings::prevSeekDuration()
{
	return cfg.get("prevSeekDuration", 0, 0, INT_MAX);
}

int Settings::httpAllocatedPort()
{
	return cfg.get("httpAllocatedPort", 0);
}

QString Settings::httpInterface()
{
	return cfg.get("httpInterface", QString());
}

int Settings::playQueueView()
{
	if (version() < CANTATA_MAKE_VERSION(1, 3, 53)) {
		return cfg.get("playQueueGrouped", true) ? ItemView::Mode_GroupedTree : ItemView::Mode_Table;
	}
	return ItemView::toMode(cfg.get("playQueueView", ItemView::modeStr(ItemView::Mode_GroupedTree)));
}

bool Settings::playQueueAutoExpand()
{
	return cfg.get("playQueueAutoExpand", true);
}

bool Settings::playQueueStartClosed()
{
	return cfg.get("playQueueStartClosed", false);
}

bool Settings::playQueueScroll()
{
	return cfg.get("playQueueScroll", true);
}

int Settings::playQueueBackground()
{
	return getBoolAsInt("playQueueBackground", 0);
}

int Settings::playQueueBackgroundOpacity()
{
	return cfg.get("playQueueBackgroundOpacity", 15, 0, 100);
}

int Settings::playQueueBackgroundBlur()
{
	return cfg.get("playQueueBackgroundBlur", 0, 0, 20);
}

QString Settings::playQueueBackgroundFile()
{
	return cfg.getFilePath("playQueueBackgroundFile", QString());
}

bool Settings::playQueueConfirmClear()
{
	return cfg.get("playQueueConfirmClear", false);
}

bool Settings::playQueueSearch()
{
	return cfg.get("playQueueSearch", true);
}

bool Settings::playQueueSimpleSort()
{
	return cfg.get("playQueueSimpleSort", false);
}

bool Settings::playListsStartClosed()
{
	return cfg.get("playListsStartClosed", true);
}

#ifdef ENABLE_HTTP_STREAM_PLAYBACK
bool Settings::playStream()
{
	return cfg.get("playStream", false);
}
#endif

#if defined CDDB_FOUND || defined MusicBrainz5_FOUND
bool Settings::cdAuto()
{
	return cfg.get("cdAuto", true);
}

bool Settings::paranoiaFull()
{
	return cfg.get("paranoiaFull", true);
}

bool Settings::paranoiaNeverSkip()
{
	return cfg.get("paranoiaNeverSkip", true);
}

int Settings::paranoiaOffset()
{
	return cfg.get("paranoiaOffset", 0);
}
#endif

#if defined CDDB_FOUND && defined MusicBrainz5_FOUND
bool Settings::useCddb()
{
	return cfg.get("useCddb", true);
}
#endif

#ifdef CDDB_FOUND
QString Settings::cddbHost()
{
	return cfg.get("cddbHost", QString("gnudb.gnudb.org"));
}

int Settings::cddbPort()
{
	return cfg.get("cddbPort", 80);
}
#endif

bool Settings::forceSingleClick()
{
	return cfg.get("forceSingleClick", true);
}

bool Settings::startHidden()
{
	return useSystemTray() ? cfg.get("startHidden", false) : false;
}

bool Settings::showTimeRemaining()
{
	return cfg.get("showTimeRemaining", false);
}

QStringList Settings::hiddenStreamCategories()
{
	return cfg.get("hiddenStreamCategories", QStringList());
}

QStringList Settings::hiddenOnlineProviders()
{
	return cfg.get("hiddenOnlineProviders", QStringList());
}

#if (defined Q_OS_LINUX && defined QT_QTDBUS_FOUND) || (defined Q_OS_MAC && defined IOKIT_FOUND)
bool Settings::inhibitSuspend()
{
	return cfg.get("inhibitSuspend", false);
}
#endif

int Settings::rssUpdate()
{
	return cfg.get("rssUpdate", 0, 0, 7 * 24 * 60);
}

QDateTime Settings::lastRssUpdate()
{
	return cfg.get("lastRssUpdate", QDateTime());
}

QString Settings::podcastDownloadPath()
{
	return Utils::fixPath(cfg.get("podcastDownloadPath", Utils::fixPath(QDir::homePath()) + QLatin1String("Music/Podcasts/")));
}

int Settings::podcastAutoDownloadLimit()
{
	if (cfg.hasEntry("podcastAutoDownload")) {
		return cfg.get("podcastAutoDownload", false) ? 1000 : 0;
	}
	return cfg.get("podcastAutoDownloadLimit", 0, 0, 1000);
}

int Settings::volumeStep()
{
	return cfg.get("volumeStep", 5, 1, 20);
}

Settings::StartupState Settings::startupState()
{
	return getStartupState(cfg.get("startupState", getStartupStateStr(SS_Previous)));
}

QString Settings::searchCategory()
{
	return cfg.get("searchCategory", QString());
}

bool Settings::fetchCovers()
{
	return cfg.get("fetchCovers", true);
}

QString Settings::lang()
{
	return cfg.get("lang", QString());
}

bool Settings::showCoverWidget()
{
	return cfg.get("showCoverWidget", true);
}

bool Settings::showStopButton()
{
	return cfg.get("showStopButton", false);
}

bool Settings::showRatingWidget()
{
	return cfg.get("showRatingWidget", false);
}

bool Settings::showTechnicalInfo()
{
	return cfg.get("showTechnicalInfo", false);
}

bool Settings::infoTooltips()
{
	return cfg.get("infoTooltips", true);
}

QSet<QString> Settings::ignorePrefixes()
{
	return Utils::listToSet(cfg.get("ignorePrefixes", Song::ignorePrefixes().values()));
}

bool Settings::mpris()
{
	return cfg.get("mpris", true);
}

QString Settings::style()
{
	return cfg.get("style", QString());
}

#if !defined Q_OS_WIN && !defined Q_OS_MAC
bool Settings::showMenubar()
{
	return cfg.get("showMenubar", false);
}
#endif

bool Settings::useOriginalYear()
{
	return cfg.get("useOriginalYear", false);
}

bool Settings::responsiveSidebar()
{
	return cfg.get("responsiveSidebar", true);
}

void Settings::removeConnectionDetails(const QString& v)
{
	if (v == currentConnection()) {
		saveCurrentConnection(QString());
	}
	cfg.removeGroup(MPDConnectionDetails::configGroupName(v));
}

void Settings::saveConnectionDetails(const MPDConnectionDetails& v)
{
	if (v.name.isEmpty()) {
		cfg.removeEntry("connectionHost");
		cfg.removeEntry("connectionPasswd");
		cfg.removeEntry("connectionPort");
		cfg.removeEntry("mpdDir");
	}

	QString n = MPDConnectionDetails::configGroupName(v.name);
	Configuration grp(n);
	grp.set("host", v.hostname);
	grp.set("port", (int)v.port);
	if (v.dir.startsWith("http:", Qt::CaseInsensitive) || v.dir.startsWith("https:", Qt::CaseInsensitive)) {
		grp.set("dir", v.dir);
	}
	else {
		grp.setDirPath("dir", v.dir);
	}
	grp.set("passwd", v.password);
	grp.set("partition", v.partition);
#ifdef ENABLE_HTTP_STREAM_PLAYBACK
	grp.set("streamUrl", v.streamUrl);
#endif
	grp.set("applyReplayGain", v.applyReplayGain);
	grp.set("allowLocalStreaming", v.allowLocalStreaming);
	grp.set("autoUpdate", v.autoUpdate);
}

void Settings::saveCurrentConnection(const QString& v)
{
	cfg.set("currentConnection", v);
}

void Settings::saveShowFullScreen(bool v)
{
	cfg.set("showFullScreen", v);
}

void Settings::saveShowPlaylist(bool v)
{
	cfg.set("showPlaylist", v);
}

void Settings::saveHeaderState(const QString& key, const QByteArray& v)
{
	cfg.set(key + "HeaderState", v);
}

void Settings::saveSplitterState(const QByteArray& v)
{
	cfg.set("splitterState", v);
}

void Settings::saveSplitterAutoHide(bool v)
{
	cfg.set("splitterAutoHide", v);
}

void Settings::saveMainWindowSize(const QSize& v)
{
	cfg.set("mainWindowSize", v);
}

void Settings::saveMaximized(bool v)
{
	cfg.set("maximized", v);
}

void Settings::saveMainWindowCollapsedSize(const QSize& v)
{
	if (v.width() > 16 && v.height() > 16) {
		cfg.set("mainWindowCollapsedSize", v);
	}
}

void Settings::saveMainWindowPos(const QPoint& pos)
{
	return cfg.set("mainWindowPos", pos);
}

void Settings::saveUseSystemTray(bool v)
{
	cfg.set("useSystemTray", v);
}

void Settings::saveMinimiseOnClose(bool v)
{
	cfg.set("minimiseOnClose", v);
}

void Settings::saveShowPopups(bool v)
{
	cfg.set("showPopups", v);
}

void Settings::saveStopOnExit(bool v)
{
	cfg.set("stopOnExit", v);
}

void Settings::saveStoreCoversInMpdDir(bool v)
{
	cfg.set("storeCoversInMpdDir", v);
}

void Settings::saveStoreLyricsInMpdDir(bool v)
{
	cfg.set("storeLyricsInMpdDir", v);
}

void Settings::saveCoverFilename(const QString& v)
{
	cfg.set("coverFilename", v);
}

void Settings::saveSidebar(int v)
{
	cfg.set("sidebar", v);
}

void Settings::saveComposerGenres(const QSet<QString>& v)
{
	cfg.set("composerGenres", v.values());
}

void Settings::saveSingleTracksFolders(const QSet<QString>& v)
{
	cfg.set("singleTracksFolders", v.values());
}

void Settings::saveCueSupport(MPDParseUtils::CueSupport v)
{
	cfg.set("cueSupport", MPDParseUtils::toStr(v));
}

void Settings::saveLyricProviders(const QStringList& v)
{
	cfg.set("lyricProviders", v);
}

void Settings::saveWikipediaLangs(const QStringList& v)
{
	cfg.set("wikipediaLangs", v);
}

void Settings::saveWikipediaIntroOnly(bool v)
{
	cfg.set("wikipediaIntroOnly", v);
}

void Settings::saveContextBackdrop(int v)
{
	cfg.set("contextBackdrop", v);
}

void Settings::saveContextBackdropOpacity(int v)
{
	cfg.set("contextBackdropOpacity", v);
}

void Settings::saveContextBackdropBlur(int v)
{
	cfg.set("contextBackdropBlur", v);
}

void Settings::saveContextBackdropFile(const QString& v)
{
	cfg.setFilePath("contextBackdropFile", v);
}

void Settings::saveContextDarkBackground(bool v)
{
	cfg.set("contextDarkBackground", v);
}

void Settings::saveContextZoom(int v)
{
	cfg.set("contextZoom", v);
}

void Settings::saveContextSlimPage(const QString& v)
{
	cfg.set("contextSlimPage", v);
}

void Settings::saveContextSplitterState(const QByteArray& v)
{
	cfg.set("contextSplitterState", v);
}

void Settings::saveContextAlwaysCollapsed(bool v)
{
	cfg.set("contextAlwaysCollapsed", v);
}

void Settings::saveContextSwitchTime(int v)
{
	cfg.set("contextSwitchTime", v);
}

void Settings::saveContextAutoScroll(bool v)
{
	cfg.set("contextAutoScroll", v);
}

void Settings::saveContextTrackView(int v)
{
	cfg.set("contextTrackView", v);
}

void Settings::savePage(const QString& v)
{
	cfg.set("page", v);
}

void Settings::saveHiddenPages(const QStringList& v)
{
	cfg.set("hiddenPages", v);
}

#ifdef ENABLE_DEVICES_SUPPORT
void Settings::saveOverwriteSongs(bool v)
{
	cfg.set("overwriteSongs", v);
}

void Settings::saveShowDeleteAction(bool v)
{
	cfg.set("showDeleteAction", v);
}
#endif

void Settings::saveStopFadeDuration(int v)
{
	cfg.set("stopFadeDuration", v);
}

void Settings::savePrevSeekDuration(int v)
{
	cfg.set("prevSeekDuration", v);
}

void Settings::saveHttpAllocatedPort(int v)
{
	cfg.set("httpAllocatedPort", v);
}

void Settings::saveHttpInterface(const QString& v)
{
	cfg.set("httpInterface", v);
}

void Settings::savePlayQueueView(int v)
{
	cfg.set("playQueueView", ItemView::modeStr((ItemView::Mode)v));
}

void Settings::savePlayQueueAutoExpand(bool v)
{
	cfg.set("playQueueAutoExpand", v);
}

void Settings::savePlayQueueStartClosed(bool v)
{
	cfg.set("playQueueStartClosed", v);
}

void Settings::savePlayQueueScroll(bool v)
{
	cfg.set("playQueueScroll", v);
}

void Settings::savePlayQueueBackground(int v)
{
	cfg.set("playQueueBackground", v);
}

void Settings::savePlayQueueBackgroundOpacity(int v)
{
	cfg.set("playQueueBackgroundOpacity", v);
}

void Settings::savePlayQueueBackgroundBlur(int v)
{
	cfg.set("playQueueBackgroundBlur", v);
}

void Settings::savePlayQueueBackgroundFile(const QString& v)
{
	cfg.setFilePath("playQueueBackgroundFile", v);
}

void Settings::savePlayQueueConfirmClear(bool v)
{
	cfg.set("playQueueConfirmClear", v);
}

void Settings::savePlayQueueSearch(bool v)
{
	cfg.set("playQueueSearch", v);
}

void Settings::savePlayQueueSimpleSort(bool v)
{
	cfg.set("playQueueSimpleSort", v);
}

void Settings::savePlayListsStartClosed(bool v)
{
	cfg.set("playListsStartClosed", v);
}

#ifdef ENABLE_HTTP_STREAM_PLAYBACK
void Settings::savePlayStream(bool v)
{
	cfg.set("playStream", v);
}
#endif

#if defined CDDB_FOUND || defined MusicBrainz5_FOUND
void Settings::saveCdAuto(bool v)
{
	cfg.set("cdAuto", v);
}

void Settings::saveParanoiaFull(bool v)
{
	cfg.set("paranoiaFull", v);
}

void Settings::saveParanoiaNeverSkip(bool v)
{
	cfg.set("paranoiaNeverSkip", v);
}

void Settings::saveParanoiaOffset(int v)
{
	cfg.set("paranoiaOffset", v);
}
#endif

#if defined CDDB_FOUND && defined MusicBrainz5_FOUND
void Settings::saveUseCddb(bool v)
{
	cfg.set("useCddb", v);
}
#endif

#ifdef CDDB_FOUND
void Settings::saveCddbHost(const QString& v)
{
	cfg.set("cddbHost", v);
}

void Settings::saveCddbPort(int v)
{
	cfg.set("cddbPort", v);
}
#endif

void Settings::saveForceSingleClick(bool v)
{
	cfg.set("forceSingleClick", v);
}

void Settings::saveStartHidden(bool v)
{
	cfg.set("startHidden", v);
}

void Settings::saveShowTimeRemaining(bool v)
{
	cfg.set("showTimeRemaining", v);
}

void Settings::saveHiddenStreamCategories(const QStringList& v)
{
	cfg.set("hiddenStreamCategories", v);
}

void Settings::saveHiddenOnlineProviders(const QStringList& v)
{
	cfg.set("hiddenOnlineProviders", v);
}

#if (defined Q_OS_LINUX && defined QT_QTDBUS_FOUND) || (defined Q_OS_MAC && defined IOKIT_FOUND)
void Settings::saveInhibitSuspend(bool v)
{
	cfg.set("inhibitSuspend", v);
}
#endif

void Settings::saveRssUpdate(int v)
{
	cfg.set("rssUpdate", v);
}

void Settings::saveLastRssUpdate(const QDateTime& v)
{
	cfg.set("lastRssUpdate", v);
}

void Settings::savePodcastDownloadPath(const QString& v)
{
	cfg.set("podcastDownloadPath", v);
}

void Settings::savePodcastAutoDownloadLimit(int v)
{
	if (cfg.hasEntry("podcastAutoDownload")) {
		cfg.removeEntry("podcastAutoDownload");
	}
	cfg.set("podcastAutoDownloadLimit", v);
}

void Settings::saveVolumeStep(int v)
{
	cfg.set("volumeStep", v);
}

void Settings::saveStartupState(int v)
{
	cfg.set("startupState", getStartupStateStr((StartupState)v));
}

void Settings::saveSearchCategory(const QString& v)
{
	cfg.set("searchCategory", v);
}

void Settings::saveFetchCovers(bool v)
{
	cfg.set("fetchCovers", v);
}

void Settings::saveLang(const QString& v)
{
	cfg.set("lang", v);
}

void Settings::saveShowCoverWidget(bool v)
{
	cfg.set("showCoverWidget", v);
}

void Settings::saveShowStopButton(bool v)
{
	cfg.set("showStopButton", v);
}

void Settings::saveShowRatingWidget(bool v)
{
	cfg.set("showRatingWidget", v);
}

void Settings::saveShowTechnicalInfo(bool v)
{
	cfg.set("showTechnicalInfo", v);
}

void Settings::saveInfoTooltips(bool v)
{
	cfg.set("infoTooltips", v);
}

void Settings::saveIgnorePrefixes(const QSet<QString>& v)
{
	cfg.set("ignorePrefixes", v.values());
}

void Settings::saveMpris(bool v)
{
	cfg.set("mpris", v);
}

void Settings::saveReplayGain(const QString& conn, const QString& v)
{
	QString n = MPDConnectionDetails::configGroupName(conn);
	Configuration grp(n);
	grp.set("replayGain", v);
}

void Settings::saveStyle(const QString& v)
{
	cfg.set("style", v);
}

#if !defined Q_OS_WIN && !defined Q_OS_MAC
void Settings::saveShowMenubar(bool v)
{
	cfg.set("showMenubar", v);
}
#endif

void Settings::saveUseOriginalYear(bool v)
{
	cfg.set("useOriginalYear", v);
}

void Settings::saveResponsiveSidebar(bool v)
{
	cfg.set("responsiveSidebar", v);
}

void Settings::save()
{
	if (AP_NotConfigured != state) {
		if (version() != PACKAGE_VERSION || AP_FirstRun == state) {
			cfg.set("version", PACKAGE_VERSION_STRING);
			ver = PACKAGE_VERSION;
		}
	}
	cfg.sync();
}

void Settings::clearVersion()
{
	cfg.removeEntry("version");
	state = AP_NotConfigured;
}

int Settings::getBoolAsInt(const QString& key, int def)
{
	// Old config, sometimes bool was used - which has now been converted
	// to an int...
	QString v = cfg.get(key, QString::number(def));
	if (QLatin1String("false") == v) {
		return 0;
	}
	if (QLatin1String("true") == v) {
		return 1;
	}
	return v.toInt();
}
