Editor/Tileset/TilesetTools/Tools/EraseTileTool.cs
using Editor;
using Sandbox;
using System.Collections.Generic;

namespace SpriteTools.TilesetTool.Tools;

/// <summary>
/// Used to erase tiles from the selected layer.
/// </summary>
[Title( "Erase" )]
[Icon( "delete" )]
[Alias( "tileset-tools.erase-tool" )]
[Group( "2" )]
[Order( 1 )]
public class EraserTileTool : BaseTileTool
{
	public EraserTileTool ( TilesetTool parent ) : base( parent ) { }

	/// <summary>
	/// The size of the Brush when Erasing.
	/// </summary>
	[Group( "Eraser Tool" ), Property, Range( 1, 12 ), Step( 1 )] public int BrushSize { get; set; } = 1;

	/// <summary>
	/// Whether the Brush is round or square.
	/// </summary>
	[Group( "Eraser Tool" ), Property] public bool IsRound { get; set; } = false;

	bool isErasing = false;
	List<Vector2Int> positions;

	public override void OnUpdate ()
	{
		if ( !CanUseTool() ) return;

		var pos = GetGizmoPos();
		Parent._sceneObject.RenderingEnabled = false;

		var tile = TilesetTool.Active.SelectedTile;
		positions = new();
		if ( tile.Size.x > 1 || tile.Size.y > 1 )
		{
			for ( int i = 0; i < tile.Size.x; i++ )
			{
				for ( int j = 0; j < tile.Size.y; j++ )
				{
					positions.Add( new Vector2Int( i, -j ) );
				}
			}
		}
		else if ( IsRound )
		{
			var size = ( BrushSize - 0.9f ) * 2;
			var center = new Vector2Int( (int)( size / 2f ), (int)( size / 2f ) );
			for ( int i = 0; i < size * 2; i++ )
			{
				for ( int j = 0; j < size * 2; j++ )
				{
					var offset = new Vector2Int( i, j ) - center;
					if ( offset.LengthSquared <= ( size / 2 ) * ( size / 2 ) )
					{
						positions.Add( offset );
					}
				}
			}
		}
		else
		{
			Vector2Int startPos = new Vector2Int( -BrushSize / 2, -BrushSize / 2 );
			for ( int i = 0; i < BrushSize; i++ )
			{
				for ( int j = 0; j < BrushSize; j++ )
				{
					positions.Add( new Vector2Int( i, j ) + startPos );
				}
			}
		}

		var tileSize = Parent.SelectedLayer.TilesetResource.GetTileSize();
		var tilePos = ( pos - Parent.SelectedComponent.WorldPosition ) / tileSize;
		if ( Gizmo.IsLeftMouseDown )
		{
			if ( _componentUndoScope is null )
			{
				_componentUndoScope = SceneEditorSession.Active.UndoScope( "Erase Tiles" ).WithComponentChanges( Parent.SelectedComponent ).Push();
			}
			var brush = AutotileBrush;
			foreach ( var ppos in positions )
			{
				if ( brush is null )
				{
					Parent.EraseTile( tilePos + ppos );
				}
				else
				{
					Parent.EraseAutoTile( brush, (Vector2Int)tilePos + ppos, false );
				}
			}

			if ( brush is not null )
			{
				foreach ( var ppos in positions )
				{
					Parent.SelectedLayer.UpdateAutotile( brush.Id, (Vector2Int)tilePos + ppos, true );
				}
			}
			isErasing = true;
		}
		else if ( isErasing )
		{
			_componentUndoScope?.Dispose();
			_componentUndoScope = null;
			isErasing = false;
		}

		using ( Gizmo.Scope( "eraser" ) )
		{
			Gizmo.Draw.Color = Color.Red.WithAlpha( 0.5f );
			foreach ( var ppos in positions )
			{
				var p = ppos * tileSize + tilePos * tileSize;
				var pp = Vector3.Up * 200 + (Vector3)p;
				Gizmo.Draw.SolidBox( new BBox( pp, pp + (Vector3)tileSize ) );
			}
		}
	}

	[Shortcut( "tileset-tools.erase-tool", "e", typeof( SceneViewportWidget ) )]
	public static void ActivateSubTool ()
	{
		if ( EditorToolManager.CurrentModeName != nameof( TilesetTool ) ) return;
		EditorToolManager.SetSubTool( nameof( EraserTileTool ) );
	}
}