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.entities.Trend;
import cz.muni.fi.lasaris.sbms.semantics.api.request.Insert;
import cz.muni.fi.lasaris.sbms.semantics.api.request.TrendsRequest;
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("trends")
@PermitAll
public class TrendsEndpoint {
final static Logger logger = Logger.getLogger(TrendsEndpoint.class);
	
	@RolesAllowed({"user","admin"})
	@GET
	@Produces(MediaType.APPLICATION_JSON)
	public GroupedResponse getTrends(
			@QueryParam("bmsId") String IdP,
			@QueryParam("dataPoint.bmsId") String dpIdP,
			@QueryParam("dataPoint.type") String dptP,
			@QueryParam("dataPoint.source.bimId") String sourceIdP,
			@QueryParam("dataPoint.source.type") String sourceTypeP,
			@QueryParam("dataPoint.source.location") String sourceLocP,
			@QueryParam("dataPoint.scope.bimId") String scopeIdP,
			@QueryParam("dataPoint.scope.type") String scopeTypeP,
			@QueryParam("dataPoint.scope.location") String scopeLocP,
			@QueryParam("dataPoint.sensing.type") String sensingTypeP,
			@QueryParam("dataPoint.sensing.window") String sensingWindowP,
			@QueryParam("dataPoint.property.domain") String propDomP,
			@QueryParam("dataPoint.property.quality") String propQualityP,
			@QueryParam("dataPoint.publisher.bimId") String publisherP,
			@QueryParam("dataPoint.influenced.scope.bimId") String inflScopeIdP,
			@QueryParam("dataPoint.influenced.property.quality") String inflQualityP,
			@QueryParam("dataPoint.influenced.property.domain") String inflDomainP,
			@QueryParam("fields") String fieldsP,
			@QueryParam("grouping") String groupingP
			) {
		TrendsRequest dpr = new TrendsRequest();
		Trend t = new Trend();
		DataPoint dp = new DataPoint();
		t.setDataPoint(dp);
		dpr.setTrend(t);
		
		if(IdP != null) {
			t.setBmsId(IdP);
		}
		
		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.getTrendsResponse(dpr);
		} catch (Exception e){
			logger.error(e, e);
			return GroupedResponse.getErrorResponse(e.toString());
		}
	}
	
	@GET
	@Path("/{bmsId}")
	@Produces(MediaType.APPLICATION_JSON)
	public GroupedResponse getDataPoint(
			@PathParam("bmsId") String bmsIdP, 
			@QueryParam("fields") String fieldsP) {
		
		TrendsRequest tr = new TrendsRequest();
		Trend t = new Trend();
		t.setBmsId(bmsIdP);
		tr.setTrend(t);
		
		tr.parseResponseFields(fieldsP);
		
		try {
			return QueryParser.getTrendsResponse(tr);
		} 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 InsertTrendInfo(Insert insert) {
		try {
			if(insert.getTrend() != null && ModelUpdater.insertTrend(insert)) {
				URI createdUri = new URI(uriInfo.getAbsolutePath().toString() + insert.getTrend().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 RemoveTrendInfo(@PathParam("bmsId") String bmsId) {
		System.out.println(bmsId);
		try {
			if(ModelUpdater.removeTrendAssertions(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();
		}
	}
	
}
