Editor/Carve/ArchExtrude.cs
using System;

namespace Sunless.Architecture;

// The deliberate sibling of a damage zone. Where that one breaks a corner open, this stands work PROUD of
// whichever elevation it covers - a pier between two shopfronts, a rusticated corner, a banded ground storey.
// Both are one dragged box asking the walls under it for a response, which is why neither is a part of its own.
public enum ArchExtrudeKind {
	None,
	Face,
	Quoins,
	Courses,
	// The one kind that goes the other way. It belongs here rather than beside Subtract because a recess in an
	// elevation is a FINISH on that elevation - it takes no wall away - and because the zone is the only thing
	// that can give it a real height band: a modifier dragged in plan can only ever climb to the wall head.
	Indent,
	// A real dressed COLUMN engaged against the wall - footing, plinth, banded shaft and capital off an authored
	// .pillartype - rather than a block on the face. It is the only kind whose work is not a wall modifier, so it
	// is stood by ArchExtrudeAffector as a part the wall does not own, and its band crosses floor lines: that is
	// what makes one gesture a support running the whole height of a building.
	Pier
}

public static class ArchExtrude {
	public const float LeastDepth = 0.5f;

	public static ArchCutAffects Targets( ArchExtrudeKind kind ) {
		return kind == ArchExtrudeKind.None ? ArchCutAffects.None : ArchCutAffects.Walls;
	}

	// Every kind is a wall modifier the tool already emitted, so the block stack, the material role and the piece
	// it comes out as are answers ArchWallModKinds already had rather than three new ones.
	public static ArchWallMod Section( ArchExtrudeKind kind ) => kind switch {
		ArchExtrudeKind.Quoins => ArchWallMod.Quoin,
		ArchExtrudeKind.Courses => ArchWallMod.Course,
		ArchExtrudeKind.Indent => ArchWallMod.Indent,
		_ => ArchWallMod.Pilaster
	};

	// A recess bites ONE elevation whatever the zone says. Offering it both faces would be offering a hole
	// through the wall, which is Subtract's job and not a finish.
	public static bool Coursed( ArchExtrudeKind kind ) => kind is ArchExtrudeKind.Quoins or ArchExtrudeKind.Courses;

	// Whether the zone's work is a real part standing beside the wall rather than a modifier the wall carries.
	// Asked here and never re-tested inline, so the wall generator and the affector cannot disagree about which
	// zones are theirs.
	public static bool Stands( ArchExtrudeKind kind ) => kind == ArchExtrudeKind.Pier;

	public static bool Dresses( ArchExtrudeKind kind ) => kind != ArchExtrudeKind.None && !Stands( kind );

	public static float Reach( ArchCutPart cut ) => MathF.Max( LeastDepth, cut?.ExtrudeDepth ?? LeastDepth );

	public static string Label( ArchExtrudeKind kind ) => kind switch {
		ArchExtrudeKind.Face => "Face — one proud block over everything the zone covers",
		ArchExtrudeKind.Quoins => "Quoins — alternately long and short blocks, the rusticated corner",
		ArchExtrudeKind.Courses => "Courses — level bands across the whole width, parted by a recessed joint",
		ArchExtrudeKind.Indent => "Indent — a recess bitten out of the elevation, on the outside face only",
		ArchExtrudeKind.Pier => "Pier — a real dressed column engaged against the wall, climbing the zone's whole band",
		_ => "None — the zone stands nothing"
	};

	public static string Glyph( ArchExtrudeKind kind ) => kind switch {
		ArchExtrudeKind.Face => "crop_square",
		ArchExtrudeKind.Quoins => "grid_view",
		ArchExtrudeKind.Courses => "view_stream",
		ArchExtrudeKind.Indent => "check_box_outline_blank",
		ArchExtrudeKind.Pier => "view_column",
		_ => "block"
	};
}