using System.Collections.Concurrent; using System.Linq.Expressions; using AIStudio.Settings.DataModel; using AIStudio.Tools.PluginSystem; namespace AIStudio.Settings; public static partial class ManagedConfiguration { private static readonly ConcurrentDictionary METADATA = new(); /// /// Attempts to retrieve the configuration metadata for a given configuration selection and property expression. /// /// /// When no configuration metadata is found, it returns a NoConfig instance with the default value set to default(TValue). /// This allows the caller to handle the absence of configuration gracefully. In such cases, the return value of the method will be false. /// /// The expression to select the configuration class. /// The expression to select the property within the configuration class. /// The output parameter that will hold the configuration metadata if found. /// The type of the configuration class. /// The type of the property within the configuration class. /// True if the configuration metadata was found, otherwise false. public static bool TryGet(Expression> configSelection, Expression> propertyExpression, out ConfigMeta configMeta) { var configPath = Path(configSelection, propertyExpression); if (METADATA.TryGetValue(configPath, out var value) && value is ConfigMeta meta) { configMeta = meta; return true; } configMeta = new NoConfig(configSelection, propertyExpression) { Default = default!, }; return false; } /// /// Checks if a configuration setting is left over from a configuration plugin that is no longer available. /// If the configuration setting is locked and managed by a configuration plugin that is not available, /// it resets the managed state of the configuration setting and returns true. /// Otherwise, it returns false. /// /// The expression to select the configuration class. /// The expression to select the property within the configuration class. /// The collection of available plugins to check against. /// The type of the configuration class. /// The type of the property within the configuration class. /// True if the configuration setting is left over and was reset, otherwise false. public static bool IsConfigurationLeftOver(Expression> configSelection, Expression> propertyExpression, IEnumerable availablePlugins) { if (!TryGet(configSelection, propertyExpression, out var configMeta)) return false; if(configMeta.MangedByConfigPluginId == Guid.Empty || !configMeta.IsLocked) return false; // Check if the configuration plugin ID is valid against the available plugin IDs: var plugin = availablePlugins.FirstOrDefault(x => x.Id == configMeta.MangedByConfigPluginId); if (plugin is null) { // Remove the locked state: configMeta.ResetManagedState(); return true; } return false; } private static string Path(Expression> configSelection, Expression> propertyExpression) { var className = typeof(TClass).Name; var memberExpressionConfig = configSelection.GetMemberExpression(); var configName = memberExpressionConfig.Member.Name; var memberExpressionProperty = propertyExpression.GetMemberExpression(); var propertyName = memberExpressionProperty.Member.Name; var configPath = $"{configName}.{className}.{propertyName}"; return configPath; } }