Editor/InteriorLayoutBuilder/RoomLayoutGeometryBuilder.CorridorBoundaries.cs
using System.Collections.Generic;
using Sandbox;

namespace ReusableRoomLayout;

public sealed partial class RoomLayoutGeometryBuilder
{
	private static void BuildCorridorBoundaryWalls(
		Scene scene,
		GameObject frameParent,
		RoomLayoutDocument document,
		ICollection<RoomLayoutSolidSlab> solidSlabs,
		RoomLayoutSettings settings,
		RoomLayoutCorridor corridor,
		IReadOnlyList<Vector2> points,
		IReadOnlyCollection<RoomLayoutRect> footprintRects,
		DoorPoint start,
		DoorPoint end,
		float width,
		string outerWallMaterialPath,
		string innerWallMaterialPath,
		string capMaterialPath,
		string baseboardMaterialPath,
		float outerWallMaterialScale,
		float innerWallMaterialScale,
		float capMaterialScale,
		float baseboardMaterialScale )
	{
		if ( footprintRects.Count == 0 )
		{
			return;
		}

		var xs = new List<float>();
		var ys = new List<float>();
		foreach ( var rect in footprintRects )
		{
			AddUniqueCoordinate( xs, rect.X );
			AddUniqueCoordinate( xs, rect.X + rect.Width );
			AddUniqueCoordinate( ys, rect.Y );
			AddUniqueCoordinate( ys, rect.Y + rect.Height );
		}

		xs.Sort();
		ys.Sort();

		var cells = CorridorFootprintCells( footprintRects, xs, ys );
		var wallIndex = 0;
		for ( var x = 0; x < xs.Count - 1; x++ )
		{
			for ( var y = 0; y < ys.Count - 1; y++ )
			{
				if ( !cells[x, y] )
				{
					continue;
				}

				var minX = xs[x];
				var maxX = xs[x + 1];
				var minY = ys[y];
				var maxY = ys[y + 1];

				if ( y == 0 || !cells[x, y - 1] )
				{
					wallIndex = BuildCorridorBoundaryWall(
						solidSlabs,
						document,
						settings,
						corridor,
						points,
						wallIndex,
						new CorridorBoundaryEdge( minX, maxX, minY, true, -1 ),
						start,
						end,
						width,
						outerWallMaterialPath,
						innerWallMaterialPath,
						capMaterialPath,
						baseboardMaterialPath,
						outerWallMaterialScale,
						innerWallMaterialScale,
						capMaterialScale,
						baseboardMaterialScale );
				}

				if ( y == ys.Count - 2 || !cells[x, y + 1] )
				{
					wallIndex = BuildCorridorBoundaryWall(
						solidSlabs,
						document,
						settings,
						corridor,
						points,
						wallIndex,
						new CorridorBoundaryEdge( minX, maxX, maxY, true, 1 ),
						start,
						end,
						width,
						outerWallMaterialPath,
						innerWallMaterialPath,
						capMaterialPath,
						baseboardMaterialPath,
						outerWallMaterialScale,
						innerWallMaterialScale,
						capMaterialScale,
						baseboardMaterialScale );
				}

				if ( x == 0 || !cells[x - 1, y] )
				{
					wallIndex = BuildCorridorBoundaryWall(
						solidSlabs,
						document,
						settings,
						corridor,
						points,
						wallIndex,
						new CorridorBoundaryEdge( minY, maxY, minX, false, -1 ),
						start,
						end,
						width,
						outerWallMaterialPath,
						innerWallMaterialPath,
						capMaterialPath,
						baseboardMaterialPath,
						outerWallMaterialScale,
						innerWallMaterialScale,
						capMaterialScale,
						baseboardMaterialScale );
				}

				if ( x == xs.Count - 2 || !cells[x + 1, y] )
				{
					wallIndex = BuildCorridorBoundaryWall(
						solidSlabs,
						document,
						settings,
						corridor,
						points,
						wallIndex,
						new CorridorBoundaryEdge( minY, maxY, maxX, false, 1 ),
						start,
						end,
						width,
						outerWallMaterialPath,
						innerWallMaterialPath,
						capMaterialPath,
						baseboardMaterialPath,
						outerWallMaterialScale,
						innerWallMaterialScale,
						capMaterialScale,
						baseboardMaterialScale );
				}
			}
		}

		BuildCorridorBoundaryCorners(
			solidSlabs,
			settings,
			corridor.Id,
			wallIndex,
			cells,
			xs,
			ys,
			start,
			end,
			width,
			outerWallMaterialPath,
			innerWallMaterialPath,
			capMaterialPath,
			baseboardMaterialPath,
			outerWallMaterialScale,
			innerWallMaterialScale,
			capMaterialScale,
			baseboardMaterialScale );

		BuildCorridorOpeningFrames( scene, frameParent, settings, document, corridor, points, width );
	}

	private static bool[,] CorridorFootprintCells(
		IReadOnlyCollection<RoomLayoutRect> footprintRects,
		IReadOnlyList<float> xs,
		IReadOnlyList<float> ys )
	{
		var cells = new bool[xs.Count - 1, ys.Count - 1];
		for ( var x = 0; x < xs.Count - 1; x++ )
		{
			for ( var y = 0; y < ys.Count - 1; y++ )
			{
				var center = new Vector2( (xs[x] + xs[x + 1]) * 0.5f, (ys[y] + ys[y + 1]) * 0.5f );
				cells[x, y] = CorridorFootprintContains( footprintRects, center );
			}
		}

		return cells;
	}

	private static bool CorridorFootprintContains( IReadOnlyCollection<RoomLayoutRect> footprintRects, Vector2 point )
	{
		foreach ( var rect in footprintRects )
		{
			if ( point.x >= rect.X && point.x <= rect.X + rect.Width &&
				point.y >= rect.Y && point.y <= rect.Y + rect.Height )
			{
				return true;
			}
		}

		return false;
	}

	private static bool IsCorridorCellCovered( bool[,] cells, int x, int y )
	{
		return x >= 0 &&
			y >= 0 &&
			x < cells.GetLength( 0 ) &&
			y < cells.GetLength( 1 ) &&
			cells[x, y];
	}

}