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,
};
}