using System.Text.Json;
namespace ZB.MOM.WW.OtOpcUa.Core.Abstractions;
///
/// The Galaxy () tag reference: the attributeRef a Galaxy raw tag's
/// TagConfig carries, tag_name.AttributeName, which the driver dials through MXAccess. One parser for the
/// driver (which dials it) and the address-space composer (which names the AVEVA event source it implies, Gitea #886),
/// so the two can never disagree about which tags carry one.
///
public static class GalaxyAttributeRef
{
/// The TagConfig key (camelCase; matched case-insensitively).
public const string Key = "attributeRef";
///
/// Read the Galaxy dialled address from a tag's TagConfig JSON — the camelCase attributeRef key (the v3
/// rename of the pre-v3 PascalCase FullName). Case-insensitive on the property name for authoring tolerance;
/// returns null on an absent/blank/non-string value or an unparseable blob.
///
/// The tag's TagConfig JSON.
/// The attributeRef, or null.
public static string? TryRead(string? tagConfigJson)
{
if (string.IsNullOrWhiteSpace(tagConfigJson)) return null;
try
{
using var doc = JsonDocument.Parse(tagConfigJson);
if (doc.RootElement.ValueKind != JsonValueKind.Object) return null;
foreach (var prop in doc.RootElement.EnumerateObject())
{
if (!prop.NameEquals(Key) && !string.Equals(prop.Name, Key, StringComparison.OrdinalIgnoreCase)) continue;
if (prop.Value.ValueKind != JsonValueKind.String) return null;
var v = prop.Value.GetString();
return string.IsNullOrWhiteSpace(v) ? null : v;
}
}
catch (JsonException)
{
// Malformed blob: no dialable address.
}
return null;
}
///
/// The AVEVA alarm reference of a native-alarm tag, or null: the tag's attributeRef when its
/// driver is the Galaxy driver, otherwise null (no other driver's alarms are stored by AVEVA under a Galaxy name).
///
/// The owning driver's DriverType.
/// The tag's TagConfig JSON.
/// The Galaxy alarm reference (tag_name.AlarmAttribute), or null.
public static string? AlarmReferenceOf(string? driverType, string? tagConfigJson) =>
string.Equals(driverType, DriverTypeNames.Galaxy, StringComparison.Ordinal) ? TryRead(tagConfigJson) : null;
///
/// The Galaxy object (tag_name) a reference belongs to: the text before the first ., or the whole
/// reference when it has none. This is AVEVA's Source_Object for the object's events and its attributes'
/// alarms. Null for a blank reference or one that starts with a ..
///
/// A Galaxy reference, e.g. Oven_007.TempHiAlarm.
/// The object name, e.g. Oven_007.
public static string? ObjectNameOf(string? reference)
{
if (string.IsNullOrWhiteSpace(reference)) return null;
var trimmed = reference.Trim();
var dot = trimmed.IndexOf('.');
return dot switch
{
< 0 => trimmed,
0 => null,
_ => trimmed[..dot],
};
}
}