package cz.muni.fi.lasaris.sbms.model;

import java.util.ArrayList;
import java.util.List;

import org.apache.jena.rdf.model.RDFNode;
import org.apache.log4j.Logger;

import cz.muni.fi.lasaris.sbms.api.response.TypeResponse;

public class TypesProvider {
	final static Logger logger = Logger.getLogger(TypesProvider.class);
	
	private static TypeResponse getTypeMembers(String name, String queryString) {
		TypeResponse t = new TypeResponse();
		t.setName(name);
		t.setMembers(new ArrayList<String>());
		List<RDFNode> l = TdbConnector.executeSPARQLList(queryString, true);
		for(RDFNode n : l) {
			t.getMembers().add(n.asResource().getLocalName());
		}
		return t;
	}

	public static TypeResponse getDataPointTypes() {
		/*
		String queryString = String.format("SELECT * { ?member <%ssubClassOf> <%sDataPoint>."
				+" FILTER ( ?member != <%sDataPoint> && ?member != <%sNothing> ) .}", NS.rdfs, NS.sbms, NS.sbms, NS.owl); 
		return getTypeMembers("datapoint.type",queryString);
		*/
		return getDirectSubTypes("datapoint.type", NS.sbms, "DataPoint");
	}
	
	public static TypeResponse getDataPointTypes(String root) {
		return getDirectSubTypes("datapoint.type", NS.sbms, root);
	}
	
	public static TypeResponse getAddressTypes() {
		return getDirectSubTypes("address.type", NS.sbms, "Address");
	}
	
	public static TypeResponse getAddressTypes(String root) {
		if(root.equals("all")) {
			return getSubTypes("address.type", NS.sbms, "Address");
		} else {
			return getDirectSubTypes("address.type", NS.sbms, root);
		}
		
	}
	
	public static TypeResponse getQualityTypes() {
		String queryString = String.format("SELECT * { ?member <%stype> <%sPhysicalQuality>. }", NS.rdf, NS.muo);  
		return getTypeMembers("property.quality",queryString);
	}

	public static TypeResponse getPropDomainTypes() {
		String queryString = String.format("SELECT * { ?member <%stype> <%sPropertyDomain>. }", NS.rdf, NS.sbms); 
		return getTypeMembers("property.domain", queryString);
	}

	public static TypeResponse getTimeWindowTypes() {
		String queryString = String.format("SELECT * { ?member <%stype> <%sSensingTimeWindow>. }", NS.rdf, NS.sbms); 
		return getTypeMembers("sensing.timeWindow", queryString);
	}
	
	public static TypeResponse getSourceTypes() {
		return getDirectSubTypes("source.type", NS.sbim, "DistributionElement");
	}
	
	public static TypeResponse getSourceTypes(String root) {
		if(root.equals("all")) {
			return getSubTypes("source.type", NS.sbim, "Device");
		} else {
			return getDirectSubTypes("source.type", NS.sbim, root);
		}
	}
	
	public static TypeResponse getSensingTypes() {
		return getDirectSubTypes("sensing.type", NS.sbms, "Sensing");
	}
	
	public static TypeResponse getSensingTypes(String root) {
		if(root.equals("all")) {
			return getSubTypes("sensing.type", NS.sbms, "Sensing");
		} else {
			return getDirectSubTypes("sensing.type", NS.sbms, root);
		}
	}
	
	public static TypeResponse getStatefulSensingTypes() {
		return getSubTypes("sensing.type", NS.sbms, "StatefulSensing");
	}
	
	public static TypeResponse getStatelessSensingTypes() {
		return getSubTypes("sensing.type", NS.sbms, "StatelessSensing");
	}
	
	public static TypeResponse getSubTypes(String typeName, String rootNS, String rootClass) {
		String queryString = String.format("SELECT * { ?member <%ssubClassOf> <%s%s>."
			    + "FILTER (?member != <%sNothing>"
				+ " && ?member != <%s%s>"
				+ " && not exists { ?subtype <%ssubClassOf> ?member."
				+ " FILTER (?subtype != ?member && ?subtype != <%s%s> && ?subtype != <%sNothing>) }).}",
				NS.rdfs, rootNS, rootClass, NS.owl, rootNS, rootClass, NS.rdfs, rootNS, rootClass, NS.owl);
		return getTypeMembers(typeName, queryString);
	}
	
	public static TypeResponse getDirectSubTypes(String typeName, String rootNS, String rootClass) {
		String query =  String.format("SELECT * WHERE { ?member <%ssubClassOf> <%s%s>."
  			+ "FILTER (not exists { ?midtype <%ssubClassOf> <%s%s>. ?member <%ssubClassOf> ?midtype."
  				+ "FILTER(?midtype != ?member && ?midtype != <%s%s>) }  && ?member != <%s%s> && ?member != <%sNothing>) }",
  				NS.rdfs, rootNS, rootClass, NS.rdfs, rootNS, rootClass, NS.rdfs, rootNS, rootClass, rootNS, rootClass, NS.owl); 
		return getTypeMembers(typeName, query);
	}
	
	public static TypeResponse getScopeTypes() {
		TypeResponse t = new TypeResponse();
		t.setName("scope.type");
		t.setMembers(new ArrayList<String>());
		t.getMembers().add("Not implemented");
		return t;
	}
	
	
}
