package speiger.src.coreengine.utils.collections.pools;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;

import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.lists.ObjectList;
import speiger.src.coreengine.utils.functions.Functions;

public class ThreadLocalPool<T> implements IPool<T> {
	ThreadLocal<ObjectList<T>> stack = ThreadLocal.withInitial(ObjectArrayList::new);
	int cap;
	Supplier<T> creator;
	Consumer<T> acceptor;
	
	public ThreadLocalPool(int size, Supplier<T> creator) {
		this(size, creator, Functions.getVoidConsumer());
	}
	
	public ThreadLocalPool(int size, Supplier<T> creator, Consumer<T> acceptor) {
		cap = size;
		this.creator = creator;
		this.acceptor = acceptor;
	}
	
	@Override
	public void accept(T t) {
		List<T> list = stack.get();
		if(list.size() >= cap) return;
		acceptor.accept(t);
		list.add(t);
	}
	
	@Override
	public T get() {
		List<T> list = stack.get();
		return list.isEmpty() ? creator.get() : list.remove(list.size() - 1);
	}
	
	@Override
	public T[] get(T[] input) {
		List<T> list = stack.get();
		for(int i = 0,m = input.length;i < m;i++) {
			input[i] = list.isEmpty() ? creator.get() : list.remove(list.size() - 1);
		}
		return input;
	}
	
	@Override
	public void accept(T[] array) {
		ObjectList<T> list = stack.get();
		list.addAll(array, 0, Math.min(array.length, cap - list.size()));
		for(int i = 0,m = Math.min(array.length, cap - list.size());i < m;acceptor.accept(array[i++]));
	}
	
	@Override
	public void accept(Collection<T> values) {
		List<T> list = stack.get();
		Iterator<T> iter = values.iterator();
		for(int i = 0,m = Math.min(values.size(), cap - list.size());i < m && iter.hasNext();i++) {
			T next = iter.next();
			list.add(next);
			acceptor.accept(next);
		}
	}
}
