// Serialization // Copyright 2018-2024 Kybernetik //
#if UNITY_EDITOR
using System;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;
// Shared File Last Modified: 2023-08-12.
namespace Animancer.Editor
// namespace InspectorGadgets.Editor
{
    /// [Editor-Only] Various serialization utilities.
    public partial class Serialization
    {
        /// [Editor-Only]
        /// Directly serializing an  reference doesn't always work (such as with scene
        /// objects when entering Play Mode), so this class also serializes their instance ID and uses that if the
        /// direct reference fails.
        /// 
        [Serializable]
        public class ObjectReference
        {
            /************************************************************************************************************************/
            [SerializeField] private Object _Object;
            [SerializeField] private int _InstanceID;
            /************************************************************************************************************************/
            /// The referenced .
            public Object Object
            {
                get
                {
                    Initialize();
                    return _Object;
                }
            }
            /// The .
            public int InstanceID => _InstanceID;
            /************************************************************************************************************************/
            /// 
            /// Creates a new  which wraps the specified
            /// .
            /// 
            public ObjectReference(Object obj)
            {
                _Object = obj;
                if (obj != null)
                    _InstanceID = obj.GetInstanceID();
            }
            /************************************************************************************************************************/
            private void Initialize()
            {
                if (_Object == null)
                    _Object = EditorUtility.InstanceIDToObject(_InstanceID);
                else
                    _InstanceID = _Object.GetInstanceID();
            }
            /************************************************************************************************************************/
            /// 
            /// Creates a new  which wraps the specified
            /// .
            /// 
            public static implicit operator ObjectReference(Object obj)
                => new(obj);
            /// Returns the target .
            public static implicit operator Object(ObjectReference reference)
                => reference.Object;
            /************************************************************************************************************************/
            /// Creates a new array of s representing the `objects`.
            public static ObjectReference[] Convert(params Object[] objects)
            {
                var references = new ObjectReference[objects.Length];
                for (int i = 0; i < objects.Length; i++)
                    references[i] = objects[i];
                return references;
            }
            /// 
            /// Creates a new array of s containing the target  of each
            /// of the `references`.
            /// 
            public static Object[] Convert(params ObjectReference[] references)
            {
                var objects = new Object[references.Length];
                for (int i = 0; i < references.Length; i++)
                    objects[i] = references[i];
                return objects;
            }
            /************************************************************************************************************************/
            /// Indicates whether both arrays refer to the same set of objects.
            public static bool AreSameObjects(ObjectReference[] references, Object[] objects)
            {
                if (references == null)
                    return objects == null;
                if (objects == null)
                    return false;
                if (references.Length != objects.Length)
                    return false;
                for (int i = 0; i < references.Length; i++)
                {
                    if (references[i] != objects[i])
                        return false;
                }
                return true;
            }
            /************************************************************************************************************************/
            /// Returns a string describing this object.
            public override string ToString()
                => $"Serialization.ObjectReference [{_InstanceID}] {_Object}";
            /************************************************************************************************************************/
        }
        /************************************************************************************************************************/
        /// Returns true if the `reference` and  are not null.
        public static bool IsValid(this ObjectReference reference)
            => reference?.Object != null;
        /************************************************************************************************************************/
    }
}
#endif