using System.Collections.Frozen; using ZB.MOM.WW.HistorianGateway.Contracts.Grpc; using ZB.MOM.WW.OtOpcUa.Core.Abstractions; namespace ZB.MOM.WW.OtOpcUa.Driver.Historian.Gateway.Mapping; /// /// Maps the driver-agnostic (OPC UA Part 13 aggregate) onto the /// gateway's native . /// /// /// /// Served: → , /// Minimum → , Maximum → , /// Total → . /// /// /// Deliberately NOT served (#679): (OPC UA Average is the arithmetic mean; /// AVEVA's modes include no arithmetic mean — only the time-weighted one, which is TimeAverage) and /// (AVEVA Counter is a rollover-counter increase, not a sample count). /// Both surface as BadAggregateNotSupported rather than returning a different statistic under the requested name. /// /// internal static class AggregateModeMapper { /// /// The aggregates the gateway serves — every defined member maps, derived from it so the /// advertised set and the dispatch can never disagree. /// returns it (#682); it is the ONLY declaration of the gateway's served set. /// public static readonly IReadOnlySet Served = Enum.GetValues().Where(a => TryMap(a) is not null).ToFrozenSet(); /// Maps an aggregate function to the gateway retrieval mode. /// The driver-agnostic aggregate function. /// The matching gateway . /// A defined member the gateway has no retrieval mode for. /// An undefined enum value. public static RetrievalMode ToRetrievalMode(HistoryAggregateType aggregate) { if (TryMap(aggregate) is { } mode) return mode; // Part 13 aggregates the gateway has no retrieval mode for (#285) — an UNDEFINED enum value is a // programming error, but a defined-yet-unserved member is a normal client request the server // answers with BadAggregateNotSupported. if (Enum.IsDefined(aggregate)) throw new HistoryAggregateNotSupportedException(aggregate); throw new ArgumentOutOfRangeException( nameof(aggregate), aggregate, "Unmapped HistoryAggregateType — add a RetrievalMode mapping."); } /// The single mapping table: the retrieval mode for a served aggregate, or null. private static RetrievalMode? TryMap(HistoryAggregateType aggregate) => aggregate switch { HistoryAggregateType.TimeAverage => RetrievalMode.TimeWeightedAverage, HistoryAggregateType.Minimum => RetrievalMode.MinimumWithTime, HistoryAggregateType.Maximum => RetrievalMode.MaximumWithTime, HistoryAggregateType.Total => RetrievalMode.Integral, _ => null, }; }