Skip to content
Yaml_Conf.cpp 5 KiB
Newer Older
Valerio Pastore's avatar
Valerio Pastore committed
#include <Yaml_Conf.h>
#include <fstream>
#include <filesystem>
#include <algorithm>
#include <iterator>
#include <cctype>
#include<boost/algorithm/string.hpp>

using namespace inaf::oasbo::Configurators;

YamlConfigurator::YamlConfigurator(std::string path) {
	this->path = path;
	load(path);
}

void YamlConfigurator::load(std::string path) {
	if (!std::filesystem::exists(path)) {
		std::cerr << "Yaml Configurator error: file: " << path
				<< " does not exits." << std::endl;
		return;
	}
	file = YAML::LoadFile(path);
	if (file.IsNull()) {
		std::cerr << "Yaml Configurator error: empty file." << std::endl;
	}
	if (!file.IsSequence()) {
		std::cerr
				<< "Yaml Configurator error: file does not contains a yaml sequence."
				<< std::endl;
	}
}

/**
 * Aggiorna il file di configurazione YAML inserendo nuove voci di configurazione per la chiave target.
 * Rimuove anche le vecchie configurazioni corrispondenti alla chiave target.
 *
 * @param target La chiave di destinazione per la quale aggiungere e rimuovere le voci di configurazione.
 */
int YamlConfigurator::pushConfigToSource(std::string target) {
	boost::to_lower(target);
	// Extracrs only target entries
	std::map<std::string, std::string> filteredMap;
	for (const auto &pair : this->config) {
		if (pair.first.compare(0, target.length(),
				target) == 0) {
			std::string key = pair.first.substr(target.length() + 1);
			boost::to_lower(key);
			filteredMap[key] = pair.second;
		}
	}

	// save the file content in a vector
	std::fstream ifile(path);
	std::vector<std::string> file_content;
	std::string line;
	while (std::getline(ifile, line)) {
		file_content.push_back(line);
	}
	ifile.close();
	// update the file content into the vector
	size_t pos = 0;
	for (; pos < file_content.size(); pos++) {
		if (file_content[pos].find(std::string("- ").append(target))
				!= std::string::npos) {
			for (auto pair : filteredMap) {
				pos += 1;
				std::string new_line("    " + pair.first + ": " + pair.second);
				auto insertionPoint = file_content.begin() + pos;
				file_content.insert(insertionPoint, new_line);
			}
			pos += 1;
			break;
		}
	}

	// remove the old configuration
	for (; pos < file_content.size(); pos++) {
		if (file_content[pos][0] != '-') {
			line = file_content[pos];
			// Elimina gli spazi vuoti all'inizio della stringa e  Ferma l'analisi al carattere ":" escluso
			line = line.erase(0, line.find_first_not_of(' ')).substr(0,
					line.find(':'));
			boost::to_lower(line);
			bool found = false; // Controlla se la riga è stata sostituita dalla nuova conf
			for (auto key : filteredMap) {
				if (key.first.compare(line) == 0) {
					found = true;
					break;
				}
			}
			if (found) {
				file_content.erase(file_content.begin() + pos);
				pos--;
			}

		} else
			break;
	}

	// update the file with the content of the vector
	std::ofstream ofile(path, std::ofstream::trunc); // Open the file in truncation mode
	for (const auto &line : file_content) {
		ofile << line << std::endl;
	}
	ofile.close();

	load(path);
	return 1;
}

int YamlConfigurator::pushConfigToSource() {
	// estraggo tutti i target e li inserisco nel vector
	std::vector<std::string> tagets;

	for (const auto &pair : config) {
		std::string key = pair.first;
		size_t pos = key.find('_');

		if (pos != std::string::npos) {
			std::string prefix = key.substr(0, pos);
			if (std::find(tagets.begin(), tagets.end(), prefix)
					== tagets.end()) {
				tagets.push_back(prefix);
			}
		}
	}
	// chiamo la funzione per ogni target.
	for (auto target : tagets)
		pushConfigToSource(target);
	return 1;
}

int YamlConfigurator::readConfigFromSource(std::string target) {
	boost::to_lower(target);
	if (file.IsNull())
		return -1;
	try {
		for (auto element : file) {
			if (element[target]) {
				YAML::Node node = element[target];
				for (const auto &kvp : node) {
					config[target + "_" + kvp.first.as<std::string>()] =
							kvp.second.as<std::string>();
				}
			}
		}
	} catch (const YAML::Exception &e) {
		std::cerr << "Yaml Configurator reading error:: " << e.what()
				<< std::endl;
		return -1;
	}
	return 1;
}

int YamlConfigurator::readConfigFromSource() {
	if (file.IsNull())
		return -1;
	try {
		// Itera sugli elementi del documento YAML
		for (const auto &element : file) {
			for (const auto &pair : element) {
				std::string elementName = element.first.as<std::string>();
				boost::to_lower(elementName);
				// Se l'elemento è una mappa, estrai le chiavi e i valori
				if (pair.second.IsMap()) {
					for (const auto &subPair : pair.second) {
						std::string key = elementName + "_"
								+ subPair.first.as<std::string>();
						std::string value = subPair.second.as<std::string>();
						config[key] = value;
					}
				}
			}
		}
	} catch (const YAML::Exception &e) {
		std::cerr << "Yaml Configurator reading error:: " << e.what()
				<< std::endl;
		return -1;
	}
	return 1;
}

int YamlConfigurator::insert(std::map<std::string, std::string> conf,
		std::string target) {
	boost::to_lower(target);
	for (const auto &kvp : conf) {
		this->config[target + "_" + kvp.first] = kvp.second;
	}
	return 1;
}