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

namespace mgaia.Utils
{
    /// <summary>
    /// Classe que gerencia todas as pools de GameObject. É com ela que o desenvolvedor deve interagir para criar pools e pegar objetos delas.
    /// </summary>
    /// <owner>Felipe</owner>
    public class PoolManager
    {
        public static PoolManager Instance { get; private set; }

		static PoolManager()
		{
            Instance = new PoolManager();
		}

        private const string POOL_NAME_PREFIX = "Pool_";
        private Dictionary<string, Pool> mPools = new Dictionary<string, Pool>();

        /// <summary>
        /// Cria uma nova pool de um dado GameObject presente na pasta Resources. O GameObject deve possuir/herdar o behaviour PoolElement.
        /// </summary>
        /// <param name="resourcePath">Path completo da resource, relativo à sua pasta raiz Resources.</param>
        /// <param name="initialSize">Quantidade de PoolElements que será criada durante a criação da pool. Idealmente a pool nunca deve aumentar de tamanho durante o jogo.</param>
        public void CreatePool(string resourcePath, int initialSize)
        {
            Assert.AssertTrue(!mPools.ContainsKey(GetPoolName(resourcePath)), "There is already a pool named " + GetPoolName(resourcePath));
            mPools[GetPoolName(resourcePath)] = new Pool(resourcePath, GetPoolName(resourcePath), initialSize);
        }

        /// <summary>
        /// Pega um PoolElement de sua pool. Caso uma pool deste tipo não exista, ela é criada com apenas 1 elemento e ele é retornado.
        /// </summary>
        /// <typeparam name="T">O tipo da resource, que deve ser ou herdar de PoolElement.</typeparam>
        /// <param name="resourcePath">Path completo da resource, relativo à sua pasta raiz Resources.</param>
        /// <returns></returns>
        public T Pop<T>(string resourcePath) where T : PoolElement
        {
            if (!mPools.ContainsKey(GetPoolName(resourcePath)))
            {
                CreatePool(resourcePath, 1);
            }
            return mPools[GetPoolName(resourcePath)].Pop() as T;
        }

        /// <summary>
        /// Gera um nome de pool, concatenando uma string prefixo ao path da resource.
        /// </summary>
        /// <param name="resourcePath">Path completo da resource, relativo à sua pasta raiz Resources.</param>
        /// <returns>O nome da pool.</returns>
        private string GetPoolName(string resourcePath)
        {
            return POOL_NAME_PREFIX + resourcePath;
        }

        /// <summary>
        /// Recarrega todas as pools que estão abaixo do seu limite
        /// </summary>
        public void RechargePools()
        {
            mPools.Values.ForEach(pool => pool.Recharge());
        }
    }
}