using System.Runtime.CompilerServices;
using IFSEngine.Model;
namespace IFSRenderer.Shared;
/// <summary>A node's position on the graph canvas.</summary>
public readonly record struct NodePosition(double X, double Y);
/// <summary>
/// Side-table of node-graph positions, keyed by <see cref="Iterator"/>.
/// </summary>
/// <remarks>
/// Node positions are deliberately NOT part of <see cref="IFSEngine"/>'s model - the engine
/// has no concept of a canvas. The WPF app keeps them in exactly this shape
/// (<c>WpfDisplay/Helper/IteratorExtensions.cs</c>), and the on-disk format pairs them to
/// iterators by position in the <c>Nodes</c> array. Mirroring that here keeps
/// <see cref="IfsNodesSerializer"/> free of any UI dependency.
/// <para>
/// A <see cref="ConditionalWeakTable{TKey,TValue}"/> means positions die with their iterator
/// and never keep a discarded fractal alive.
/// </para>
/// </remarks>
public static class IteratorPositions
{
private static readonly ConditionalWeakTable<Iterator, object> _positions = [];
public static NodePosition? GetPosition(this Iterator iterator) =>
_positions.TryGetValue(iterator, out object boxed) ? (NodePosition)boxed : null;
public static void SetPosition(this Iterator iterator, NodePosition position) =>
_positions.AddOrUpdate(iterator, position);
public static void ClearPosition(this Iterator iterator) => _positions.Remove(iterator);
}