using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
using ZB.MOM.WW.OtOpcUa.Core.ScriptedAlarms;
namespace ZB.MOM.WW.OtOpcUa.Server.Phase7;
///
/// adapter exposing each scripted alarm's current
/// as an OPC UA boolean. Phase 7 follow-up (task #245).
///
///
///
/// Paired with the dispatch in
/// DriverNodeManager.OnReadValue. Full-reference lookup is the
/// ScriptedAlarmId the walker wrote into DriverAttributeInfo.FullName
/// when emitting the alarm variable node.
///
///
/// Unknown alarm ids return BadNodeIdUnknown so misconfiguration surfaces
/// instead of silently reading false. Alarms whose predicate has never
/// been evaluated (brand new, before the engine's first cascade tick) report
/// via ,
/// which matches the Part 9 initial-state semantics.
///
///
public sealed class ScriptedAlarmReadable : IReadable
{
/// OPC UA StatusCodes.BadNodeIdUnknown — kept local so we don't pull the OPC stack.
private const uint BadNodeIdUnknown = 0x80340000;
private readonly ScriptedAlarmEngine _engine;
public ScriptedAlarmReadable(ScriptedAlarmEngine engine)
{
_engine = engine ?? throw new ArgumentNullException(nameof(engine));
}
public Task> ReadAsync(
IReadOnlyList fullReferences, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(fullReferences);
var now = DateTime.UtcNow;
var results = new DataValueSnapshot[fullReferences.Count];
for (var i = 0; i < fullReferences.Count; i++)
{
var alarmId = fullReferences[i];
var state = _engine.GetState(alarmId);
if (state is null)
{
results[i] = new DataValueSnapshot(null, BadNodeIdUnknown, null, now);
continue;
}
var active = state.Active == AlarmActiveState.Active;
results[i] = new DataValueSnapshot(active, 0u, now, now);
}
return Task.FromResult>(results);
}
}