using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace TFramework
{
    public class ObjectPool
    {
        private GameObject _objTemplate;
        private Queue<GameObject> _objPool;
        private int _maxCount;
        private TAction<GameObject> OnTakeOut;
        private TAction<GameObject> OnRecycle;
        List<Component> _initComponents = new List<Component>();

        public ObjectPool(GameObject objTemplate, int maxCount, TAction<GameObject> takeOutEvent, TAction<GameObject> recycleEvent)
        {
            _objTemplate = objTemplate;
            _maxCount = maxCount;
            _objPool = new Queue<GameObject>(_maxCount);
            OnTakeOut = takeOutEvent;
            OnRecycle = recycleEvent;
        }

        public int Count => _objPool.Count;

        /// <summary>
        /// 取出对象
        /// </summary>
        /// <returns></returns>
        public GameObject TakeOutObj()
        {
            GameObject obj;
            if (Count > 0)
                obj = _objPool.Dequeue();
            else
                obj = GameObject.Instantiate(_objTemplate);
            obj.SetActive(true);
            OnTakeOut?.Invoke(obj);
            return obj;
        }

        /// <summary>
        /// 回收对象
        /// </summary>
        /// <param name="obj"></param>
        public void RecycleObj(GameObject obj)
        {
            obj.SetActive(false);
            _initComponents.Clear();
            _initComponents.AddRange(obj.GetComponents<Component>());
            foreach (var template in _objTemplate.GetComponents<Component>())
            {
                for (int i = 0; i < _initComponents.Count; i++)
                {
                    if (template.GetType().Equals(_initComponents[i].GetType()))
                    {
                        _initComponents[i] = template;
                        _initComponents.Remove(_initComponents[i]);
                        break;
                    }
                }
            }
            OnRecycle?.Invoke(obj);
            if (Count >= _maxCount)
                GameObject.Destroy(obj);
            else
                _objPool.Enqueue(obj);
        }

        public void Clear()
        {
            while (Count > 0)
            {
                GameObject.Destroy(_objPool.Dequeue());
            }
        }
    }
}
