package at.ac.univie.cs.dsnotify.eval.util;

import java.util.HashSet;
import java.util.Set;

import com.hp.hpl.jena.query.Query;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QueryFactory;
import com.hp.hpl.jena.query.QuerySolution;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.rdf.model.Literal;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.Resource;

public class SPARQLDescribePerformance {

	private String sparqlEndpoint = "http://dbpedia.org/sparql";

	private String graph = "http://dbpedia.org";

	private String type = "http://dbpedia.org/ontology/Person";

	private Integer maxSPARQLResults = 5000;

	
	public SPARQLDescribePerformance() {

		Set<String> res = retrieveAllResources(graph, type);
		
		
		long startQuery = System.currentTimeMillis();
		
		int counter = 0;
		
		for(String resource : res) {
			
			int queryTime = retrieveModel(graph, resource);
			
			counter++;
			
			float avgQueryTime = (float) (System.currentTimeMillis() - startQuery) / counter;
			
			System.out.println("Retrieving model no " + counter + " in " + queryTime + "ms. Avg. query time / model: " + avgQueryTime);

			
			
		}
		

	}



	private int retrieveModel(String graph_uri, String resource) {

		String describe_query = "DESCRIBE <" + resource + "> FROM <" + graph_uri + ">";

		Query query = QueryFactory.create(describe_query);

		QueryExecution qexec = QueryExecutionFactory.createServiceRequest(sparqlEndpoint,
				query);

		
		long start = System.currentTimeMillis();
		
		qexec.execDescribe();

		long end = System.currentTimeMillis();

		
		
		qexec.close();


		return (int) (end-start);
		
	}
	
	
	
	private Set<String> retrieveAllResources(String graph_uri, String rdfTypeRestriction) {

		Set<String> resultsResources = new HashSet<String>();

		int offset = 0;

		boolean continueQuerying = true;

		while (continueQuerying) {

			if (offset % 100000 == 0) {
				System.out.println("Retrieving resources of type " + rdfTypeRestriction
						+ " starting with offset " + offset);
			}

			String all_res_sparql = "SELECT DISTINCT ?x WHERE { GRAPH <" + graph_uri + "> { ?x a <"
					+ rdfTypeRestriction + "> .} } LIMIT " + maxSPARQLResults + " OFFSET " + offset;

			// System.out.println(all_res_old_sparql);

			Query query = QueryFactory.create(all_res_sparql);

			// log.debug("Sending query " + query + " to SPARQL endpoint " +
			// settings.sparqlEndpoint);

			QueryExecution qexec = QueryExecutionFactory.createServiceRequest(this.sparqlEndpoint,
					query);

			try {

				ResultSet results = qexec.execSelect();

				if (results.hasNext()) {

					for (; results.hasNext();) {

						QuerySolution soln = results.nextSolution();

						// TODO: fix after virtuoso result set bug is fixed

						RDFNode node = soln.get("?x");

						String uri = null;

						if (node.canAs(Resource.class)) {
							uri = node.as(Resource.class).getURI();
						} else if (node.canAs(Literal.class)) {
							uri = node.as(Literal.class).getLexicalForm();
						} else {
							System.out.println("Query returned object of unknown type - " + node);
						}

						resultsResources.add(uri);

					}

					offset = offset + maxSPARQLResults;

				} else {
					continueQuerying = false;
				}

			} catch (Exception e) {

				System.out.println("Error when executing query " + all_res_sparql + " at "
						+ all_res_sparql + "\n" + e);

			} finally {

				qexec.close();

			}

		}

		return resultsResources;

	}

	public static void main(String[] args) {
		new SPARQLDescribePerformance();
	}

}
