package cz.muni.fi.lasaris.sbms.data.util;

import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import cz.muni.fi.lasaris.sbms.data.entities.Address;
import cz.muni.fi.lasaris.sbms.data.entities.containers.CompositeDataContainer;

/**
 * This class handles splitting of results from the provider to groups requested in the API call.
 * The provider has to implement one of the handlers to supply data to the algorithm.
 * @author akucera
 *
 * @param <R> Type of the data that enter the handler - unprocessed data from the provider
 */
public class GroupHandler<R> {
	
	/**
	 * The ContainerHandler serves to organize data in some kind of container - e.g. Trend 
	 * @author akucera
	 *
	 * @param <C> The container
	 * @param <R> The data type entering the algorithm
	 */
	public static interface ContainerHandler<C extends CompositeDataContainer<Address, R>,R> {
		public C getContainer();
		public Map<Address, R> getResults(List<Address> all);
	}
	
	public static interface ScalarHandler<S, R> {
		public Map<Address, R> getResults(List<Address> all);
		public S getScalar(Map<Address, R> data);
	}
	
	
	public <C extends CompositeDataContainer<Address, R>> Map<String, C> getGroups(Map<String,List<Address>> groups, ContainerHandler<C, R> cProvider) {
		List<Address> all = new LinkedList<Address>();
		for(String group : groups.keySet()) {
			all.addAll(groups.get(group));
		}
		Map<Address, R> results = cProvider.getResults(all);
		Map<String, C> output = new LinkedHashMap<String, C>(groups.size());
		for(String group : groups.keySet()) {
			C x = cProvider.getContainer();
			output.put(group, x);
			for(Address a : groups.get(group)) {
				x.add(a, results.get(a));
			
			}
		}
		return output;
	}
	
	public <S> Map<String, S> getGroups(Map<String,List<Address>> groups, ScalarHandler<S, R> sProvider) {
		List<Address> all = new LinkedList<Address>();
		for(String group : groups.keySet()) {
			all.addAll(groups.get(group));
		}
		Map<Address, R> results = sProvider.getResults(all);
		Map<String, S> output = new LinkedHashMap<String, S>(groups.size());
		for(String group : groups.keySet()) {
			Map<Address, R> groupData = new LinkedHashMap<Address, R>();
			for(Address a : groups.get(group)) {
				groupData.put(a, results.get(a));
			}
			S s = sProvider.getScalar(groupData);
			output.put(group, s);
		}
		return output;
	}
	
}
