using System;
using ArchestrA.MxAccess;
using Serilog;
using ZB.MOM.WW.LmxProxy.Host.Domain;
namespace ZB.MOM.WW.LmxProxy.Host.MxAccess
{
public sealed partial class MxAccessClient
{
///
/// Callback invoked by the SubscriptionManager when it needs to deliver
/// data change events. Set by the SubscriptionManager during initialization.
///
public Action? OnTagValueChanged { get; set; }
///
/// COM event handler for MxAccess OnDataChange events.
/// Signature matches the ArchestrA.MxAccess ILMXProxyServerEvents interface.
///
private void OnDataChange(
int hLMXServerHandle,
int phItemHandle,
object pvItemValue,
int pwItemQuality,
object pftItemTimeStamp,
ref MXSTATUS_PROXY[] ItemStatus)
{
try
{
var quality = MapQuality(pwItemQuality);
var timestamp = ConvertTimestamp(pftItemTimeStamp);
// Check MXSTATUS_PROXY — if success is false, override quality
// with a more specific code derived from the MxAccess status fields
if (ItemStatus != null && ItemStatus.Length > 0 && ItemStatus[0].success == 0)
{
var status = ItemStatus[0];
quality = MxStatusMapper.CategoryToQuality((int)status.category, status.detail);
Log.Debug("OnDataChange status failure for handle {Handle}: {Status}",
phItemHandle, MxStatusMapper.FormatStatus(status.detail, (int)status.category, (int)status.detectedBy));
}
var vtq = new Vtq(pvItemValue, timestamp, quality);
// Resolve address from handle map
string address;
lock (_lock)
{
if (!_handleToAddress.TryGetValue(phItemHandle, out address))
{
Log.Debug("OnDataChange for unknown handle {Handle}, ignoring", phItemHandle);
return;
}
}
// Invoke the stored subscription callback
Action callback;
lock (_lock)
{
if (!_storedSubscriptions.TryGetValue(address, out callback))
{
Log.Debug("OnDataChange for {Address} but no callback registered", address);
return;
}
}
callback.Invoke(address, vtq);
// Also route to the SubscriptionManager's global handler
OnTagValueChanged?.Invoke(address, vtq);
}
catch (Exception ex)
{
Log.Error(ex, "Error processing OnDataChange event for handle {Handle}", phItemHandle);
}
}
///
/// COM event handler for MxAccess OnWriteComplete events.
/// Signature matches the ArchestrA.MxAccess ILMXProxyServerEvents interface.
/// Kept wired for diagnostic logging only — writes are resolved synchronously
/// when the Write() COM call returns without throwing.
///
private void OnWriteComplete(
int hLMXServerHandle,
int phItemHandle,
ref MXSTATUS_PROXY[] ItemStatus)
{
try
{
if (ItemStatus != null && ItemStatus.Length > 0)
{
var status = ItemStatus[0];
if (status.success == 0)
{
Log.Warning("OnWriteComplete callback: write failed for handle {Handle}: {Status}",
phItemHandle, MxStatusMapper.FormatStatus(status.detail, (int)status.category, (int)status.detectedBy));
}
else
{
Log.Debug("OnWriteComplete callback: write succeeded for handle {Handle}", phItemHandle);
}
}
else
{
Log.Debug("OnWriteComplete callback: no status for handle {Handle}", phItemHandle);
}
}
catch (Exception ex)
{
Log.Error(ex, "Error processing OnWriteComplete event for handle {Handle}", phItemHandle);
}
}
///
/// Converts a timestamp object to DateTime in UTC.
///
private static DateTime ConvertTimestamp(object timestamp)
{
if (timestamp is DateTime dt)
{
return dt.Kind == DateTimeKind.Utc ? dt : dt.ToUniversalTime();
}
return DateTime.UtcNow;
}
}
}