using System;
using System.Collections.Generic;
using System.Linq;
using PrefsGUI.Kvs;
using UnityEngine;
using UnityEngine.Pool;
using UnityEngine.Serialization;
namespace PrefsGUI
{
///
/// Origin of Prefs*
///
public abstract partial class PrefsParam : ISerializationCallbackReceiver
{
#region Static
private static readonly HashSet All = new();
private static readonly Dictionary AllDic = new();
private static readonly Dictionary KeyToOnValueChangedCallback = new();
public static event Action onRegisterPrefsParam;
public static IReadOnlyCollection all => All;
public static IReadOnlyDictionary allDic => AllDic;
#endregion
[SerializeField]
[FormerlySerializedAs("key")]
private string _key;
public string key
{
get => _key;
set
{
if (_key != value && !string.IsNullOrEmpty(value))
{
var old = _key;
_key = value;
OnKeyChanged(old, _key);
}
}
}
protected PrefsParam(string key) => this.key = key;
public virtual void Delete()
{
ClearCache();
PrefsKvs.DeleteKey(key);
}
// 保持している一時変数などを初期化する
// EditorのPlayModeが変化したときに呼ばれる
public virtual void Reset()
{
ClearSync();
ClearCache();
}
public virtual void ClearCache()
{
}
protected virtual void OnKeyChanged(string oldKey, string newKey)
{
if (!string.IsNullOrEmpty(oldKey))
{
AllDic.Remove(oldKey);
}
Register();
}
protected virtual void OnValueChanged()
{
if (KeyToOnValueChangedCallback.TryGetValue(key, out var action))
{
action?.Invoke();
}
}
public void RegisterValueChangedCallback(Action callback)
{
KeyToOnValueChangedCallback.TryGetValue(key, out var action);
KeyToOnValueChangedCallback[key] = action + callback;
}
public void UnregisterValueChangedCallback(Action callback)
{
if (!KeyToOnValueChangedCallback.TryGetValue(key, out var action)) return;
KeyToOnValueChangedCallback[key] = action - callback;
}
#region abstract
public abstract Type GetInnerType();
public abstract bool IsDefault { get; }
public abstract void SetCurrentToDefault();
public abstract void ResetToDefault();
public abstract IPrefsInnerAccessor GetInnerAccessor();
#endregion
#region RegistAllInstance
#region ISerializationCallbackReceiver
public void OnBeforeSerialize() {}
// To Register Array/List In Inspector. constructor is not called.
// Inspectorで値を変えても呼ばれる。Key、DefaultValueが更新されてる可能性がある
public virtual void OnAfterDeserialize()
{
// _key が書き換えられてる場合があるのでOnKeyChange()を直接呼ぶ
OnKeyChanged(null, _key);
}
#endregion
private void Register()
{
if (string.IsNullOrEmpty(key)) return;
if (AllDic.TryGetValue(key, out var prev))
{
All.Remove(prev);
}
var alreadyExist = !All.Add(this);
if (alreadyExist)
{
using var _ = ListPool.Get(out var keys);
keys.AddRange(AllDic.Where(pair => pair.Value == this).Select(pair => pair.Key));
foreach(var removeKey in keys)
{
AllDic.Remove(removeKey);
}
}
AllDic[key] = this;
onRegisterPrefsParam?.Invoke(this);
}
#endregion
}
}