using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using Microsoft.Extensions.Logging;
namespace ImageCatalog;
///
/// Modern parameter storage service using XML for persistence.
/// Thread-safe key-value store for application settings.
///
public class ParametriSetup
{
private readonly object _lock = new();
private readonly ILogger _logger;
private Dictionary _parameters = new(StringComparer.OrdinalIgnoreCase);
///
/// Gets or sets the XML file path for settings storage.
///
public string? NomeFileSetup { get; set; }
///
/// Initializes a new instance with the specified settings file.
///
/// Path to the XML settings file.
/// Optional logger for diagnostics.
public ParametriSetup(string? fileSetup = null, ILogger? logger = null)
{
_logger = logger ?? Microsoft.Extensions.Logging.Abstractions.NullLogger.Instance;
NomeFileSetup = fileSetup;
if (!string.IsNullOrWhiteSpace(fileSetup))
{
CaricaParametriSetup();
}
}
///
/// Loads settings from the XML file.
///
public void CaricaParametriSetup()
{
lock (_lock)
{
if (string.IsNullOrEmpty(NomeFileSetup) || !File.Exists(NomeFileSetup))
{
_parameters = new Dictionary(StringComparer.OrdinalIgnoreCase);
return;
}
try
{
var doc = XDocument.Load(NomeFileSetup);
var setupElements = doc.Descendants("Setup");
_parameters = setupElements
.Where(e => e.Element("Nome") != null)
.ToDictionary(
e => e.Element("Nome")!.Value,
e => e.Element("Valore")?.Value ?? string.Empty,
StringComparer.OrdinalIgnoreCase
);
_logger.LogInformation("Loaded {Count} parameters from {FilePath}", _parameters.Count, NomeFileSetup);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to load settings from {FilePath}", NomeFileSetup);
_parameters = new Dictionary(StringComparer.OrdinalIgnoreCase);
}
}
}
///
/// Saves settings to the XML file.
///
/// Thrown when NomeFileSetup is not set.
public void SalvaParametriSetup()
{
if (string.IsNullOrWhiteSpace(NomeFileSetup))
throw new InvalidOperationException("NomeFileSetup is not set.");
lock (_lock)
{
try
{
// Ensure directory exists
var directory = Path.GetDirectoryName(NomeFileSetup);
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
// Create XML document with DataSet-compatible structure
var doc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XElement("NewDataSet",
_parameters.Select(kvp =>
new XElement("Setup",
new XElement("Nome", kvp.Key),
new XElement("Valore", kvp.Value)
)
)
)
);
doc.Save(NomeFileSetup);
_logger.LogInformation("Saved {Count} parameters to {FilePath}", _parameters.Count, NomeFileSetup);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to save settings to {FilePath}", NomeFileSetup);
throw;
}
}
}
///
/// Reads a parameter as a string.
///
/// Parameter name.
/// Parameter value or empty string if not found.
public string LeggiParametroString(string nomeParametro)
{
lock (_lock)
{
return _parameters.TryGetValue(nomeParametro, out var value) ? value : string.Empty;
}
}
///
/// Reads a parameter as a boolean.
///
/// Parameter name.
/// True if value is truthy (TRUE, OK, SI, 1, YES, VERO), false otherwise.
public bool LeggiParametroBoolean(string nomeParametro)
{
var raw = LeggiParametroString(nomeParametro);
return raw.ToUpperInvariant() switch
{
"TRUE" or "OK" or "SI" or "1" or "YES" or "VERO" => true,
_ => false
};
}
///
/// Updates or creates a parameter.
///
/// Parameter name.
/// Parameter value.
public void AggiornaParametro(string nomeParametro, object? valoreParametro)
{
lock (_lock)
{
_parameters[nomeParametro] = valoreParametro?.ToString() ?? string.Empty;
}
}
///
/// Reads a parameter and converts it to the specified type.
///
/// Target type.
/// Parameter name.
/// Default value if conversion fails.
/// Converted value or default value.
public T LeggiParametro(string nomeParametro, T defaultValue = default!)
{
var raw = LeggiParametroString(nomeParametro);
if (string.IsNullOrEmpty(raw))
return defaultValue;
try
{
// Handle nullable types
var targetType = Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T);
// Special handling for common types
if (targetType == typeof(bool))
{
return (T)(object)LeggiParametroBoolean(nomeParametro);
}
return (T)Convert.ChangeType(raw, targetType, CultureInfo.InvariantCulture);
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Failed to convert parameter {ParameterName} to {TypeName}, using default value",
nomeParametro, typeof(T).Name);
return defaultValue;
}
}
///
/// Checks if a parameter exists.
///
/// Parameter name.
/// True if parameter exists, false otherwise.
public bool ParametroExists(string nomeParametro)
{
lock (_lock)
{
return _parameters.ContainsKey(nomeParametro);
}
}
///
/// Removes a parameter.
///
/// Parameter name.
/// True if parameter was removed, false if it didn't exist.
public bool RimuoviParametro(string nomeParametro)
{
lock (_lock)
{
return _parameters.Remove(nomeParametro);
}
}
///
/// Gets all parameter names.
///
/// Collection of parameter names.
public IReadOnlyCollection GetParameterNames()
{
lock (_lock)
{
return _parameters.Keys.ToList();
}
}
///
/// Clears all parameters.
///
public void ClearAll()
{
lock (_lock)
{
_parameters.Clear();
}
}
}