using Google.Protobuf.WellKnownTypes;
using ZB.MOM.WW.HistorianGateway.Contracts.Grpc;
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
using ZB.MOM.WW.OtOpcUa.Core.AlarmHistorian;
namespace ZB.MOM.WW.OtOpcUa.Driver.Historian.Gateway.Mapping;
///
/// Maps a driver-agnostic onto a gateway wire
/// for the SendEvent write path.
///
internal static class AlarmEventMapper
{
///
/// Maps to the numeric OPC UA Part 9 priority (1-1000) carried in the
/// wire event's Severity property, per the
/// contract ("Mapped to Historian's numeric priority on the sink side"). The read side
/// () int.TryParses this same property, so it
/// must stay a numeric string — the enum's .ToString() name (e.g. "High") is NOT
/// parseable and used to silently collapse every read-back severity to the minimum (1). The
/// values mirror the existing native-alarm convention
/// (ZB.MOM.WW.OtOpcUa.Runtime.Drivers.NativeAlarmProjector.MapSeverity).
///
private static string ToNumericSeverity(AlarmSeverity severity) => severity switch
{
AlarmSeverity.Low => "200",
AlarmSeverity.Medium => "500",
AlarmSeverity.High => "700",
AlarmSeverity.Critical => "900",
_ => "500",
};
/// Maps an alarm historian event to a gateway event.
/// The driver-agnostic alarm event.
/// The gateway wire event ready for SendEvent.
public static HistorianEvent ToHistorianEvent(AlarmHistorianEvent alarm)
{
if (alarm.DeliveryId == Guid.Empty)
throw new ArgumentException("Alarm delivery identity must be nonzero.", nameof(alarm));
// Timestamp.FromDateTime requires a Utc-kind DateTime; coerce defensively (TimestampUtc is
// already Utc by contract, but a caller could pass Unspecified).
var eventTime = Timestamp.FromDateTime(DateTime.SpecifyKind(alarm.TimestampUtc, DateTimeKind.Utc));
var historianEvent = new HistorianEvent
{
// Identity belongs to the event/durable queue, never to an individual RPC attempt.
Id = alarm.DeliveryId.ToString("D"),
SourceName = alarm.EquipmentPath,
Type = alarm.AlarmTypeName,
EventTime = eventTime,
ReceivedTime = eventTime, // the server re-stamps the received time on the SQL path
};
// Proto map values must be non-null — only insert non-null properties.
if (!string.IsNullOrWhiteSpace(alarm.AlarmId))
historianEvent.Properties["AlarmId"] = alarm.AlarmId;
historianEvent.Properties["AlarmName"] = alarm.AlarmName;
historianEvent.Properties["EventKind"] = alarm.EventKind;
historianEvent.Properties["Severity"] = ToNumericSeverity(alarm.Severity);
historianEvent.Properties["User"] = alarm.User;
historianEvent.Properties["Message"] = alarm.Message;
if (alarm.Comment is not null)
historianEvent.Properties["Comment"] = alarm.Comment;
return historianEvent;
}
}