using ScadaLink.Commons.Entities.Templates;
namespace ScadaLink.TemplateEngine;
///
/// Resolves the hierarchical ("qualified") name of a composition-derived
/// template. A derived template stores only its contained name — the
/// owning composition slot's InstanceName, unique only within that owner.
/// The qualified path (Owner.Slot.Slot…) is computed on demand by
/// walking the chain up to the base
/// template.
///
public static class TemplateNaming
{
///
/// Returns the dotted hierarchical name of . For
/// a base (non-derived) template this is just its stored name. The walk is
/// null-safe: if any owner link is missing from the supplied lookups it
/// stops and falls back to the stored contained name, and a cycle (which
/// the composition graph should never contain) is broken defensively.
///
public static string QualifiedName(
Template template,
IReadOnlyDictionary byId,
IReadOnlyDictionary compById)
{
ArgumentNullException.ThrowIfNull(template);
ArgumentNullException.ThrowIfNull(byId);
ArgumentNullException.ThrowIfNull(compById);
return Resolve(template, byId, compById, new HashSet());
}
private static string Resolve(
Template template,
IReadOnlyDictionary byId,
IReadOnlyDictionary compById,
HashSet visited)
{
// Base template, broken owner link, or a cycle → the stored name is the
// best (and contained) answer.
if (!template.IsDerived
|| template.OwnerCompositionId is not { } compId
|| !compById.TryGetValue(compId, out var composition)
|| !byId.TryGetValue(composition.TemplateId, out var owner)
|| !visited.Add(template.Id))
{
return template.Name;
}
return $"{Resolve(owner, byId, compById, visited)}.{composition.InstanceName}";
}
}