using MeterVault.Core.Analysis; using MeterVault.Core.Analysis.Totals; namespace MeterVault.App.Analysis; /// /// What an analysis view charts (D-47 metric=consumption|generation|export|runtime|net|cost|balance): a /// quantity kind, the cost, or a tank's balance. The URL token is the stable identifier; the visible label comes from /// . /// public enum AnalysisMetric { Consumption, Generation, Export, Runtime, /// A signed virtual result (a difference of kinds, D-26). Net, /// The cost of the scope (D-34 – D-43). Cost, /// A tank's level over time (consumables). Balance, } /// URL tokens and meaning of . public static class AnalysisMetrics { private static readonly (AnalysisMetric Value, string Token)[] Tokens = [ (AnalysisMetric.Consumption, "consumption"), (AnalysisMetric.Generation, "generation"), (AnalysisMetric.Export, "export"), (AnalysisMetric.Runtime, "runtime"), (AnalysisMetric.Net, "net"), (AnalysisMetric.Cost, "cost"), (AnalysisMetric.Balance, "balance"), ]; /// The URL token of a metric (consumption, cost, …). public static string Format(AnalysisMetric metric) { foreach (var (value, token) in Tokens) { if (value == metric) { return token; } } throw new ArgumentOutOfRangeException(nameof(metric), metric, "No URL token for this metric."); } /// Parses a metric token, ignoring case and surrounding blanks; false for anything else. public static bool TryParse(string? token, out AnalysisMetric metric) { metric = default; if (string.IsNullOrWhiteSpace(token)) { return false; } var text = token.Trim(); foreach (var (value, name) in Tokens) { if (string.Equals(name, text, StringComparison.OrdinalIgnoreCase)) { metric = value; return true; } } return false; } /// True for the quantity metrics (everything but cost and balance), which the analysis reader answers. public static bool IsQuantity(this AnalysisMetric metric) => metric is not (AnalysisMetric.Cost or AnalysisMetric.Balance); /// The quantity kind a quantity metric charts; null for cost and balance. public static QuantityKind? QuantityKindOf(AnalysisMetric metric) => metric switch { AnalysisMetric.Consumption => QuantityKind.Consumption, AnalysisMetric.Generation => QuantityKind.Generation, AnalysisMetric.Export => QuantityKind.Export, AnalysisMetric.Runtime => QuantityKind.Runtime, AnalysisMetric.Net => QuantityKind.Net, _ => null, }; /// /// The per-type measures (D-22) a quantity metric shows for an energy type or the portfolio: consumption is the /// household use and, separately, the billed grid import (never added to each other); net has no measure, being a /// virtual meter's own result. /// public static IReadOnlyList MeasuresOf(AnalysisMetric metric) => metric switch { AnalysisMetric.Consumption => [TotalsMeasure.Use, TotalsMeasure.GridImport], AnalysisMetric.Generation => [TotalsMeasure.Generation], AnalysisMetric.Export => [TotalsMeasure.Export], AnalysisMetric.Runtime => [TotalsMeasure.Runtime], _ => [], }; /// The metric a quantity kind is charted under; has none. public static AnalysisMetric? MetricOf(QuantityKind kind) => kind switch { QuantityKind.Consumption => AnalysisMetric.Consumption, QuantityKind.Generation => AnalysisMetric.Generation, QuantityKind.Export => AnalysisMetric.Export, QuantityKind.Runtime => AnalysisMetric.Runtime, QuantityKind.Net => AnalysisMetric.Net, QuantityKind.Cost => AnalysisMetric.Cost, _ => null, }; }