Park/Paths/PathFurniture.cs
using HC3.Persistence;
using HC3.Terrain;
using HC3.UI;

namespace HC3;

/// <summary>
/// Specifies the available categories of furniture items.
/// </summary>
public enum FurnitureType
{
	[Title( "Uncategorised" )]
	Uncategorised = 0,

	[Title( "Bins" ), Icon( "delete" )]
	Bin,

	[Title( "Benches" ), Icon( "chair_alt" )]
	Bench,

	[Title( "Lamps" ), Icon( "tungsten" )]
	Lamp,

	[Title( "Signs" ), Icon( "assignment" )]
	Sign,

	[Title( "Other" ), Icon( "other_houses" )]
	Other
}

public partial class PathFurniture : Component, IPlacementObject, IGridObjectEvent, IInspectable, IPathBlocker
{
	private static float PathOffset => 0.7f;

	[Property] public FurnitureType FurnitureType { get; set; } = FurnitureType.Uncategorised;

	/// <summary>
	/// Cost to place this in the world.
	/// </summary>
	[Property, Feature( "Building" )] public int Cost { get; set; } = 15;

	[Property, Feature( "Building" ), Group( "Display" )] public string Title { get; set; } = "Furniture";
	[Property, Feature( "Building" ), Group( "Display" ), ImageAssetPath] public string Thumbnail { get; set; } = "textures/thumbnails/missing_thumbnail.png";

	public Group Group => new( "Furniture", FurnitureType.ToString() );

	[Property, Feature( "Masks" )]
	public PathMask BlockedDirections { get; set; }

	[Property, Feature( "Masks" )]
	public PathMask BlockedNavigation { get; set; }

	[RequireComponent]
	public GridObject GridObject { get; private set; }

	protected override void OnValidate()
	{
		GridObject ??= GetOrAddComponent<GridObject>( false );
		GridObject.Enabled = false;
	}

	/// <summary>
	/// Check whether or not this building has been placed or is currently being placed.
	/// </summary>
	public bool IsPlaced
	{
		get => _isPlaced;
		set
		{
			_isPlaced = value;
			GridObject.Enabled = value;
		}
	}

	private bool _isPlaced = false;

	public TileEdge TileEdge { get; set; }

	protected override void OnAwake()
	{
		if ( GameObject.IsPrefabInstanceRoot )
		{
			PrefabSource = GameObject.PrefabInstanceSource;
		}
	}

	void IGridObjectEvent.NeighborsChanged( GridCell cell )
	{
		int level = GridManager.FloorWorldHeightToGrid( WorldPosition.z );
		var path = cell?.GetComponent<Path>( level );
		if ( !IsAllowed( path, TileEdge ) )
		{
			ParkManager.Instance.DestroyObject( this );
		}
	}

	Window IInspectable.Select()
	{
		var building = this;

		var inspector = new DecorationInspector();
		inspector.Building = building;

		return inspector;
	}

	public bool IsAllowed( Path path, TileEdge edge )
	{
		if ( !path.IsValid() ) return false;

		// no stairs
		if ( path.IsStairs ) return false;

		if ( FurnitureType is FurnitureType.Sign )
		{
			// require a walkable edge
			if ( !path.IsWalkable( edge, GridCell.ConnectionFlags.RequirePlaced ) ) return false;
		}
		else
		{
			// require an unwalkable edge
			if ( path.IsWalkable( edge, GridCell.ConnectionFlags.RequirePlaced ) ) return false;
		}

		// already something there
		if ( path.GetComponentsInChildren<PathFurniture>().Any( x => x != this && x.TileEdge == edge ) )
			return false;

		return true;
	}

	public static float GetPathOffset( FurnitureType furnitureType )
	{
		if ( furnitureType is FurnitureType.Sign ) return 0.9f;

		return PathOffset;
	}
}

file sealed class PathFurnitureSaveData : SpawnedPrefabSaveData<PathFurniture, PathFurniture.SaveData>
{
	public override string PropertyName => "PathFurniture";
	public override int PropertyOrder => 1;
}