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

import java.net.URI;

import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
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.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;

import org.apache.log4j.Logger;

import cz.muni.fi.lasaris.sbms.semantics.api.entities.DataPoint;
import cz.muni.fi.lasaris.sbms.semantics.api.entities.Influence;
import cz.muni.fi.lasaris.sbms.semantics.api.entities.ObservedProperty;
import cz.muni.fi.lasaris.sbms.semantics.api.entities.Scope;
import cz.muni.fi.lasaris.sbms.semantics.api.entities.Sensing;
import cz.muni.fi.lasaris.sbms.semantics.api.entities.Source;
import cz.muni.fi.lasaris.sbms.semantics.api.request.DataPointsRequest;
import cz.muni.fi.lasaris.sbms.semantics.api.request.Insert;
import cz.muni.fi.lasaris.sbms.semantics.api.response.GroupedResponse;
import cz.muni.fi.lasaris.sbms.semantics.logic.ModelUpdater;
import cz.muni.fi.lasaris.sbms.semantics.logic.QueryParser;

@Path("datapoints")
@PermitAll
public class DataPointsEndpoint {
	
	final static Logger logger = Logger.getLogger(DataPointsEndpoint.class);
	
	
	@RolesAllowed({"user","admin"})
	@GET
	@Produces(MediaType.APPLICATION_JSON)
	public GroupedResponse getDataPoints(
			@QueryParam("bmsId") String dpIdP,
			@QueryParam("type") String dptP,
			@QueryParam("source.bimId") String sourceIdP,
			@QueryParam("source.type") String sourceTypeP,
			@QueryParam("source.location") String sourceLocP,
			@QueryParam("scope.bimId") String scopeIdP,
			@QueryParam("scope.type") String scopeTypeP,
			@QueryParam("scope.location") String scopeLocP,
			@QueryParam("sensing.type") String sensingTypeP,
			@QueryParam("sensing.window") String sensingWindowP,
			@QueryParam("property.domain") String propDomP,
			@QueryParam("property.quality") String propQualityP,
			@QueryParam("publisher.bimId") String publisherP,
			@QueryParam("influenced.scope.bimId") String inflScopeIdP,
			@QueryParam("influenced.property.quality") String inflQualityP,
			@QueryParam("influenced.property.domain") String inflDomainP,
			@QueryParam("fields") String fieldsP,
			@QueryParam("grouping") String groupingP
			) {
		DataPointsRequest dpr = new DataPointsRequest();
		DataPoint dp = new DataPoint();
		dpr.setDataPoint(dp);
		
		if(dpIdP != null) {
			dp.setBmsId(dpIdP);
		}
		
		if(dptP != null) {
			dp.setType(dptP);
		}
		
		if(sourceIdP != null || sourceTypeP != null || sourceLocP != null) {
			Source s = new Source(sourceIdP, sourceTypeP, sourceLocP);
			dp.setSource(s);
		}
		
		if(scopeIdP != null || scopeTypeP != null  || scopeLocP != null) {
			Scope s = new Scope(scopeIdP, scopeTypeP, scopeLocP);
			dp.setScope(s);
		}
		
		if(sensingTypeP != null || sensingWindowP != null) {
			Sensing s = new Sensing(sensingTypeP, sensingWindowP);
			dp.setSensing(s);
		}
		
		if(propDomP != null || propQualityP != null) {
			ObservedProperty p = new ObservedProperty(propQualityP, propDomP);
			dp.setProperty(p);
		}
		
		if(publisherP !=null) {
			dp.setPublisher(new Source(publisherP, null, null));
		}
		
		ObservedProperty ip = null;
		Scope is = null;
		if(inflScopeIdP != null) {
			is = new Scope(inflScopeIdP, null, null);
		}
		if(inflQualityP != null || inflDomainP != null) {
			ip = new ObservedProperty(inflQualityP, inflDomainP);
		}
		
		if(ip != null || is != null) {
			dp.setInfluenced(new Influence(ip, is));	
		}
		
		dpr.setGrouping(groupingP);
		
		dpr.parseResponseFields(fieldsP);
		try {
			return QueryParser.getDataPointResponse(dpr);
		} catch (Exception e){
			logger.error(e, e);
			return GroupedResponse.getErrorResponse(e.toString());
		}
	}
	
	@RolesAllowed({"user","admin"})
	@GET
	@Path("/{bmsId}")
	@Produces(MediaType.APPLICATION_JSON)
	public GroupedResponse getDataPoint(
			@PathParam("bmsId") String bmsIdP, 
			@QueryParam("fields") String fieldsP) {
		
		DataPointsRequest dpr = new DataPointsRequest();
		DataPoint dp = new DataPoint();
		dp.setBmsId(bmsIdP);
		dpr.setDataPoint(dp);
		
		dpr.parseResponseFields(fieldsP);
		
		try {
			return QueryParser.getDataPointResponse(dpr);
		} catch (Exception e){
			logger.error(e, e);
			return GroupedResponse.getErrorResponse(e.toString());
		}
	}
	
	@Context
	private UriInfo uriInfo;
	
	@RolesAllowed("admin")
	@POST
	@Consumes(MediaType.APPLICATION_JSON)
	public Response InsertDataPointInfo(Insert insert) {
		try {
			if(insert.getDataPoint() != null && ModelUpdater.insertDataPoint(insert)) {
				URI createdUri = new URI(uriInfo.getAbsolutePath().toString() + insert.getDataPoint().getResourceId());
				return Response.created(createdUri).build();
			} else {
				return Response.status(Response.Status.BAD_REQUEST).entity("Invalid JSON data - see server log").build();
			}
		} catch (Exception e) {
			logger.error(e, e);
			return Response.serverError().build();
		}
	}
	
	@RolesAllowed("admin")
	@DELETE
	@Path("/{bmsId}")
	@Consumes(MediaType.APPLICATION_JSON)
	public Response RemoveDataPointInfo(@PathParam("bmsId") String bmsId) {
		System.out.println(bmsId);
		try {
			if(ModelUpdater.removeDataPointAssertions(bmsId)) {
				return Response.ok().build();
			} else {
				return Response.status(Response.Status.BAD_REQUEST).entity("Invalid JSON data - see server log").build();
			}
		} catch (Exception e) {
			logger.error(e, e);
			return Response.serverError().build();
		}
	}	
	
}

	
	
