/*
*  
*  $Id: configurationcontroller.cpp $
*  Ginkgo CADx Project
*
*  Copyright 2008-12 MetaEmotion S.L. All rights reserved.
*  http://ginkgo-cadx.com
*
*  This file is licensed under LGPL v3 license.
*  See License.txt for details
*
*
*/
#include <wx/string.h>
#include <api/globals.h>
#include "controladorlog.h"
#include "configurationcontroller.h"
#include <main/controllers/configurationcontroller.h>
#include <wx/filename.h>
#include <wx/dir.h>
#include <wx/wfstream.h>
#include <wx/fileconf.h>
#include <wx/stdpaths.h>
#include <wx/file.h>


namespace GNC {
	namespace GCS {
		ConfigurationController* ConfigurationController::m_pInstance = NULL;
		wxCriticalSection ConfigurationController::m_criticalSection;

		ConfigurationController* ConfigurationController::Instance() {
			if (m_pInstance == NULL) {
				wxCriticalSectionLocker locker(m_criticalSection);
				m_pInstance = new ConfigurationController();
			}
			return m_pInstance;	  
		}

		void ConfigurationController::FreeInstance() {
			wxCriticalSectionLocker locker(m_criticalSection);
			if (m_pInstance != NULL) {
				delete m_pInstance;
				m_pInstance = NULL;
			}			
		}

		void ConfigurationController::Flush()
		{
			wxFileName user(m_pathUserConfig);
			if (user.IsFileWritable()) {
				m_pUserConfig->Flush();
			} 
			wxFileName global(m_pathGlobalConfig);
			if (global.IsFileWritable()) {
				m_pGeneralConfig->Flush();
			}
		}

		bool ConfigurationController::deleteEntryGeneral(const std::string& scope, const std::string&key)
		{
			return deleteEntry(TC_General, scope, key);
		}

		bool ConfigurationController::writeStringGeneral(const std::string& scope, const std::string& key, const std::string& value)
		{
			return writeString(TC_General, scope, key, value);
		}

      bool ConfigurationController::readStringGeneral(const std::string& scope, const std::string& key, std::string& value, const std::string& defaultValue)
		{
			return readString(TC_General, scope, key, value, defaultValue);
		}

		bool ConfigurationController::readBoolGeneral(const std::string& scope, const std::string& key, bool& value, bool defaultValue)
		{
			return readBool(TC_General, scope, key, value, defaultValue);
		}

		bool ConfigurationController::writeBoolGeneral(const std::string& scope, const std::string& key, bool value)
		{
			return writeBool(TC_General, scope, key, value);
		}

		bool ConfigurationController::readIntGeneral(const std::string& scope, const std::string& key, int& value, int defaultValue)
		{
			return readInt(TC_General, scope, key, value, defaultValue);
		}

		bool ConfigurationController::writeIntGeneral(const std::string& scope, const std::string& key, int value)
		{
			return writeInt(TC_General, scope, key, value);
		}

		bool ConfigurationController::readDoubleGeneral(const std::string& scope, const std::string& key, double& value, double defaultValue)
		{
			return readDouble(TC_General, scope, key, value, defaultValue);
		}

		bool ConfigurationController::writeDoubleGeneral(const std::string& scope, const std::string& key, double value)
		{
			return writeDouble(TC_General, scope, key, value);
		}

		bool ConfigurationController::writeGroupGeneral(const std::string& scope, const TListGroups& listOfGroups, const std::string& prefix)
		{
			return writeGroup(TC_General, scope, listOfGroups, prefix);
		}

		bool ConfigurationController::readGroupGeneral(const std::string& scope, TListGroups& listOfGroups) 
		{
			return readGroup(TC_General, scope, listOfGroups);
		}

		bool ConfigurationController::deleteEntryUser(const std::string& scope, const std::string&key)
		{
			return deleteEntry(TC_User, scope, key);
		}
		
		bool ConfigurationController::writeStringUser(const std::string& scope, const std::string& key, const std::string& value)
		{
			return writeString(TC_User, scope, key, value);
		}

      bool ConfigurationController::readStringUser(const std::string& scope, const std::string& key, std::string& value, const std::string& defaultValue)
		{
			if (!readString(TC_General, scope, key, value, defaultValue)) {
				return readString(TC_User, scope, key, value, defaultValue);
			} else {
				return true;
			}
		}

		bool ConfigurationController::readBoolUser(const std::string& scope, const std::string& key, bool& value, bool defaultValue)
		{
			if (!readBool(TC_General, scope, key, value, defaultValue)) {
				return readBool(TC_User, scope, key, value, defaultValue);
			} else {
				return true;
			}
		}

		bool ConfigurationController::writeBoolUser(const std::string& scope, const std::string& key, bool value)
		{
			return writeBool(TC_User, scope, key, value);
		}

		bool ConfigurationController::readIntUser(const std::string& scope, const std::string& key, int& value, int defaultValue)
		{
			if (!readInt(TC_General, scope, key, value, defaultValue)) {
				return readInt(TC_User, scope, key, value, defaultValue);
			} else {
				return true;
			}
		}

		bool ConfigurationController::writeIntUser(const std::string& scope, const std::string& key, int value)
		{
			return writeInt(TC_User, scope, key, value);
		}

		bool ConfigurationController::readDoubleUser(const std::string& scope, const std::string& key, double& value, double defaultValue)
		{
			if (!readDouble(TC_General, scope, key, value, defaultValue)) {
				return readDouble(TC_User, scope, key, value, defaultValue);
			} else {
				return true;
			}
		}

		bool ConfigurationController::writeDoubleUser(const std::string& scope, const std::string& key, double value)
		{
			return writeDouble(TC_User, scope, key, value);
		}

		bool ConfigurationController::writeGroupUser(const std::string& scope, const TListGroups& listOfGroups, const std::string& prefix)
		{
			return writeGroup(TC_User, scope, listOfGroups, prefix);
		}

		bool ConfigurationController::readGroupUser(const std::string& scope, TListGroups& listOfGroups) 
		{
			if (!readGroup(TC_General, scope, listOfGroups)) {
				return readGroup(TC_User, scope, listOfGroups);
			} else {
				return true;
			}
		}

		bool ConfigurationController::saveGlobalConfigurationFile(const std::string& path)
		{
			wxString pathWx = FROMPATH(path);
			wxCriticalSectionLocker locker(m_criticalSection);
			wxFileOutputStream ostream(pathWx);
			return m_pGeneralConfig->Save(ostream);	
		}

		bool ConfigurationController::loadGlobalConfigurationFile(const std::string& path)
		{
			wxString pathWx = FROMPATH(path);
			wxCriticalSectionLocker locker(m_criticalSection);
			delete m_pGeneralConfig;
			bool res = wxCopyFile(pathWx, m_pathGlobalConfig, true);
			if (!res) {
				LOG_WARN("ConfigurationController", "Error Loading configuration file " << path);
			}
			m_pGeneralConfig = new wxFileConfig(wxEmptyString,wxEmptyString,m_pathGlobalConfig,wxEmptyString,wxCONFIG_USE_LOCAL_FILE);
			return res;
		}

		bool ConfigurationController::deleteEntry(TConfig type, const std::string& scope, const std::string&key)
		{
			wxCriticalSectionLocker locker(m_criticalSection);
			wxConfigBase * config;
			if (type==TC_General) {
				config = m_pGeneralConfig;
			} else {
				config = m_pUserConfig;
			}

			if (key == "") {
				return config->DeleteGroup(wxString::FromUTF8(scope.c_str()));
			} else {
				config->SetPath(wxString::FromUTF8(scope.c_str()));
				return config->DeleteEntry(wxString::FromUTF8(key.c_str()));
			}
		}

		bool ConfigurationController::writeString(TConfig type, const std::string& scope, const std::string& key, const std::string& value) 
		{
			wxCriticalSectionLocker locker(m_criticalSection);
			wxConfigBase * config;
			if (type==TC_General) {
				config = m_pGeneralConfig;
			} else {
				config = m_pUserConfig;
			}
			config->SetPath(wxString::FromUTF8(scope.c_str()));

			bool result = config->Write(wxString::FromUTF8(key.c_str()),wxString::FromUTF8(value.c_str()));
			Flush();   
			return result;
		}

		bool ConfigurationController::readString(TConfig type, const std::string& scope, const std::string& key, std::string& value, const std::string& defaultValue)
		{
			wxCriticalSectionLocker locker(m_criticalSection);
			wxConfigBase * config;
			if (type==TC_General) {
				config = m_pGeneralConfig;
			} else {
				config = m_pUserConfig;
			}
			config->SetPath(wxString::FromUTF8(scope.c_str()));
			wxString wxTmp;
			bool result = config->Read(wxString::FromUTF8(key.c_str()),&wxTmp,wxString::FromUTF8(defaultValue.c_str()));
			value = wxTmp.ToUTF8();
			return result;
		}

		bool ConfigurationController::writeBool(TConfig type, const std::string& scope, const std::string& key, bool value) 
		{
			wxCriticalSectionLocker locker(m_criticalSection);
			wxConfigBase * config;
			if (type==TC_General) {
				config = m_pGeneralConfig;
			} else {
				config = m_pUserConfig;
			}
			config->SetPath(wxString::FromUTF8(scope.c_str()));

			bool result = config->Write(wxString::FromUTF8(key.c_str()),value);
			Flush();    
			return result;
		}

		bool ConfigurationController::readBool(TConfig type, const std::string& scope, const std::string& key, bool& value, bool defaultValue)
		{
			wxCriticalSectionLocker locker(m_criticalSection);
			wxConfigBase * config;
			if (type==TC_General) {
				config = m_pGeneralConfig;
			} else {
				config = m_pUserConfig;
			}
			config->SetPath(wxString::FromUTF8(scope.c_str()));
			
			bool result = config->Read(wxString::FromUTF8(key.c_str()),&value,defaultValue);
			
			return result;
		}

		bool ConfigurationController::readInt(TConfig type, const std::string& scope, const std::string& key, int& value, int defaultValue)
		{
			wxCriticalSectionLocker locker(m_criticalSection);
			wxConfigBase * config;
			if (type==TC_General) {
				config = m_pGeneralConfig;
			} else {
				config = m_pUserConfig;
			}
			config->SetPath(wxString::FromUTF8(scope.c_str()));
			
			bool result = config->Read(wxString::FromUTF8(key.c_str()),&value,defaultValue);
			
			return result;
		}

		bool ConfigurationController::writeInt(TConfig type, const std::string& scope, const std::string& key, int value) 
		{
			wxCriticalSectionLocker locker(m_criticalSection);
			wxConfigBase * config;
			if (type==TC_General) {
				config = m_pGeneralConfig;
			} else {
				config = m_pUserConfig;
			}
			config->SetPath(wxString::FromUTF8(scope.c_str()));

			bool result = config->Write(wxString::FromUTF8(key.c_str()),value);
			Flush();    
			return result;
		}

		bool ConfigurationController::readDouble(TConfig type, const std::string& scope, const std::string& key, double& value, double defaultValue)
		{
			wxCriticalSectionLocker locker(m_criticalSection);
			wxConfigBase * config;
			if (type==TC_General) {
				config = m_pGeneralConfig;
			} else {
				config = m_pUserConfig;
			}
			config->SetPath(wxString::FromUTF8(scope.c_str()));
			
			bool result = config->Read(wxString::FromUTF8(key.c_str()),&value,defaultValue);
			
			return result;
		}

		bool ConfigurationController::writeDouble(TConfig type, const std::string& scope, const std::string& key, double value) 
		{
			wxCriticalSectionLocker locker(m_criticalSection);
			wxConfigBase * config;
			if (type==TC_General) {
				config = m_pGeneralConfig;
			} else {
				config = m_pUserConfig;
			}
			config->SetPath(wxString::FromUTF8(scope.c_str()));

			bool result = config->Write(wxString::FromUTF8(key.c_str()),value);
			Flush();    
			return result;
		}

		bool ConfigurationController::writeGroup(TConfig type, const std::string& scope, const TListGroups& listOfGroups, const std::string& prefix)
		{
			wxCriticalSectionLocker locker(m_criticalSection);
			wxConfigBase * config;
			if (type==TC_General) {
				config = m_pGeneralConfig;
			} else {
				config = m_pUserConfig;
			}
			config->DeleteGroup(wxString::FromUTF8(scope.c_str()));
			config->SetPath(wxString::FromUTF8(scope.c_str()));

			int i=0;
			bool ok = true;
			for (TListGroups::const_iterator itGroups = listOfGroups.begin(); itGroups != listOfGroups.end(); ++itGroups, ++i) {
				for (TMapValues::const_iterator itValues = (*itGroups).begin(); itValues != (*itGroups).end(); ++itValues) {
					std::ostringstream ostrKey;
					ostrKey << prefix << i << "/" << (*itValues).first;
					ok &= config->Write(wxString::FromUTF8(ostrKey.str().c_str()), wxString::FromUTF8((*itValues).second.c_str()));
				}
			}
			return ok;
		}

		bool ConfigurationController::readGroup(TConfig type, const std::string& scope, TListGroups& listOfGroups)
		{
			wxCriticalSectionLocker locker(m_criticalSection);
			wxConfigBase * config;
			if (type==TC_General) {
				config = m_pGeneralConfig;
			} else {
				config = m_pUserConfig;
			}
			config->SetPath(wxString::FromUTF8(scope.c_str()));

			long dummy;
			wxString str;
			bool bCont = config->GetFirstGroup(str, dummy);
			while ( bCont ) {
				config->SetPath(str);
				TMapValues mapTmp;
				long dummy2;
				wxString str2;
				bool bCont2 = config->GetFirstEntry(str, dummy2); 
				while (bCont2) {
					config->Read(str, &str2);
					mapTmp[std::string(str.ToUTF8())] = std::string(str2.ToUTF8());
					bCont2 = config->GetNextEntry(str, dummy2);
				}
				listOfGroups.push_back(mapTmp);
				config->SetPath(wxT(".."));
				bCont = config->GetNextGroup(str, dummy);
			}
			return true;
		}

		ConfigurationController::ConfigurationController() 
		{			
			m_pUserConfig = new wxFileConfig(wxT("GinkgoUser"), wxT("Metaemotion"),wxEmptyString,wxEmptyString,wxCONFIG_USE_LOCAL_FILE );
			m_pathUserConfig = m_pGeneralConfig->GetLocalFileName(wxT("GinkgoUser"));

			wxString pathEjecutable = wxStandardPaths::Get().GetExecutablePath();
			wxFileName fileName(pathEjecutable);
			//= than execute
			fileName.SetExt(wxT("ini"));
			m_pathGlobalConfig = fileName.GetLongPath();
			if(wxFileExists(m_pathGlobalConfig)) {
				m_pGeneralConfig = new wxFileConfig(wxEmptyString,wxEmptyString,m_pathGlobalConfig,wxEmptyString,wxCONFIG_USE_LOCAL_FILE);
			} else {
				//Ginkgo.ini
				m_pathGlobalConfig = wxPathOnly(m_pathGlobalConfig) +  wxFileName::GetPathSeparator() + wxT("GinkgoGeneral.ini");
				if(wxFileExists(m_pathGlobalConfig)) {
					m_pGeneralConfig = new wxFileConfig(wxEmptyString,wxEmptyString,m_pathGlobalConfig,wxEmptyString,wxCONFIG_USE_LOCAL_FILE);
				} else {
					m_pathGlobalConfig = wxPathOnly(m_pathGlobalConfig) +  wxFileName::GetPathSeparator() + wxT("Ginkgo.ini");
					if(wxFileExists(m_pathGlobalConfig)) {
						m_pGeneralConfig = new wxFileConfig(wxEmptyString,wxEmptyString,m_pathGlobalConfig,wxEmptyString,wxCONFIG_USE_LOCAL_FILE);
					} else {
						//se inicializa el fichero de propiedades
						m_pGeneralConfig = new wxFileConfig(wxT("Ginkgo"), wxT("Metaemotion"),wxEmptyString,wxEmptyString,wxCONFIG_USE_LOCAL_FILE );
						m_pathGlobalConfig = m_pGeneralConfig->GetLocalFileName(wxT("Ginkgo"));
					}
				}
			}
		}

		ConfigurationController::~ConfigurationController() {
			Flush();
			delete m_pUserConfig;
			delete m_pGeneralConfig;
		}  

	}
}
