using GFramework.Core.Abstractions.Events;
using GFramework.Core.Abstractions.Property;
using GFramework.Core.Abstractions.StateManagement;
using GFramework.Core.Events;
namespace GFramework.Core.StateManagement;
///
/// Store 选择结果的只读绑定视图。
/// 该类型将整棵状态树上的订阅转换为局部状态片段的订阅,
/// 使现有依赖 IReadonlyBindableProperty 的 UI 代码能够平滑复用到 Store 场景中。
///
/// 源状态类型。
/// 投影后的局部状态类型。
public sealed class StoreSelection : IReadonlyBindableProperty
{
///
/// 用于判断选择结果是否真正变化的比较器。
///
private readonly IEqualityComparer _comparer;
///
/// 当前监听器列表。
///
private readonly List _listeners = [];
///
/// 保护监听器集合和底层 Store 订阅句柄的同步锁。
///
private readonly object _lock = new();
///
/// 负责从完整状态中投影出局部状态的选择器。
///
private readonly Func _selector;
///
/// 源 Store。
///
private readonly IReadonlyStore _store;
///
/// 当前已缓存的选择结果。
/// 该缓存仅在存在监听器时用于变化比较和事件通知,直接读取 Value 时始终以 Store 当前状态为准。
///
private TSelected _currentValue = default!;
///
/// 连接到底层 Store 的订阅句柄。
/// 仅当当前存在至少一个监听器时才会建立该订阅,以减少长期闲置对象造成的引用链。
///
private IUnRegister? _storeSubscription;
///
/// 初始化一个新的 Store 选择视图。
///
/// 源 Store。
/// 状态选择器。
/// 选择结果比较器;未提供时使用 。
///
/// 当 或 为 时抛出。
///
public StoreSelection(
IReadonlyStore store,
Func selector,
IEqualityComparer? comparer = null)
{
_store = store ?? throw new ArgumentNullException(nameof(store));
_selector = selector ?? throw new ArgumentNullException(nameof(selector));
_comparer = comparer ?? EqualityComparer.Default;
}
///
/// 获取当前选择结果。
///
public TSelected Value => _selector(_store.State);
///
/// 将无参事件监听适配为带选择结果参数的监听。
///
/// 无参事件监听器。
/// 用于取消订阅的句柄。
IUnRegister IEvent.Register(Action onEvent)
{
ArgumentNullException.ThrowIfNull(onEvent);
return Register(_ => onEvent());
}
///
/// 注册选择结果变化监听器。
///
/// 选择结果变化时的回调。
/// 用于取消订阅的句柄。
/// 当 为 时抛出。
public IUnRegister Register(Action onValueChanged)
{
ArgumentNullException.ThrowIfNull(onValueChanged);
var subscription = new SelectionListenerSubscription(onValueChanged);
var shouldAttach = false;
lock (_lock)
{
if (_listeners.Count == 0)
{
_currentValue = Value;
shouldAttach = true;
}
_listeners.Add(subscription);
}
if (shouldAttach)
{
AttachToStore();
}
return new DefaultUnRegister(() => UnRegister(subscription));
}
///
/// 注册选择结果变化监听器,并立即回放当前值。
///
/// 选择结果变化时的回调。
/// 用于取消订阅的句柄。
/// 当 为 时抛出。
public IUnRegister RegisterWithInitValue(Action action)
{
ArgumentNullException.ThrowIfNull(action);
var subscription = new SelectionListenerSubscription(action)
{
IsActive = false
};
var currentValue = Value;
TSelected? pendingValue = default;
var hasPendingValue = false;
lock (_lock)
{
if (_listeners.Count == 0)
{
_currentValue = currentValue;
}
_listeners.Add(subscription);
}
EnsureAttached();
try
{
action(currentValue);
}
catch
{
UnRegister(subscription);
throw;
}
lock (_lock)
{
if (!subscription.IsSubscribed)
{
return new DefaultUnRegister(() => { });
}
subscription.IsActive = true;
if (subscription.HasPendingValue)
{
pendingValue = subscription.PendingValue;
hasPendingValue = true;
subscription.PendingValue = default!;
subscription.HasPendingValue = false;
}
}
if (hasPendingValue)
{
action(pendingValue!);
}
return new DefaultUnRegister(() => UnRegister(subscription));
}
///
/// 取消注册选择结果变化监听器。
///
/// 需要移除的监听器。
/// 当 为 时抛出。
public void UnRegister(Action onValueChanged)
{
ArgumentNullException.ThrowIfNull(onValueChanged);
SelectionListenerSubscription? subscriptionToRemove = null;
lock (_lock)
{
var index = _listeners.FindIndex(subscription => subscription.Listener == onValueChanged);
if (index < 0)
{
return;
}
subscriptionToRemove = _listeners[index];
}
if (subscriptionToRemove != null)
{
UnRegister(subscriptionToRemove);
}
}
///
/// 确保当前选择视图已连接到底层 Store。
///
private void EnsureAttached()
{
var shouldAttach = false;
lock (_lock)
{
shouldAttach = _listeners.Count > 0 && _storeSubscription == null;
}
if (shouldAttach)
{
AttachToStore();
}
}
///
/// 取消注册一个精确的选择结果监听器。
///
/// 需要移除的订阅对象。
private void UnRegister(SelectionListenerSubscription subscriptionToRemove)
{
IUnRegister? storeSubscription = null;
lock (_lock)
{
subscriptionToRemove.IsSubscribed = false;
_listeners.Remove(subscriptionToRemove);
if (_listeners.Count == 0 && _storeSubscription != null)
{
storeSubscription = _storeSubscription;
_storeSubscription = null;
}
}
storeSubscription?.UnRegister();
}
///
/// 将当前选择视图连接到底层 Store。
///
private void AttachToStore()
{
var subscription = _store.Subscribe(OnStoreChanged);
Action[] listenersSnapshot = Array.Empty>();
var latestValue = Value;
var shouldNotify = false;
lock (_lock)
{
// 如果在建立底层订阅期间所有监听器都已被移除,则立即释放刚刚建立的订阅,
// 避免选择视图在无人监听时继续被 Store 保持引用。
if (_listeners.Count == 0)
{
subscription.UnRegister();
return;
}
if (_storeSubscription != null)
{
subscription.UnRegister();
return;
}
_storeSubscription = subscription;
if (!_comparer.Equals(_currentValue, latestValue))
{
_currentValue = latestValue;
foreach (var listener in _listeners)
{
if (!listener.IsSubscribed)
{
continue;
}
if (listener.IsActive)
{
continue;
}
listener.PendingValue = latestValue;
listener.HasPendingValue = true;
}
listenersSnapshot = _listeners
.Where(listener => listener.IsSubscribed && listener.IsActive)
.Select(listener => listener.Listener)
.ToArray();
shouldNotify = listenersSnapshot.Length > 0;
}
}
if (!shouldNotify)
{
return;
}
foreach (var listener in listenersSnapshot)
{
listener(latestValue);
}
}
///
/// 响应底层 Store 的状态变化,并在选中片段真正变化时通知监听器。
///
/// 新的完整状态。
private void OnStoreChanged(TState state)
{
var selectedValue = _selector(state);
Action[] listenersSnapshot = Array.Empty>();
lock (_lock)
{
if (_listeners.Count == 0 || _comparer.Equals(_currentValue, selectedValue))
{
return;
}
_currentValue = selectedValue;
foreach (var listener in _listeners)
{
if (!listener.IsSubscribed)
{
continue;
}
if (listener.IsActive)
{
continue;
}
listener.PendingValue = selectedValue;
listener.HasPendingValue = true;
}
listenersSnapshot = _listeners
.Where(listener => listener.IsSubscribed && listener.IsActive)
.Select(listener => listener.Listener)
.ToArray();
}
foreach (var listener in listenersSnapshot)
{
listener(selectedValue);
}
}
///
/// 表示一个选择结果监听订阅。
/// 该对象用于保证 RegisterWithInitValue 在初始化回放与后续状态变化之间不会漏掉最近一次更新。
///
private sealed class SelectionListenerSubscription(Action listener)
{
///
/// 获取订阅回调。
///
public Action Listener { get; } = listener;
///
/// 获取或设置订阅是否已激活。
///
public bool IsActive { get; set; } = true;
///
/// 获取或设置订阅是否仍然有效。
///
public bool IsSubscribed { get; set; } = true;
///
/// 获取或设置是否存在待补发的局部状态值。
///
public bool HasPendingValue { get; set; }
///
/// 获取或设置初始化阶段积累的最新局部状态值。
///
public TSelected PendingValue { get; set; } = default!;
}
}