Editor/InteriorLayoutBuilder/RoomLayoutTool.FloorCutouts.cs
using System;
using System.Linq;
using Editor;
using Sandbox;

namespace ReusableRoomLayout;

public sealed partial class RoomLayoutTool
{
	private RoomLayoutFloorCutout SelectedFloorCutout()
	{
		return selectedFloorCutoutId == 0
			? null
			: document.FloorCutouts.FirstOrDefault( cutout => cutout.Id == selectedFloorCutoutId );
	}

	private void HandleFloorCutoutMouse( Vector2 cursor, bool selectedLayoutAtCursor )
	{
		if ( Gizmo.WasLeftMousePressed )
		{
			if ( TryFindFloorCutout( cursor, out var cutout ) )
			{
				SelectFloorCutout( cutout );
				movingFloorCutout = true;
				BeginLayoutEdit();
				dragStart = cursor;
				moveStartBounds = cutout.Bounds;
				return;
			}

			if ( selectedLayoutAtCursor )
			{
				return;
			}

			selectedRoomId = 0;
			selectedDoorId = 0;
			selectedWindowId = 0;
			selectedCorridorId = 0;
			selectedFloorCutoutId = 0;
			drawingFloorCutout = true;
			dragStart = cursor;
			dragCurrent = cursor;
		}

		if ( drawingFloorCutout )
		{
			dragCurrent = cursor;
			if ( Gizmo.WasLeftMouseReleased )
			{
				CommitDrawnFloorCutout();
			}
			return;
		}

		if ( movingFloorCutout )
		{
			MoveSelectedFloorCutoutByDrag( cursor );
			if ( Gizmo.WasLeftMouseReleased )
			{
				movingFloorCutout = false;
				CommitLayoutEdit();
			}
		}
	}

	private void CommitDrawnFloorCutout()
	{
		var bounds = SnapRect( RoomLayoutRect.FromPoints( dragStart, dragCurrent ) );
		drawingFloorCutout = false;

		if ( bounds.Width < document.Settings.GridSize || bounds.Height < document.Settings.GridSize )
		{
			return;
		}

		var cutout = new RoomLayoutFloorCutout
		{
			Id = document.AllocateId(),
			Floor = activeFloor,
			Name = $"Floor Cutout {document.FloorCutouts.Count + 1}",
			Bounds = bounds
		};

		PushLayoutUndo();
		document.FloorCutouts.Add( cutout );
		SelectFloorCutout( cutout );
		CommitLayoutChange();
	}

	private void MoveSelectedFloorCutoutByDrag( Vector2 cursor )
	{
		if ( SelectedFloorCutout() is not { } cutout )
		{
			movingFloorCutout = false;
			return;
		}

		var delta = cursor - dragStart;
		cutout.Bounds = SnapRect( moveStartBounds.MovedBy( delta ) );
	}

	private void SelectFloorCutout( RoomLayoutFloorCutout cutout )
	{
		selectedRoomId = 0;
		selectedDoorId = 0;
		selectedWindowId = 0;
		selectedCorridorId = 0;
		selectedFloorCutoutId = cutout.Id;
		SetActiveFloorFromSelection();
	}

	private bool TryFindFloorCutout( Vector2 point, out RoomLayoutFloorCutout cutout )
	{
		cutout = document.FloorCutouts.LastOrDefault( candidate => IsActiveFloor( candidate ) && candidate.Bounds.Contains( point ) );
		return cutout is not null;
	}
}