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

import java.io.IOException;

import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;

import org.apache.log4j.Logger;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

import cz.muni.fi.lasaris.sbms.data.api.request.GroupedAddressRequest;
import cz.muni.fi.lasaris.sbms.data.api.request.AddressRequest;
import cz.muni.fi.lasaris.sbms.data.api.response.AggregateResponse;
import cz.muni.fi.lasaris.sbms.data.api.response.SnapshotResponse;
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.values.RawValue;
import cz.muni.fi.lasaris.sbms.data.logic.ProviderManager;
import cz.muni.fi.lasaris.sbms.data.logic.DPDataCollector;

//TODO http://stackoverflow.com/questions/14202257/design-restful-query-api-with-a-long-list-of-query-parameters

@Path("datapoints")
@PermitAll
public class DataPointsEndpoint {
	final static Logger logger = Logger.getLogger(DataPointsEndpoint.class);
	
	private DPDataCollector dc = new DPDataCollector(); 
	
	@RolesAllowed({"user","admin"})
	@GET
	@Produces(MediaType.APPLICATION_JSON)
	public SnapshotResponse getDataPoints(
			@QueryParam("ids") String json,
			@QueryParam("cache") String cache
			) {
		
		ObjectMapper m = new ObjectMapper();
		m.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
		try {
			logger.debug("Processing request...");
			logger.debug(json);
			AddressRequest readSpecs = m.readValue(json, AddressRequest.class);
			logger.debug(readSpecs);
			SnapshotResponse result = dc.getDataPointValues(readSpecs, allowCache(cache));
			logger.debug(result);
			return result;
		} catch (IOException e) {
			return SnapshotResponse.getErrorResponse("Unable to parse query:" + e);
		}
		
		
	}
	
	
	@RolesAllowed({"user","admin"})
	@GET
	@Path("/aggregated")
	@Produces(MediaType.APPLICATION_JSON)
	public AggregateResponse getAggregatedDataPoints(
			@QueryParam("ids") String json,
			@DefaultValue("NONE") @QueryParam("aggregation") AggregationFunction agg,
			@QueryParam("cache") String cache
			) {
		ObjectMapper m = new ObjectMapper();
		try {
			logger.debug("Processing request...");
			logger.debug(json);
			AddressRequest readSpecs = m.readValue(json, AddressRequest.class);
			logger.debug(readSpecs);
			return dc.getDataPointsAggregation(readSpecs, agg, allowCache(cache));
		} catch (IOException e) {
			return AggregateResponse.getErrorResponse("Unable to parse query:" + e);
		}
	}


	@RolesAllowed({"user","admin"})
	@GET
	@Path("/grouped")
	@Produces(MediaType.APPLICATION_JSON)
	public SnapshotResponse getGroupedDataPoints(
			@QueryParam("ids") String json,
			@QueryParam("cache") String cache
			) {
		ObjectMapper m = new ObjectMapper();
		try {
			logger.debug("Processing request...");
			logger.debug(json);
			GroupedAddressRequest readSpecs = m.readValue(json,GroupedAddressRequest.class);
			logger.debug(readSpecs);
			return dc.getDataPointGroupedValues(readSpecs, allowCache(cache));
		} catch (IOException e) {
			return SnapshotResponse.getErrorResponse("Unable to parse query:" + e);
		}
	}
	
	@RolesAllowed({"user","admin"})
	@GET
	@Path("/group-aggregated")
	@Produces(MediaType.APPLICATION_JSON)
	public AggregateResponse getGroupedAggregatedDataPoints(
			@QueryParam("ids") String json,
			@DefaultValue("NONE") @QueryParam("aggregation") AggregationFunction agg,
			@QueryParam("cache") String cache
			) {
		ObjectMapper m = new ObjectMapper();
		try {
			logger.debug("Processing request...");
			logger.debug(json);
			GroupedAddressRequest readSpecs = m.readValue(json, GroupedAddressRequest.class);
			logger.debug(readSpecs);
			AggregateResponse result =  dc.getDataPointGroupAggregations(readSpecs, agg, allowCache(cache));
			logger.debug(result);
			return result;
		} catch (IOException e) {
			return AggregateResponse.getErrorResponse("Unable to parse query:" + e);
		}
	}
	
	@RolesAllowed({"user","admin"})
	@GET
	@Path("/{id}")
	@Produces(MediaType.APPLICATION_JSON)
	public SnapshotResponse getDataPoint(
			@PathParam("id") String idP, 
			@QueryParam("cache") String cache) {
		Address a = new Address(idP);
		RawValue v = ProviderManager.getDataPointsProvider(a.getProtocol()).getDataPointValue(a, allowCache(cache));
		return new SnapshotResponse(a, v);
	}
	
	private boolean allowCache(String cache) {
		return cache == null || cache.toLowerCase().equals("true") || cache.toLowerCase().equals("cache");  
	}
}
