/////////////////////////////////////////////////////////////////////////////
// Name:        configutils.cpp
// Author:      Cesar Mauri Loba
// Copyright:   (C) 2011 Cesar Mauri Loba - CREA Software Systems
// 
//  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/>.
/////////////////////////////////////////////////////////////////////////////
#include "sphost/configutils.h"

#include "spcore/coreruntime.h"
#include "spcore/paths.h"

#define BOOST_FILESYSTEM_VERSION 3
//#define BOOST_FILESYSTEM_NO_DEPRECATED 1
#include <boost/filesystem.hpp>
#include <boost/filesystem/exception.hpp>

#include <string.h>

using namespace spcore;
using namespace std;
using namespace boost::filesystem;

namespace sphost {

static
bool GetFullPath(const char* fname, path& fullpath) 
{
	assert (fname && *fname);
	if (!fname || !*fname) return false;
	
	// Set file name
	fullpath= fname;
	if (!fullpath.is_complete()) {
		// When is relative
		const char* userDataDir= getSpCoreRuntime()->GetPaths().GetUserDataDir();
		if (!userDataDir) return false;
		fullpath= userDataDir;
		fullpath/= fname;
	}
		
	return true;
}

SmartPtr<IConfiguration> LoadConfiguration(const char* fname) 
{
	ICoreRuntime* cr= getSpCoreRuntime();

	SmartPtr<IConfiguration> result;
	
	path fullpath;
	if (!GetFullPath(fname, fullpath)) return result;
	
	// Try to open config file
	FILE* file= fopen(fullpath.string().c_str(), "rb");
	if (!file) {
		if (errno!= ENOENT) {
			// Log other errors than non-existing file
			std::string error_msg= "Cannot open ";
			error_msg+= fullpath.string();
			error_msg+= " for reading. ";
			error_msg+= strerror(errno);
			
			cr->LogMessage(ICoreRuntime::LOG_ERROR, error_msg.c_str(), "configutils");
		}
		return result;
	}
	
	// Read contents
	result= cr->GetConfiguration();
	if (!result->Load(file)) {
		fclose(file);
		result.reset();

		// Log error
		std::string error_msg= "An error occurred while loading configuration file ";
		error_msg+= fullpath.string();
		cr->LogMessage(ICoreRuntime::LOG_ERROR, error_msg.c_str(), "configutils");

		return result;
	}
	fclose(file);

	return result;
}

bool SaveConfiguration(const IConfiguration& cfg, const char* fname)
{
	path fullpath;
	ICoreRuntime* cr= getSpCoreRuntime();
	
	if (!GetFullPath(fname, fullpath)) return false;
	
	// Make sure user configuration directory exists
	try {
		boost::filesystem::create_directories(fullpath.branch_path());
	}
	catch (const boost::filesystem::filesystem_error& e) {
		cr->LogMessage(ICoreRuntime::LOG_ERROR, e.what(), "configutils");
		return false;
	}

	// Try to open config file
	FILE* file= fopen(fullpath.string().c_str(), "wb");
	if (!file) {
		std::string error_msg= "Cannot open ";
		error_msg+= fullpath.string();
		error_msg+= " for writing. ";
		error_msg+= strerror(errno);

		cr->LogMessage(ICoreRuntime::LOG_ERROR, error_msg.c_str(), "configutils");
		return false;
	}

	// Create configuration instance
	if (!cfg.Save(file)) {
		fclose(file);
		
		// Log error
		std::string error_msg= "An error occurred writing configuration file ";
		error_msg+= fullpath.string();
		cr->LogMessage(ICoreRuntime::LOG_ERROR, error_msg.c_str(), "configutils");
		return false;
	}
	fclose(file);

	return true;
}

};
