using System.Collections.Immutable; using System.Diagnostics; namespace StabilityMatrix.Core.Models; public readonly record struct LaunchOptionCard { public required string Title { get; init; } public required LaunchOptionType Type { get; init; } public required IReadOnlyList Options { get; init; } public string? Description { get; init; } public static LaunchOptionCard FromDefinition(LaunchOptionDefinition definition) { return new LaunchOptionCard { Title = definition.Name, Description = definition.Description, Type = definition.Type, Options = definition.Options.Select(s => { var option = new LaunchOption { Name = s, Type = definition.Type, DefaultValue = definition.DefaultValue }; return option; }).ToImmutableArray() }; } /// /// Yield LaunchOptionCards given definitions and launch args to load /// /// /// /// /// public static IEnumerable FromDefinitions( IEnumerable definitions, IEnumerable launchArgs) { // During card creation, store dict of options with initial values var initialOptions = new Dictionary(); // To dictionary ignoring duplicates var launchArgsDict = launchArgs .ToLookup(launchArg => launchArg.Name) .ToDictionary( group => group.Key, group => group.First() ); // Create cards foreach (var definition in definitions) { // Check that non-bool types have exactly one option if (definition.Type != LaunchOptionType.Bool && definition.Options.Count != 1) { throw new InvalidOperationException( $"Definition: '{definition.Name}' has {definition.Options.Count} options," + $" it must have exactly 1 option for non-bool types"); } // Store initial values if (definition.InitialValue != null) { // For bool types, initial value can be string (single/multiple options) or bool (single option) if (definition.Type == LaunchOptionType.Bool) { // For single option, check bool if (definition.Options.Count == 1 && definition.InitialValue is bool boolValue) { initialOptions[definition.Options.First()] = boolValue; } else { // For single/multiple options (string only) var option = definition.Options.FirstOrDefault(opt => opt.Equals(definition.InitialValue)); if (option == null) { throw new InvalidOperationException( $"Definition '{definition.Name}' has InitialValue of '{definition.InitialValue}', but it was not found in options:" + $" '{string.Join(",", definition.Options)}'"); } initialOptions[option] = true; } } else { // Otherwise store initial value for first option initialOptions[definition.Options.First()] = definition.InitialValue; } } // Create the new card var card = new LaunchOptionCard { Title = definition.Name, Description = definition.Description, Type = definition.Type, Options = definition.Options.Select(s => { // Parse defaults and user loaded values here var userOption = launchArgsDict.GetValueOrDefault(s); var userValue = userOption?.OptionValue; // If no user value, check set initial value if (userValue is null) { var initialValue = initialOptions.GetValueOrDefault(s); userValue ??= initialValue; Debug.WriteLineIf(initialValue != null, $"Using initial value {initialValue} for option {s}"); } var option = new LaunchOption { Name = s, Type = definition.Type, DefaultValue = definition.DefaultValue, OptionValue = userValue }; return option; }).ToImmutableArray() }; yield return card; } } }