Editor/Cabinet/ArchCabinetExtent.cs
namespace Sunless.Architecture;

// A run's extent is its RESOLVE, corners and all - so a stretch given away to a corner unit reports the shape it
// really has rather than the drag it was drawn over, and a selection outline sits on the carcasses that stand.
public sealed class ArchCabinetExtentProvider : IArchExtentProvider {
	public ArchKind Kind => ArchKind.Cabinet;

	public ArchExtent Measure( object payload, ArchExtentContext context ) {
		var extent = new ArchExtent();

		if ( payload is not ArchCabinetPart part ) {
			return extent;
		}

		// Found rather than taken: an ask that arrived with neither - a viewport pick, an mcp argument - would
		// otherwise measure the run off plan zero and report it a storey and a plinth below what stands there.
		var room = context.Room ?? context.Plan?.HostOf<ArchRoom>( part );
		var building = context.Building ?? context.Plan?.OwnerOf( room );
		var shape = ArchCabinetShape.Resolve( context.Plan, context.Kit, room, building, part );

		if ( !shape.Standing ) {
			return extent;
		}

		// The generator draws under the building's own space, which its foundation lifts off the ground. A planned
		// extent left in plan space reads as the whole run standing a plinth below what was built.
		var lift = ArchAnswers.Load().Lift( context.Plan, building, context.Kit );

		if ( shape.Cells.Count > 0 ) {
			extent.Add( shape.Outline(), shape.Seat + lift, shape.Head + lift );
		}

		foreach ( var joint in shape.Joints ) {
			extent.Add( joint.Top, joint.Seat + lift, joint.Head + joint.Counter + lift );

			if ( joint.Cornice > 0.01f ) {
				extent.Add( joint.Crown, joint.Head + lift, joint.Head + joint.Cornice + lift );
			}
		}

		return extent;
	}
}