Editor/Bands/ArchCorniceStyle.cs
using System;
using System.Collections.Generic;
using System.Linq;

namespace Sunless.Architecture;

// What one course of a cornice IS. Append only: a kind inserted mid-list renumbers every authored style
// after it.
public enum CorniceCourse {
	// A swept kit section standing proud of the exterior face.
	Moulding,
	// A plain projecting box - a corona, a frieze.
	Band,
	// A row of small blocks, counted off the run.
	Dentils,
	// The same row, each block cut from a section instead of squared.
	Modillions,
	// A cap straddling the wall, oversailing BOTH faces - two of them stepped is a coping.
	Coping
}

// One course, stated bottom up. Rise is the band it takes out of the head it hangs from; Projection is how far
// proud of the face it stands, or how far a coping oversails each face.
public sealed class ArchCorniceCourse {
	public CorniceCourse Kind { get; set; } = CorniceCourse.Band;
	// Authored with +x standing OUT of the wall and +y up, whichever host sweeps it.
	public string Profile { get; set; } = "";
	public float Rise { get; set; } = 4f;
	public float Projection { get; set; } = 3f;
	// A block row's pitch, never its count - the count comes off the run. 0 takes the kit's own dentil stock.
	public float Block { get; set; }
	public float Gap { get; set; }
	public ArchSurface Field { get; set; } = ArchSurface.Trim;

	public bool Stands => Rise > 0.05f;

	public bool Straddles => Kind == CorniceCourse.Coping;

	public ArchCorniceCourse Copy() {
		return new ArchCorniceCourse {
			Kind = Kind,
			Profile = Profile,
			Rise = Rise,
			Projection = Projection,
			Block = Block,
			Gap = Gap,
			Field = Field
		};
	}
}

// The blocks that step ABOVE the cornice head - the piers a main-street parapet breaks its line with. They ride
// the wall's own column line where it has one, so a pilastered elevation needs no second rhythm authored here.
public sealed class ArchCornicePier {
	public float Width { get; set; } = 16f;
	public float Rise { get; set; }
	public float Projection { get; set; } = 2f;
	public float Cap { get; set; } = 3f;
	public float CapOversail { get; set; } = 1.5f;
	public ArchSurface Field { get; set; } = ArchSurface.WallExterior;

	public bool Stands => Rise > 0.5f && Width > 0.5f;

	public ArchCornicePier Copy() {
		return new ArchCornicePier {
			Width = Width,
			Rise = Rise,
			Projection = Projection,
			Cap = Cap,
			CapOversail = CapOversail,
			Field = Field
		};
	}
}

// The corbel that carries the TURN. A block row is held off every mitre, so a corner has no dentil on it; this is
// what stands there instead - one per vertex of the ring, deeper than the blocks, hung under the corona.
public sealed class ArchCorniceBracket {
	public float Width { get; set; }
	public float Drop { get; set; }
	public float Projection { get; set; }
	public ArchSurface Field { get; set; } = ArchSurface.Trim;

	public bool Stands => Width > 0.5f && Drop > 0.5f;

	public ArchCorniceBracket Copy() {
		return new ArchCorniceBracket {
			Width = Width,
			Drop = Drop,
			Projection = Projection,
			Field = Field
		};
	}
}

// A cornice is a STACK, never one moulding, and the stack is what an author picks. Every dimension that would
// otherwise land on the wall sheet lives here instead: one name on the elevation, the whole entablature in the kit.
public sealed class ArchCorniceStyle {
	public string Name { get; set; } = "cornice";
	public string Detail { get; set; } = "";
	public List<ArchCorniceCourse> Courses { get; set; } = new();
	public ArchCornicePier Pier { get; set; } = new();
	public ArchCorniceBracket Bracket { get; set; } = new();

	public bool Stands => Courses.Any( course => course.Stands );

	public float Rise => Courses.Where( course => course.Stands ).Sum( course => course.Rise );

	public float Projection => Courses.Count == 0 ? 0f : Courses.Max( course => MathF.Max( 0f, course.Projection ) );

	public ArchCorniceStyle Copy() {
		return new ArchCorniceStyle {
			Name = Name,
			Detail = Detail,
			Courses = Courses.Select( course => course.Copy() ).ToList(),
			Pier = Pier.Copy(),
			Bracket = Bracket.Copy()
		};
	}
}