+/**
+ * @file Common/config.cpp
+ * @brief eVaf configuration interface implementation
+ * @author Enar Vaikene
+ *
+ * Copyright (c) 2011 Enar Vaikene
+ *
+ * This file is part of the eVaf C++ cross-platform application development framework.
+ *
+ * This file can be used under the terms of the GNU General Public License
+ * version 3.0 as published by the Free Software Foundation and appearing in
+ * the file LICENSE included in the packaging of this file. Please review the
+ * the following information to ensure the GNU General Public License version
+ * 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+ *
+ * Alternatively, this file may be used in accordance with the Commercial License
+ * Agreement provided with the Software.
+ */
+
+#include "config.h"
+#include "inifile.h"
+#include "iregistry.h"
+#include "ilogger.h"
+#include "iapp.h"
+#include "version.h"
+
+#include <QtCore>
+
+//-------------------------------------------------------------------
+
+using namespace eVaf::Common;
+
+iConfig * iConfig::instance()
+{
+ static Internal::Config singleton;
+ return singleton.interface();
+}
+
+
+//-------------------------------------------------------------------
+
+using namespace eVaf::Common::Internal;
+
+Config::Config()
+ : iConfig()
+{
+ setObjectName(QString("%1.iConfig").arg(VER_MODULE_NAME_STR));
+
+ // Register the iConfig interface
+ iRegistry::instance()->registerInterface("iConfig", this);
+}
+
+Config::~Config()
+{
+ done();
+}
+
+iConfig * Config::interface() const
+{
+ return evafQueryInterface<iConfig>("iConfig");
+}
+
+bool Config::init()
+{
+ // Finalize first in case this is not the first time init() is called
+ done();
+
+ return true;
+}
+
+void Config::done()
+{
+ // Commit any queued parameters
+ commitValues();
+
+ // Clear the list of opened INI files
+ QHash<QString, IniFile *>::iterator it = mIniFiles.begin();
+ while (it != mIniFiles.end()) {
+ delete it.value();
+ it = mIniFiles.erase(it);
+ }
+}
+
+QVariant Config::getValue(QString const & paramName, QVariant const & defaultValue) const
+{
+ // Get the optional file part
+ int idx = paramName.indexOf('/');
+ if (idx < 0) {
+ EVAF_ERROR("Invalid parameter name '%s'", qPrintable(paramName));
+ return defaultValue;
+ }
+ QString file = paramName.left(idx);
+ QString name = paramName.mid(idx + 1);
+
+ // Ignore the optional backend identifier in the file name
+ idx = file.indexOf(':');
+ if (idx >= 0)
+ file.remove(0, idx + 1);
+
+ // If the file name is empty or '*', use the application's name
+ if (file.isEmpty() || file == "*")
+ file = iApp::instance()->name();
+
+ IniFile * ini = 0;
+
+ // Is this INI file already opened?
+ QHash<QString, IniFile *>::const_iterator it = mIniFiles.constFind(file);
+
+ // The file is opened and we can reuse it
+ if (it != mIniFiles.constEnd()) {
+ ini = *it;
+ }
+
+ // The file is not opened
+ else {
+ ini = new IniFile(QString("%1/%2.ini").arg(iApp::instance()->etcDir()).arg(file));
+ if (!ini->isValid()) {
+ EVAF_ERROR("Failed to open '%s' : %s", qPrintable(name), qPrintable(ini->errorString()));
+ delete ini;
+ return defaultValue;
+ }
+ mIniFiles.insert(file, ini);
+ }
+
+ // Read the value
+ return ini->getValue(name, defaultValue);
+}
+
+bool Config::setValue(QString const & paramName, QVariant const & value, bool commit)
+{
+ if (!commit) {
+ // Queue the write operation
+ mCommitQueue.enqueue(NameValuePair(paramName, value));
+ }
+ else {
+ // Commit any queued parameters
+ if (!commitValues())
+ return false;
+
+ // Write the parameter
+ if (!writeValue(paramName, value))
+ return false;
+ }
+
+ return true;
+}
+
+bool Config::commitValues()
+{
+ while (!mCommitQueue.isEmpty()) {
+ if (!writeValue(mCommitQueue.dequeue())) {
+ mCommitQueue.clear();
+ return false;
+ }
+ }
+ return true;
+}
+
+bool Config::writeValue(QString const & paramName, QVariant const & value)
+{
+ // Get the optional file part
+ int idx = paramName.indexOf('/');
+ if (idx < 0) {
+ EVAF_ERROR("Invalid parameter name '%s'", qPrintable(paramName));
+ return false;
+ }
+ QString file = paramName.left(idx);
+ QString name = paramName.mid(idx + 1);
+
+ // Ignore the optional backend identifier in the file name
+ idx = file.indexOf(':');
+ if (idx >= 0)
+ file.remove(0, idx + 1);
+
+ // If the file name is empty or '*', use the application's name
+ if (file.isEmpty() || file == "*")
+ file = iApp::instance()->name();
+
+ IniFile * ini = 0;
+
+ // Is this INI file already opened?
+ QHash<QString, IniFile *>::const_iterator it = mIniFiles.constFind(file);
+
+ // The file is opened and we can reuse it
+ if (it != mIniFiles.constEnd()) {
+ ini = *it;
+ }
+
+ // The file is not opened
+ else {
+ ini = new IniFile(QString("%1/%2.ini").arg(iApp::instance()->etcDir()).arg(file));
+ if (!ini->isValid()) {
+ EVAF_ERROR("Failed to open '%s' : %s", qPrintable(name), qPrintable(ini->errorString()));
+ delete ini;
+ return false;
+ }
+ mIniFiles.insert(file, ini);
+ }
+
+ // Write the value
+ if (!ini->setValue(name, value))
+ return false;
+
+ return true;
+}