namespace XGame.Framework.Asset
{
    /// <summary>
    /// 已加载资源的基类
    /// </summary>
    internal abstract class Asset
    {
        /// <summary>
        /// 资源路径
        /// </summary>
        public string AddressableName { get; private set; }
        /// <summary>
        /// 是否可克隆
        /// </summary>
        public bool IsCloneable { get; protected set; }
        /// <summary>
        /// 资源对象
        /// </summary>
        private object _source;
        /// <summary>
        /// 资源对象
        /// </summary>
        public object Source { get => _source; set { _source = value; OnSetSource(); } }
        //public LoadState State { get; internal set; } = LoadState.None;

        /// <summary>
        /// 资源引用次数
        /// </summary>
        public int Reference { private set; get; }
        /// <summary>
        /// 预加载标记
        /// </summary>
        public bool IsPreload { set; get; }

        /// <summary>
        /// 时间戳
        /// </summary>
        AssetTimestamp timestamp;

        /// <summary>
        /// 时间戳
        /// </summary>
        public AssetTimestamp Timestamp => timestamp;
        public void Init(string assetName)
        {
            timestamp.createTime = BinaryTimeStamp();
            AddressableName = assetName;
            IsCloneable = false;
            IsPreload = false;
            OnInit();
        }
        public abstract AssetType AssetType { get; }
        /// <summary>
        /// 克隆对象，然后记录引用次数
        /// 不可克隆的对象返回的是资源本体
        /// </summary>
        /// <returns></returns>
        public abstract object Clone();
        protected abstract void OnInit();
        protected abstract void OnSetSource();
        protected abstract void OnRetain();
        protected abstract void OnRelease();

        protected abstract void OnDispose();

        public void Retain()
        {
            timestamp.lastRequest = BinaryTimeStamp();
            Reference++;
            //有引用，取消预加载标记
            IsPreload = false;
            OnRetain();
            //Log.Debug(string.Format("Asset Retain. Name:{0} reference:{1}  time:{2}", AddressableName, Reference, System.DateTime.FromBinary(timestamp.zeroReference)));
        }
        /// <summary>
        /// 引用归零时返回true
        /// </summary>
        /// <returns></returns>
        public bool Release()
        {
            OnRelease();
            if (Reference <= 0)
            {
                Log.Warn("Asset reference zero. But release repeated. Name:{0}", AddressableName);
                return true;
            }
            if (--Reference <= 0)
            {
                timestamp.zeroReference = BinaryTimeStamp();
                //Log.Debug(string.Format("Asset Release reference zero. Name:{0}  time:{1}", AddressableName, System.DateTime.FromBinary(timestamp.zeroReference)));
                return true;
            }
            return false;
        }
        public void Dispose()
        {
            OnDispose();
            Reference = 0;
            IsPreload = false;
            _source = null;
        }
        long BinaryTimeStamp()
        {
            return System.DateTime.UtcNow.ToBinary();
        }
    }
}
