/// <summary> /// Deep-clones the setting group. /// </summary> /// <returns>The new group.</returns> public SettingsGroup DeepClone() { var result = new SettingsGroup(); foreach (var setting in _settings) { result._settings[setting.Key] = setting.Value; } foreach (var group in _groups) { result._groups[group.Key] = group.Value.DeepClone(); } return(result); }
/// <summary> /// Gets the value of a setting by path. /// </summary> /// <typeparam name="T">The type of the setting.</typeparam> /// <param name="path">The path of the value to get.</param> /// <param name="getter">A function that gets the value once the bottom-level group is found.</param> /// <returns>The value of the setting, as returned by the getter.</returns> private T GetSettingByPath <T>(string path, Func <SettingsGroup, string, T> getter) { string[] pathComponents = SplitPath(path); SettingsGroup currentGroup = this; for (int i = 0; i < pathComponents.Length; i++) { string component = pathComponents[i]; if (i == pathComponents.Length - 1) { return(getter(currentGroup, component)); } currentGroup = currentGroup._groups[component]; } throw new ArgumentException("Invalid path"); }
/// <summary> /// Loads a settings group from an XML container. /// </summary> /// <param name="container">The container to read settings from.</param> /// <returns>The loaded settings group.</returns> public SettingsGroup LoadSettingsGroup(XContainer container) { var result = new SettingsGroup(); foreach (XElement elem in container.Elements()) { if (elem.HasElements) { result.SetGroup(elem.Name.LocalName, LoadSettingsGroup(elem)); } else { result.SetSetting(elem.Name.LocalName, LoadSetting(elem)); } } return(result); }
/// <summary> /// Determines whether or not a given path has a value defined for it. /// </summary> /// <param name="path">The path to check.</param> /// <returns><c>true</c> if the path has a value defined.</returns> public bool PathExists(string path) { string[] pathComponents = SplitPath(path); SettingsGroup currentGroup = this; for (int i = 0; i < pathComponents.Length; i++) { string component = pathComponents[i]; if (i == pathComponents.Length - 1) { return(currentGroup._settings.ContainsKey(component) || currentGroup._groups.ContainsKey(component)); } if (!currentGroup._groups.TryGetValue(component, out currentGroup)) { return(false); } } return(false); }
/// <summary> /// Imports settings recursively from another group. /// Any existing settings will be overwritten, and all sub-groups will be merged. /// </summary> /// <param name="other">The group to import from.</param> public void Import(SettingsGroup other) { foreach (var setting in other._settings) { _settings[setting.Key] = setting.Value; } foreach (var group in other._groups) { SettingsGroup existingGroup; if (_groups.TryGetValue(group.Key, out existingGroup)) { existingGroup.Import(group.Value); } else { _groups[group.Key] = group.Value; } } }
/// <summary> /// Sets the value of a setting by path. Any groups will be created along the way. /// </summary> /// <param name="path">The path to the setting.</param> /// <param name="setter">An action that sets the value once the bottom-level group is found.</param> private void SetSettingByPath(string path, Action <SettingsGroup, string> setter) { string[] pathComponents = SplitPath(path); SettingsGroup currentGroup = this; for (int i = 0; i < pathComponents.Length; i++) { string component = pathComponents[i]; if (i == pathComponents.Length - 1) { setter(currentGroup, component); return; } if (!currentGroup._groups.TryGetValue(component, out currentGroup)) { // Sub-group does not exist - create one var newGroup = new SettingsGroup(); currentGroup._groups[component] = newGroup; currentGroup = newGroup; } } }
/// <summary> /// Loads an engine database from an XML container. /// </summary> /// <param name="container">The container to read engine elements from.</param> /// <returns>The built engine database.</returns> public static EngineDatabase LoadDatabase(XContainer container) { XMLSettingsGroupLoader loader = CreateSettingsGroupLoader(); var result = new EngineDatabase(); foreach (XElement elem in container.Elements("engine")) { string name = XMLUtil.GetStringAttribute(elem, "name"); string version = XMLUtil.GetStringAttribute(elem, "version"); string inherits = XMLUtil.GetStringAttribute(elem, "inherits", null); SettingsGroup settings = loader.LoadSettingsGroup(elem); if (!string.IsNullOrWhiteSpace(inherits)) { // Clone the base engine's settings and then import the new settings on top of it SettingsGroup baseSettings = result.FindEngineByName(inherits).Settings.DeepClone(); baseSettings.Import(settings); settings = baseSettings; } var desc = new EngineDescription(name, version, settings); result.RegisterEngine(desc); } return(result); }
/// <summary> /// Sets a sub-group. /// </summary> /// <param name="path">The path to the sub-group to set.</param> /// <param name="newGroup">The value of the group.</param> public void SetGroup(string path, SettingsGroup newGroup) { SetSettingByPath(path, (group, name) => group._groups[name] = newGroup); }