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

import java.util.List;

import org.apache.jena.query.QuerySolution;

import cz.muni.fi.lasaris.sbms.semantics.api.entities.Address;
import cz.muni.fi.lasaris.sbms.semantics.api.entities.Algorithm;
import cz.muni.fi.lasaris.sbms.semantics.api.entities.DataPoint;
import cz.muni.fi.lasaris.sbms.semantics.api.entities.Groupable;
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;

public class ObjectBuilders {

	public static DataPoint createDataPoint(QuerySolution soln, List<String> fields, String grouping) {
		
		DataPoint dp = new DataPoint(getLiteral(gsv("bmsId"), soln), null);
		
		if(fields.contains("type")) {
			dp.setType(getIndividual(gsv("type"), soln));
		}
		
		setGroup(soln, grouping, dp);
		
		// SOURCE
		
		if(fields.contains("source.bimId")) {
			dp.setSource(new Source());
			dp.getSource().setBimId(getLiteral(gsv("source.bimId"), soln));
		}
		
		if(fields.contains("source.type")) {
			if(dp.getSource() == null) {
				dp.setSource(new Source());
			}
			dp.getSource().setType(getIndividual(gsv("source.type"), soln));
		}
		
		if(fields.contains("source.location")) {
			if(dp.getSource() == null) {
				dp.setSource(new Source());
			}
			dp.getSource().setLocation(getLiteral(gsv("source.location"), soln));
		}
		
		// SCOPE
		
		if(fields.contains("scope.bimId")) {
			dp.setScope(new Scope());
			dp.getScope().setBimId(getLiteral(gsv("scope.bimId"), soln));
		}
		
		if(fields.contains("scope.type")) {
			if(dp.getScope() == null) {
				dp.setScope(new Scope());
			}
			dp.getScope().setType(getIndividual(gsv("scope.type"), soln));
		}
		
		if(fields.contains("scope.location") && soln.getResource(gsv("scope.location")) != null) {
			if(dp.getScope() == null) {
				dp.setScope(new Scope());
			}
			dp.getScope().setLocation(getIndividual(gsv("scope.location"), soln));
		}
		
		// SENSING
		
		if(fields.contains("sensing.type") && soln.getResource(gsv("sensing.type")) != null) {
			dp.setSensing(new Sensing());
			dp.getSensing().setType(getIndividual(gsv("sensing.type"), soln));
		}
		
		if(fields.contains("sensing.window") && soln.getResource(gsv("sensing.window")) != null) {
			if(dp.getSensing() == null) {
				dp.setSensing(new Sensing());
			}
			dp.getSensing().setWindow(getIndividual(gsv("sensing.window"), soln));
		}
		
		// PROPERTY
		
		if(fields.contains("property.quality")) {
			dp.setProperty(new ObservedProperty());
			dp.getProperty().setQuality(getIndividual(gsv("property.quality"), soln));
		}
		
		if(fields.contains("property.domain")) {
			if(dp.getProperty() == null) {
				dp.setProperty(new ObservedProperty());
			}
			dp.getProperty().setDomain(getIndividual(gsv("property.domain"), soln));
		}
		
		// PublishedBy
		if(fields.contains("publisher.bimId")) {
			dp.setPublisher(new Source(getLiteral(gsv("publisher.bimId"), soln), null, null));
		}
		
		return dp;
		
	}
	
	public static Trend createTrend(DataPoint d, QuerySolution qs, List<String> responseFields, String grouping) {
		Trend t = new Trend();
		t.setBmsId(getLiteral(gsv("trend.bmsId"), qs));
		t.setDataPoint(d);
		return t;
	}
	
	
	public static Influence createInfluence(QuerySolution soln) {
		Influence i = new Influence(new ObservedProperty(), new Scope());
		
		i.getScope().setBimId(getLiteral(gsv("influenced.scope.bimId"), soln));
		i.getScope().setType(getIndividual(gsv("influenced.scope.type"), soln));
		i.getProperty().setDomain(getIndividual(gsv("influenced.property.domain"), soln));
		i.getProperty().setQuality(getIndividual(gsv("influenced.property.quality"), soln));
		
		// we have no influence in the result (should not occur)
		if(i.getScope().getBimId() == null) {
			return null;
		}
		
		return i;
	}
	
	public static Address createAddress(QuerySolution soln) {
		Address a = new Address(getLiteral(gsv("bmsId"), soln));
		a.setType(getIndividual(gsv("type"), soln));
		String pub = getLiteral(gsv("publisher.bimId"), soln);
		if(pub != null) {
			a.setPublisher(new Source(pub, null, null));
		}
		Influence i = createInfluence(soln);
		if(i != null) {
			a.setInfluenced(i);
		}
		return a;
	}
	
	public static Algorithm createAlgorithm(QuerySolution soln) {
		Algorithm a = new Algorithm(getLiteral(gsv("bmsId"), soln));
		//a.setType(getIndividual(gsv("type"), soln));
		String u = getLiteral(gsv("used.bmsId"), soln);
		if(u != null) {
			a.setUsedAddress(new Address(u));
			a.getUsedAddress().setType(getLiteral(gsv("used.type"), soln));
		}
		return a;
	}
	
	private static void setGroup(QuerySolution soln, String grouping, Groupable o) {
		if(grouping != null) {
			switch(grouping) {
			case "datapoint.type":
			case "source.type":
			case "scope.type":
				o.setGroup(getIndividual("group", soln));
				break;
			case "scope.room":
			case "scope.floor":
			case "scope.building":
			case "scope.site":
			case "source.room":
			case "source.floor":
			case "source.building":
			case "source.site":
				o.setGroup(getLiteral("group", soln));
				break;
			case Fields.DEFAULT_GROUPING:
			default:
				o.setGroup(Fields.DEFAULT_GROUPING);
				break;
			}
		} else {
			o.setGroup(Fields.DEFAULT_GROUPING);
		}
	}
	
	private static String getIndividual(String name, QuerySolution soln) {
		return (soln.getResource(name) != null) ? soln.getResource(name).getLocalName() : null; 
	}
	
	private static String getLiteral(String name, QuerySolution soln) {
		return (soln.getLiteral(name) != null) ? soln.getLiteral(name).getString() : null; 
	}
	
	private static String gsv(String f) {
		return QueryParser.getSPARQLvar(f);
	}
}
