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

import java.util.Arrays;
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.AggregationFunction;
import cz.muni.fi.lasaris.sbms.data.entities.containers.Snapshot;
import cz.muni.fi.lasaris.sbms.data.entities.values.AggregatedValue;
import cz.muni.fi.lasaris.sbms.data.entities.values.RawValue;
import cz.muni.fi.lasaris.sbms.data.util.Aggregator;
import cz.muni.fi.lasaris.sbms.data.util.GroupHandler;
import cz.muni.fi.lasaris.sbms.data.util.GroupHandler.ContainerHandler;
import cz.muni.fi.lasaris.sbms.data.util.GroupHandler.ScalarHandler;

public abstract class AbstractSimpleDataPointsProvider implements DataPointsProvider {
	
	protected abstract Map<Address, RawValue> getValues(List<Address> dataPoints, boolean allowCache);
	
	@Override
	public RawValue getDataPointValue(Address dataPoint, boolean allowCache) {
		return getValues(Arrays.asList(new Address[] {dataPoint}), allowCache).get(dataPoint);
	}

	@Override
	public Snapshot getDataPointValues(List<Address> dataPoints, boolean allowCache) {
		Map<Address, RawValue> r = getValues(dataPoints, allowCache);
		Snapshot s = new Snapshot(r);
		return s;
	}

	@Override
	public Map<String, Snapshot> getDataPointGroupedValues(Map<String, List<Address>> dataPointGroups,
			boolean allowCache) {
		/*
		List<Address> allDPs = new LinkedList<Address>();
		for(String group : dataPointGroups.keySet()) {
			allDPs.addAll(dataPointGroups.get(group));
		}
		
		Map<Address, RawValue> r = getValues(allDPs, allowCache);
		Map<String, Snapshot> result = new LinkedHashMap<String, Snapshot>(dataPointGroups.size());
		for(String group : dataPointGroups.keySet()) {
			Snapshot s = new Snapshot();
			result.put(group, s);
			for(Address a : dataPointGroups.get(group)) {
				s.add(a, r.get(a));
			}
		}
		return result;
		*/
		GroupHandler<RawValue> g = new GroupHandler<RawValue>();
		ContainerHandler<Snapshot, RawValue> p = new ContainerHandler<Snapshot, RawValue>() {
			@Override
			public Snapshot getContainer() {
				return new Snapshot();
			}

			@Override
			public Map<Address, RawValue> getResults(List<Address> all) {
				return getValues(all, allowCache);
			}
			
		};
		return g.getGroups(dataPointGroups, p);
	}

	@Override
	public AggregatedValue getDataPointsAggregation(List<Address> dataPoints, AggregationFunction aggregation,
			boolean allowCache) {
		
		Map<Address, RawValue> r = getValues(dataPoints, allowCache);
		AggregatedValue av = Aggregator.computeAggregation(r, aggregation);
		return av;
	}

	@Override
	public Map<String, AggregatedValue> getDataPointGroupAggregations(Map<String, List<Address>> dataPointGroups,
			AggregationFunction aggregation, boolean allowCache) {
		/*
		List<Address> allDPs = new LinkedList<Address>();
		for(String group : dataPointGroups.keySet()) {
			allDPs.addAll(dataPointGroups.get(group));
		}
		
		Map<Address, RawValue> r = getValues(allDPs, allowCache);
		Aggregation<AddressGroup> result = new Aggregation<AddressGroup>();
		for(String group : dataPointGroups.keySet()) {
			Map<Address, RawValue> aggregationData = new LinkedHashMap<Address, RawValue>();
			for(Address a : dataPointGroups.get(group)) {
				aggregationData.put(a, r.get(a));
			}
			AggregatedValue av = Aggregator.computeAggregation(aggregationData, aggregation);
			result.add(new AddressGroup(dataPointGroups.get(group), group), av);
		}
		return result;
		*/
		
		GroupHandler<RawValue> g = new GroupHandler<RawValue>();
		ScalarHandler<AggregatedValue, RawValue> p = new ScalarHandler<AggregatedValue, RawValue>() {

			@Override
			public Map<Address, RawValue> getResults(List<Address> all) {
				return getValues(all, allowCache);
			}

			@Override
			public AggregatedValue getScalar(Map<Address, RawValue> data) {
				return Aggregator.computeAggregation(data, aggregation);
			}
			
			
		};
		return g.getGroups(dataPointGroups, p);
	}
}
