package com.gamepatriot.framework2d.implementation;

import java.util.ArrayList;
import java.util.Collection;

import com.gamepatriot.androidframework.framework.AndroidPool;

/**
 * The Pool class is used to prevent unnecessary instantiation and, instead, encourage the reuse of already instantiated objects. This class stores references to unused objects so they may be 
 * retrieved again for reuse using {@link #get()}.
 * 
 * @see AndroidPool
 * @author Pete Schmitz, May 9, 2013
 *
 * @param <T>		Typecast of the class being pooled.
 */
public class Pool<T> implements AndroidPool<T>{
	
	/**
	 * The PoolFactory class is used to assign override functionality that contains an explicit directive for instantiating a new class T.
	 * 
	 * @param <T>		The typecast of this PoolFactory.
	 * 
	 * @author Pete Schmitz, May 9, 2013
	 */
	public interface PoolFactory<T>{
		
		/**
		 * Return a new class of type T.
		 */
		public T createObject();
	}
	
	/** The {@link PoolFactory} reference used to instantiate a new object of class T. **/
	private final PoolFactory<T> poolFactory;
	
	/** The maximum limit of references this pool can contain. **/
	private final int limit;
	
	/** Pool container. Stores instantiated objects of class T so they can be reused. **/
	private final ArrayList<T> pool;
	
	/**
	 * Constructor
	 * @param $poolFactory		The {@link PoolFactory} reference to associate with this Pool for instantiating new objects when the pool is empty.
	 * @param $limit			The maximum amount of objects this pool is allowed to contain.
	 */
	public Pool(PoolFactory<T> $poolFactory, int $limit){
		poolFactory = $poolFactory;
		limit = $limit;
		
		pool = new ArrayList<T>($limit);
	}
	
	@Override
	public T get() {
		
		//Return an object from the pool or return a new object if the pool is empty
		if (pool.size() > 0) return pool.remove(0);
		else return poolFactory.createObject();
	}
	
	@Override
	public boolean add(T $t) {
		if (pool.size() >= limit || $t == null) return false;
		
		pool.add($t);
		
		return true;
	}

	@Override
	public int size() {
		if (pool == null) return -1;
		
		return pool.size();
	}
	
	@Override
	public Collection<T> release(){
		
		//Reference current elements in pool
		Collection<T> $collection = new ArrayList<T>();
		pool.addAll($collection);
		
		//Clear pool
		pool.clear();
		
		return $collection;
	}
	
}
