Editor/Layers/ArchLayerRules.cs
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}."
};
}
}