using ZB.MOM.WW.OtOpcUa.Driver.FOCAS;
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers.Pickers;
///
/// The addressing spaces the manual FOCAS picker can compose. Mirrors the parseable subset of
/// : is deliberately absent because a
/// fixed-tree path is discovered from the machine, not composed from parts — the picker's browse
/// tree supplies those.
///
public enum FocasManualAddressKind
{
/// PMC area — letter + byte + optional bit.
Pmc,
/// CNC parameter number + optional bit.
Parameter,
/// Macro variable number.
Macro,
}
///
/// Pure static helper that composes a canonical FOCAS address from the manual picker's parts.
/// Extracted so unit tests can call it without bUnit.
///
///
///
/// It builds through rather than formatting a string, so what
/// it emits is parseable by construction and the two cannot drift.
///
///
/// It previously emitted $"{group}:{parameterId}" over a group list of
/// axis/spindle/program/status — none of which is a FOCAS addressing space — so the
/// picker's own default value, axis:5, was an address the driver rejects. Together with
/// the browse-commit defect this meant every UI-assisted authoring path produced unusable tags,
/// and only hand-typed addresses worked at all (Gitea #540).
///
///
public static class FocasAddressBuilder
{
/// The PMC area letters the driver accepts, in the order the picker offers them.
public static IReadOnlyList PmcLetters { get; } =
["X", "Y", "F", "G", "R", "D", "C", "K", "A", "E", "T"];
///
/// Composes the canonical FOCAS address string, or an empty string when the parts do not form a
/// valid address (an out-of-range bit, a negative number, an unknown PMC letter).
///
/// Which addressing space the address is in.
/// The PMC area letter; ignored unless is
/// .
/// The PMC byte, parameter number or macro number.
/// Optional bit index — 0–7 for PMC, 0–31 for a parameter. Null for a
/// whole-word address; always ignored for a macro, which has no bit form.
/// The canonical address, or an empty string when the parts are not addressable.
public static string Build(
FocasManualAddressKind kind, string? pmcLetter, int number, int? bitIndex)
{
FocasAddress? candidate = kind switch
{
FocasManualAddressKind.Pmc => new FocasAddress(
FocasAreaKind.Pmc, (pmcLetter ?? "").Trim().ToUpperInvariant(), number, bitIndex),
FocasManualAddressKind.Parameter => new FocasAddress(
FocasAreaKind.Parameter, null, number, bitIndex),
FocasManualAddressKind.Macro => new FocasAddress(
FocasAreaKind.Macro, null, number, null),
_ => null,
};
// Round-trip rather than trust the parts: the record accepts any values, the parser is the
// authority on which of them address anything, and an empty result is what the picker shows
// as "no address yet" instead of a plausible-looking string the driver would silently skip.
return candidate?.Canonical is { } text && FocasAddress.TryParse(text) is not null ? text : "";
}
}