Code/Core/Contexts/ExecutionContext/ExecutionContext.Persistence.cs
using System.Runtime.CompilerServices;

namespace Nodebox;

public partial class ExecutionContext {
    public PersistentStore Store { get; set; } = new();
    public class PersistentStore {
        private readonly ConditionalWeakTable<Node, List<object>> _inputs = [];
        private readonly ConditionalWeakTable<Node, List<object>> _outputs = [];

        private List<object> GetInputsFor(Node node) => _inputs.GetOrAdd(
            node,
            [.. node.InputPins.Select(x => TypeLibrary.GetType(x.Type).CreateDefault())]
        );

        private List<object> GetOutputsFor(Node node) => _outputs.GetOrAdd(
            node,
            [.. node.OutputPins.Select(x => TypeLibrary.GetType(x.Type).CreateDefault())]
        );

        public View this[Node node] {
            get => new(this, node);
        }

        public readonly ref struct View(PersistentStore store, Node node) {
            private readonly PersistentStore _store = store;
            private readonly Node _node = node;

            private object GetInputObject(Type type, int index) {
                ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, _node.InputPins.Count, nameof(index));
                // Log.Info($"{_node}[{index}] = {_node.inputValues[index]} ({_node.InputWires[index].Count})");
                if (_node.InputWires[index].Count == 0) {
                    return _node.inputValues[index];
                }

                var data = _store.GetInputsFor(_node);
                if (data.Count <= index) { data.Resize(index + 1, (_) => TypeLibrary.GetType(type).CreateDefault()); }
                return data[index];
            }
            public T GetInput<T>(int index) => (T)GetInputObject(typeof(T), index);

            private object GetOutputObject(int index) {
                ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, _node.OutputPins.Count, nameof(index));
                return _store.GetOutputsFor(_node)[index];
            }
            public T GetOutput<T>(int index) => (T)GetOutputObject(index);

            public void SetInput<T>(int index, T value) {
                ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, _node.InputPins.Count, nameof(index));
                if (!value.GetType().IsAssignableTo(_node.InputPins[index].Type)) {
                    throw new InvalidCastException($"{value} is not assignable to {DisplayInfo.ForGenericType(_node.InputPins[index].Type).Name}");
                }

                var data = _store.GetInputsFor(_node);
                if (data.Count <= index) { data.Resize(index + 1, (_) => TypeLibrary.GetType<T>().CreateDefault()); }
                data[index] = value;
            }
            public void SetOutput<T>(int index, T value) {
                ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, _node.OutputPins.Count, nameof(index));
                if (!value.GetType().IsAssignableTo(_node.OutputPins[index].Type)) {
                    throw new InvalidCastException($"{value} is not assignable to {DisplayInfo.ForGenericType(_node.OutputPins[index].Type).Name}");
                }

                var data = _store.GetOutputsFor(_node);
                if (data.Count <= index) { data.Resize(index + 1, (_) => TypeLibrary.GetType<T>().CreateDefault()); }
                data[index] = value;
            }
        }
    }



}