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

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

import cz.muni.fi.lasaris.sbms.data.entities.Address;
import cz.muni.fi.lasaris.sbms.data.entities.AddressGroup;
import cz.muni.fi.lasaris.sbms.data.entities.AggregationFunction;
import cz.muni.fi.lasaris.sbms.data.entities.containers.Aggregation;
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.providers.DataPointsProvider;
import cz.muni.fi.lasaris.sbms.data.util.Aggregations;

public class BACnetPropertiesProvider implements DataPointsProvider {

	@Override
	public void init(Properties props, String name, String propertiesPrefix) {
		if(!BACnetConnector.isInitialized()) {
			BACnetConnector.init(props, name, propertiesPrefix);
		}
	}

	@Override
	public void close() {
		BACnetConnector.getInstance().close();

	}

	@Override
	public RawValue getDataPointValue(Address dataPoint, boolean allowCache) {
		return BACnetConnector.getInstance().getValues(Arrays.asList(new Address[] {dataPoint}), allowCache).get(dataPoint);
	}

	@Override
	public Snapshot getDataPointValues(List<Address> dataPoints, boolean allowCache) {
		Map<Address, RawValue> r = BACnetConnector.getInstance().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 = BACnetConnector.getInstance().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;
	}

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

	@Override
	public Aggregation<AddressGroup> 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 = BACnetConnector.getInstance().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 = Aggregations.computeAggregation(aggregationData, aggregation);
			result.add(new AddressGroup(dataPointGroups.get(group), group), av);
		}
		return result;
	}

}
