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

public class PoolController : MonoBehaviour 
{
	#region Public Members
	
	[SerializeField]
	public List<TypePool> Pools = new List<TypePool>();
	
	[SerializeField]
	public string RootName;
	
	[SerializeField]
	public bool DontDestroy;
	
	[SerializeField]
	public bool DebugMessages;
	
	[SerializeField]
	public bool NotifyOnLoad;
	
	[SerializeField]
	public GameObject NotifyTarget;
	
	[SerializeField]
	public string NotifyMethod;
	
	#endregion
	
	#region Private Members

	private bool m_isInitialized;
	
	private Transform m_rootTransform;
	
	#endregion
	
	#region Startup
	
	void Awake()
	{ 
		Initialize();	
		NotifyLoaded();
	}
	
	private void Initialize()
	{
		var root = new GameObject(RootName);
		
		if(DontDestroy)
		{
			DontDestroyOnLoad(gameObject);	
	        DontDestroyOnLoad(root);
		}
		
	    m_rootTransform = root.transform;
		
		foreach(PoolType poolType in Enum.GetValues(typeof(PoolType)))
		{
			var parent = new GameObject {name = poolType.ToString()};
		    parent.transform.parent = m_rootTransform;

		    var type = poolType;
			
			
#if UNITY_FLASH
			
			foreach(var pool in Pools)
			{
			    if(pool.PooledType == type)
				{   
				    var child = new GameObject {name = pool.PoolName};
					child.transform.parent = parent.transform;
				    pool.Initialize(child);
				}
			}
			
#else
			foreach(var pool in Pools.Where( pool => pool.PooledType == type))
			{
				var child = new GameObject {name = pool.PoolName};
			    child.transform.parent = parent.transform;
				pool.Initialize(child);
			}
#endif
		}
	}
	
	private void NotifyLoaded()
	{
		if(!NotifyOnLoad)
		{
			return;
		}
		
		if(NotifyTarget == null)
		{
			LogMessage("Notify target is null, can not send notification");
			return;
		}
		
	    NotifyTarget.SendMessage(NotifyMethod, true);	
	}
	
	#endregion
	
	#region Public Methods
	
	// Spawn a particle effect at a position
	public void Spawn(string poolName, Vector3 position)
	{
#if UNITY_FLASH		
		
		foreach(var pool in Pools)
		{
		    if(pool.PoolName == poolName)
			{
				pool.Spawn(position);
				LogMessage("Instance spawned");
			    return;
			}	
        }
		
		LogMessage("A pool for the type " + poolName + " was not found");

#else
		
		var targetPool = Pools.FirstOrDefault(p => p.PoolName == poolName);     
		
		if (targetPool == null)
		{
		    LogMessage("A pool for the type " + poolName + " was not found");
			return;
		}				
		
	    targetPool.Spawn(position);

#endif
	}
	
	public void Despawn(string poolName, int index, bool destroy, float destroyTime)
	{
#if UNITY_FLASH
		
		foreach(var pool in Pools)
		{
		    if(pool.PoolName == poolName)
			{
				LogMessage("Instance spawned");
				pool.Despawn(index, destroy, destroyTime);
			    return;
			}	
        }
		
		LogMessage("A pool for the type " + poolName + " was not found");
#else
		var targetPool = Pools.FirstOrDefault(p => p.PoolName == poolName);         
		
		if (targetPool == null)
		{
		    Debug.Log ("A pool for the type " + poolName + " was not found");
			return;
		}				
		
	    targetPool.Despawn(index, destroy, destroyTime);
#endif
	}	
	
	#endregion
	
	#region Private Methods
	
	private void LogMessage(string message)
	{
		if(DebugMessages)
		{
			Debug.Log (message);
		}
	}
	
	#endregion
}
