Files
chapter-organizer/Core/Validation/ValidationConfiguration.cs
T
2025-12-14 11:08:04 -05:00

200 lines
7.0 KiB
C#

using Core.Entities;
using System.Text.Json;
namespace Core.Validation;
/// <summary>
/// Configuration for validation thresholds and rules
/// </summary>
public class ValidationConfiguration
{
// Event count thresholds
/// <summary>
/// Minimum recommended number of events per student (Warning if below)
/// </summary>
public int MinRecommendedEvents { get; set; } = 2;
/// <summary>
/// Maximum recommended number of events per student (Warning if above)
/// </summary>
public int MaxRecommendedEvents { get; set; } = 4;
/// <summary>
/// Minimum critical number of events per student (Error if below)
/// </summary>
public int MinCriticalEvents { get; set; } = 1;
/// <summary>
/// Maximum critical number of events per student (Error if above)
/// </summary>
public int MaxCriticalEvents { get; set; } = 6;
/// <summary>
/// Maximum recommended number of regional events per student (Warning if above)
/// </summary>
public int MaxRegionalEvents { get; set; } = 3;
// Required event types
/// <summary>
/// Whether to require students to have at least one regional event
/// </summary>
public bool RequireRegionalEvent { get; set; } = true;
/// <summary>
/// Whether to require students to have at least one on-site activity
/// </summary>
public bool RequireOnSiteActivity { get; set; } = true;
/// <summary>
/// Whether to require students to have at least one individual event
/// </summary>
public bool RequireIndividualEvent { get; set; } = false;
/// <summary>
/// Whether to require team-based events to have an assigned captain
/// </summary>
public bool RequireTeamCaptain { get; set; } = true;
// Severity levels for each rule type
/// <summary>
/// Severity level for "No Regional Event" warnings
/// </summary>
public ValidationSeverity NoRegionalEventSeverity { get; set; } = ValidationSeverity.Warning;
/// <summary>
/// Severity level for "No On-Site Activity" warnings
/// </summary>
public ValidationSeverity NoOnSiteActivitySeverity { get; set; } = ValidationSeverity.Warning;
/// <summary>
/// Severity level for "No Individual Event" warnings
/// </summary>
public ValidationSeverity NoIndividualEventSeverity { get; set; } = ValidationSeverity.Warning;
/// <summary>
/// Severity level for team size warnings
/// </summary>
public ValidationSeverity TeamSizeSeverity { get; set; } = ValidationSeverity.Warning;
/// <summary>
/// Severity level for event count warnings
/// </summary>
public ValidationSeverity EventCountSeverity { get; set; } = ValidationSeverity.Warning;
/// <summary>
/// Severity level for missing captain warnings
/// </summary>
public ValidationSeverity MissingCaptainSeverity { get; set; } = ValidationSeverity.Warning;
/// <summary>
/// Severity level for too many regional events warnings
/// </summary>
public ValidationSeverity TooManyRegionalEventsSeverity { get; set; } = ValidationSeverity.Warning;
/// <summary>
/// Default configuration matching current app behavior
/// </summary>
public static ValidationConfiguration Default => new()
{
RequireRegionalEvent = true,
RequireOnSiteActivity = true,
RequireIndividualEvent = false,
MinRecommendedEvents = 2,
MaxRecommendedEvents = 4,
MinCriticalEvents = 1,
MaxCriticalEvents = 6,
MaxRegionalEvents = 3,
RequireTeamCaptain = true,
NoRegionalEventSeverity = ValidationSeverity.Warning,
NoOnSiteActivitySeverity = ValidationSeverity.Warning,
NoIndividualEventSeverity = ValidationSeverity.Warning,
TeamSizeSeverity = ValidationSeverity.Warning,
EventCountSeverity = ValidationSeverity.Warning,
MissingCaptainSeverity = ValidationSeverity.Warning,
TooManyRegionalEventsSeverity = ValidationSeverity.Warning
};
/// <summary>
/// Create validation configuration from assignment parameters
/// </summary>
/// <param name="parameters">Assignment parameters to convert</param>
/// <returns>Validation configuration matching the assignment parameters</returns>
public static ValidationConfiguration FromAssignmentParameters(AssignmentParameters parameters)
{
return new ValidationConfiguration
{
RequireRegionalEvent = parameters.RequireRegional,
RequireOnSiteActivity = parameters.RequireOnSite,
MinRecommendedEvents = parameters.EventsLowerBound,
MaxRecommendedEvents = parameters.EventsUpperBound,
MinCriticalEvents = 1,
MaxCriticalEvents = 6,
RequireTeamCaptain = true,
NoRegionalEventSeverity = ValidationSeverity.Warning,
NoOnSiteActivitySeverity = ValidationSeverity.Warning,
NoIndividualEventSeverity = ValidationSeverity.Warning,
TeamSizeSeverity = ValidationSeverity.Warning,
EventCountSeverity = ValidationSeverity.Warning,
MissingCaptainSeverity = ValidationSeverity.Warning
};
}
/// <summary>
/// Deserialize validation configuration from JSON string
/// </summary>
/// <param name="json">JSON string containing configuration</param>
/// <returns>ValidationConfiguration instance or Default if deserialization fails</returns>
public static ValidationConfiguration FromJson(string json)
{
try
{
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
Converters = { new System.Text.Json.Serialization.JsonStringEnumConverter() }
};
return JsonSerializer.Deserialize<ValidationConfiguration>(json, options) ?? Default;
}
catch
{
return Default;
}
}
/// <summary>
/// Load validation configuration from a JSON file
/// </summary>
/// <param name="path">Path to the JSON configuration file</param>
/// <returns>ValidationConfiguration instance or Default if file doesn't exist or loading fails</returns>
public static async Task<ValidationConfiguration> LoadFromFileAsync(string path)
{
try
{
if (!File.Exists(path))
return Default;
var json = await File.ReadAllTextAsync(path);
return FromJson(json);
}
catch
{
return Default;
}
}
/// <summary>
/// Save this validation configuration to a JSON file
/// </summary>
/// <param name="path">Path where the JSON file should be saved</param>
public async Task SaveToFileAsync(string path)
{
var options = new JsonSerializerOptions
{
WriteIndented = true,
Converters = { new System.Text.Json.Serialization.JsonStringEnumConverter() }
};
var json = JsonSerializer.Serialize(this, options);
await File.WriteAllTextAsync(path, json);
}
}