Decision logic for whether an architectural layer kind may be parented under another. Exposes CanParent overloads for root and non-root parents, returns an ArchLayerDecision with Allowed, HostOutput and Refusal text, and delegates manifest queries to ArchKindsAsked.
using System.Collections.Generic;
using System.Linq;
namespace Sunless.Architecture;
// One answer to "may this child live under this parent?" - the typed hierarchy's capability matrix.
// Placement, reparenting and the tree's Add menu all ask here; a no never touches the plan.
public sealed class ArchLayerDecision
{
public bool Allowed { get; init; }
// The named output a child consumes from its parent - "Platform body and deck", say.
public string HostOutput { get; init; } = "";
// Why the pair was refused, readable as a tooltip or viewport note.
public string Refusal { get; init; } = "";
}
public static class ArchLayerRules
{
// The plan root: only a kind that roots at the plan stands at a domain head.
public static ArchLayerDecision CanParent( ArchLayerRef parent, ArchKind childKind )
{
if ( parent.ItemId == 0 )
{
return CanParentRoot( childKind, "the plan root" );
}
return CanParent( parent.Kind, childKind );
}
public static ArchLayerDecision CanParent( ArchKind parentKind, ArchKind childKind )
{
if ( ValidChildren( parentKind ).Contains( childKind ) )
{
return new ArchLayerDecision { Allowed = true, HostOutput = HostOutput( parentKind ) };
}
return Refusal( childKind, ArchKindsAsked.Label( parentKind ) );
}
// The tree's Add menu: every kind that may sit under this parent. A kind with no manifest is not among them,
// so the menu offers nothing rather than offering a dead row.
public static IReadOnlyList<ArchKind> ValidChildren( ArchKind parentKind )
{
return ArchKindsAsked.ValidChildren( parentKind );
}
public static string HostOutput( ArchKind parentKind ) => ArchKindsAsked.HostOutput( parentKind );
static ArchLayerDecision CanParentRoot( ArchKind childKind, string rootName )
{
return ArchKindsAsked.RootsAtPlan( childKind )
? new ArchLayerDecision { Allowed = true, HostOutput = "Site plane" }
: Refusal( childKind, rootName );
}
static ArchLayerDecision Refusal( ArchKind childKind, string parentName )
{
return new ArchLayerDecision
{
Allowed = false,
Refusal = $"Cannot put {ArchKindsAsked.Label( childKind )} inside {parentName}."
};
}
}