package com.hammurapi.common;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;

import com.hammurapi.extract.And;
import com.hammurapi.extract.Predicate;

/**
 * Simple context implementation.
 * @author Pavel Vlasov
 *
 */
public class FacadeContext implements Context {
	
	private Map<String, ?> bindings;
	private Map<Class<?>, Iterable<?>> services;
	
	/**
	 * @param classLoader ClassLoader for services. Can be null.
	 * @param bindings Name bindings. Can be null.
	 */
	public FacadeContext(Map<Class<?>, Iterable<?>> services, Map<String, ?> bindings) {
		this.services = services;
		this.bindings = bindings;
	}
		
	public Object lookup(String name) {
		return bindings==null ? null : bindings.get(name);
	}

	@SuppressWarnings("unchecked")
	public <T> T lookup(Class<T> serviceClass, Predicate<T, Context>... selectors) {
		if (services==null) { 
			return null;
		}
		
		Iterable<?> sl = services.get(serviceClass);
		if (sl==null) {
			return null;
		}
				
		Iterator<?> sit = sl.iterator();
		And<T, Context> and = new And<T, Context>(0, null, selectors);
		while (sit.hasNext()) {
			T service = (T) sit.next();
			if (and.extract(this, null, service)) {
				return service;
			}
		}
		return null;
	}

	@SuppressWarnings("unchecked")
	public <T> Iterator<T> lookupAll(Class<T> serviceClass, Predicate<T, Context>... selectors) {
		if (services==null) {
			return (Iterator<T>) Collections.emptyList().iterator();
		}
		
		Iterable<?> sl = services.get(serviceClass);
		And<T, Context> and = new And<T, Context>(0, null, selectors);
		Collection<T> ret = new ArrayList<T>();
		Iterator<?> sit = sl.iterator();		
		while (sit.hasNext()) {
			T service = (T) sit.next();
			if (and.extract(this, null, service)) {
				ret.add(service);
			}
		}
		return Collections.unmodifiableCollection(ret).iterator();
	}

}
