package org.aksw.simba.qaldbench.rdf;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
import java.util.Set;

import org.aksw.simba.qaldbench.featurevectors.FeatureVector;
import org.openrdf.model.Model;
import org.openrdf.model.Statement;
import org.openrdf.model.URI;
import org.openrdf.model.ValueFactory;
import org.openrdf.model.impl.LinkedHashModel;
import org.openrdf.model.vocabulary.XMLSchema;
import org.openrdf.query.BindingSet;
import org.openrdf.query.MalformedQueryException;
import org.openrdf.query.QueryEvaluationException;
import org.openrdf.query.QueryLanguage;
import org.openrdf.query.TupleQuery;
import org.openrdf.query.TupleQueryResult;
import org.openrdf.repository.Repository;
import org.openrdf.repository.RepositoryConnection;
import org.openrdf.repository.RepositoryException;
import org.openrdf.repository.RepositoryResult;
import org.openrdf.repository.http.HTTPRepository;
import org.openrdf.repository.sail.SailRepository;
import org.openrdf.rio.RDFFormat;
import org.openrdf.rio.RDFHandlerException;
import org.openrdf.rio.Rio;
import org.openrdf.sail.memory.MemoryStore;

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 info.aduna.iteration.Iterations;

public class PrintBenchmark {
	public static RepositoryConnection conn = null;
	public static String sqcf = "http://sqc-framework.aksw.org/testsuite#";
	public static String vocab = "http://sqc-framework.aksw.org/vocab#";
	public static String sqcfr = "http://sqc-framework.aksw.org/test#";
	public static Repository rep ;
	public static ValueFactory factory;
	
	/**
	 * Print benchmark queries into console
	 * @param exeTime 
	 * @param similarityScore 
	 * @param method 
	 * @param normalizedVectors 
	 * @param diversityScore 
	 * @param queries queries
	 * @param outputDir output dir
	 * @throws IOException 
	 * @throws RepositoryException 
	 * @throws MalformedQueryException 
	 * @throws QueryEvaluationException 
	 * @throws RDFHandlerException 
	 */
	public static void getRDFSQCFramework(Set<String> queriesIds, String outputFile,String endpointURL, String method, Double similarityScore, long exeTime, Map<String, Double[]> normalizedVectors, Double diversityScore) throws IOException, RepositoryException, MalformedQueryException, QueryEvaluationException, RDFHandlerException {
		initializeRepo();
		conn.add(factory.createURI("http://sqc-framework.aksw.org/benchamrk"), factory.createURI(vocab,"wasGeneratedUsing"), factory.createLiteral(method));
		conn.add(factory.createURI("http://sqc-framework.aksw.org/benchamrk"), factory.createURI(vocab,"hasGenerationTimeSec"), factory.createLiteral(exeTime));
		conn.add(factory.createURI("http://sqc-framework.aksw.org/benchamrk"), factory.createURI(vocab,"hasSimilarityError"), factory.createLiteral(similarityScore));
		conn.add(factory.createURI("http://sqc-framework.aksw.org/benchamrk"), factory.createURI(vocab,"hasDiversityScore"), factory.createLiteral(diversityScore));
		Repository repo = new HTTPRepository(endpointURL, "sqcbench");
		repo.initialize();
		RepositoryConnection con = repo.getConnection();
		int testNo = 1; 
		for(String queryid:queriesIds)
		{
			String supQueryURI = "<http://lsq.aksw.org/res/q-" + queryid + ">";
			 String supQryFeat = getSupQryFeat(queryid,normalizedVectors);
		//	 System.out.println(supQryFeat);
			String queryString = "Prefix lsq: <http://lsq.aksw.org/vocab#> \n"
					+ "SELECT DISTINCT ?supText ?sub ?subText \n "
					+ "{ \n"
					+ "?sub  lsq:isEntailed " + supQueryURI +" . \n"
							+  supQueryURI + " lsq:text ?supText .  \n"
									+ "?sub lsq:text ?subText . \n"
									+ "FILTER (str(?sub) != "+supQueryURI+" ) \n"
						+ "}";
			TupleQuery  tupleQuery = con.prepareTupleQuery(QueryLanguage.SPARQL, queryString);
			   TupleQueryResult  result = tupleQuery.evaluate();
			 BindingSet bset = result.next();
				String supQueryText = bset.getBinding("supText").getValue().stringValue().replace("\n", " ");
				String subQueryText = bset.getBinding("subText").getValue().stringValue().replace("\n", " ");
				String subQueryURI = bset.getBinding("sub").getValue().toString();
				String subQueryNo = subQueryURI.replace("http://lsq.aksw.org/res/q-", "");
				
				supQueryURI = "http://lsq.aksw.org/res/q-" + queryid ;
		writeTest(testNo,supQueryURI,subQueryURI);
		writeSupQuery(queryid,supQueryText,supQryFeat);
		
		writeSubQuery(subQueryNo,subQueryText);
			testNo++;
			  while(result.hasNext()){
				  bset = result.next();
					supQueryText = bset.getBinding("supText").getValue().stringValue().replace("\n", " ");
					 subQueryText = bset.getBinding("subText").getValue().stringValue().replace("\n", " ");
					 subQueryURI = bset.getBinding("sub").getValue().toString();
					 subQueryNo = subQueryURI.replace("http://lsq.aksw.org/res/q-", "");
					 writeTest(testNo,supQueryURI,subQueryURI);
					 writeSupQuery(queryid,supQueryText,supQryFeat);
					writeSubQuery(subQueryNo,subQueryText);
						testNo++;
			  }
				
		}
		System.out.println("Total query containment tests: " + (testNo-1));
		writeModelSQCFrameWork(outputFile);
	
	}	
	public static void writeTest(int testNo, String supQueryURI,String subQueryURI) throws RepositoryException {
		String tstNo = ""+testNo;
		URI sbj = factory.createURI(sqcfr,tstNo);	
		conn.add(factory.createURI("http://sqc-framework.aksw.org/benchamrk"), factory.createURI(vocab,"hasTest"),sbj);
		conn.add(sbj,factory.createURI("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"),factory.createURI(vocab,"ContainmentTest"));
		conn.add(sbj, factory.createURI("http://www.w3.org/2000/01/rdf-schema#label"),factory.createLiteral("SQCFramework test#"+tstNo));
		conn.add(sbj, factory.createURI(vocab,"result"),factory.createLiteral("true"));
		conn.add(sbj, factory.createURI(vocab,"superQuery"),factory.createURI(supQueryURI));
		conn.add(sbj, factory.createURI(vocab,"subQuery"),factory.createURI(subQueryURI));

		
	}
	public static void writeSubQuery(String queryId, String queryText) throws RepositoryException {
		URI queryURI = factory.createURI("http://lsq.aksw.org/res/q-" + queryId);
		conn.add(queryURI,factory.createURI("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"), factory.createURI("http://lsq.aksw.org/vocab#Query"));
		conn.add(queryURI, factory.createURI("http://www.w3.org/2000/01/rdf-schema#label"),factory.createLiteral("q-"+queryId));
		conn.add(queryURI, factory.createURI("http://lsq.aksw.org/vocab#text"),factory.createLiteral(queryText));
		//conn.add(queryURI, factory.createURI("http://lsq.aksw.org/vocab#properties"),factory.createLiteral(features));
	}
	public static void writeSupQuery(String queryId, String queryText,String features) throws RepositoryException {
		URI queryURI = factory.createURI("http://lsq.aksw.org/res/q-" + queryId);
		conn.add(queryURI,factory.createURI("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"), factory.createURI("http://lsq.aksw.org/vocab#Query"));
		conn.add(queryURI, factory.createURI("http://www.w3.org/2000/01/rdf-schema#label"),factory.createLiteral("q-"+queryId));
		conn.add(queryURI, factory.createURI("http://lsq.aksw.org/vocab#text"),factory.createLiteral(queryText));
		conn.add(queryURI, factory.createURI("http://lsq.aksw.org/vocab#supQueryProps"),factory.createLiteral(features));
	}
	/**
	 * Write the model into file
	 * @throws RepositoryException
	 * @throws FileNotFoundException
	 * @throws RDFHandlerException
	 */
	public static void writeModelSQCFrameWork(String outputFile) throws RepositoryException, FileNotFoundException, RDFHandlerException {
		RepositoryResult<Statement> statements =  conn.getStatements(null, null, null, true);
		Model model = Iterations.addAll(statements, new LinkedHashModel());
		OutputStream output = new FileOutputStream(new File(outputFile));
		Rio.write(model, output, RDFFormat.TURTLE);
		System.out.println("Done! Benchmark saved to "+outputFile);

	}
	/**
	 * Write the model into file
	 * @throws RepositoryException
	 * @throws RDFHandlerException
	 * @throws IOException 
	 */
	public static void writeModel(com.hp.hpl.jena.rdf.model.Model model, String outputFile) throws RepositoryException, RDFHandlerException, IOException {
		
		FileWriter output = new FileWriter( outputFile );
		model.write(output,"N-Triples");
	//	Rio.write( (Iterable<Statement>) model, output, RDFFormat.TURTLE);
		System.out.println("Done! Benchmark saved to "+outputFile);
		output.close();

	}
	public static String getSupQryFeat(String key, Map<String, Double[]> normalizedVectors) {
		Double[] features = normalizedVectors.get(key);
	//	System.out.println(features);
		String props = "#Sub-queries: " + features[0]*FeatureVector.maxIndexVal[0];
		props = props +", #Projection Vars = " +features[1]*FeatureVector.maxIndexVal[1];
		props = props + ", #BGPs = " +features[2]*FeatureVector.maxIndexVal[2];
		props = props + ", #Triple Patterns = " +features[3]*FeatureVector.maxIndexVal[3];
		props = props + ", #Join Vertices = " +features[4]*FeatureVector.maxIndexVal[4];
		props = props + ", Max. BGP Triples = " +features[5]*FeatureVector.maxIndexVal[5];
		props = props + ", Min BGP Triples  = " +features[6]*FeatureVector.maxIndexVal[6];
		props = props + ", Mean Join Vertex Degree = " +features[7]*FeatureVector.maxIndexVal[7];
		props = props + ", #SPARQL Features  = " +features[8]*FeatureVector.maxIndexVal[8];
			return props;
	}
	/**
	 * Initialize Sesame Repository
	 * @throws RepositoryException
	 */
	private static void initializeRepo() throws RepositoryException {
		rep = new SailRepository(new MemoryStore());
		rep.initialize();
		factory  = rep.getValueFactory();
		conn = rep.getConnection();

	}
	public static void getRDF(Set<String> queryIds, String outputFile, String endpointURL, String method,
			Double similarityScore, long exeTime, Map<String, Double[]> normalizedVectors, Double diversityScore) throws RepositoryException, RDFHandlerException, IOException {
//		initializeRepo();
//		conn.add(factory.createURI("http://qald-gen.aksw.org/benchamrk"), factory.createURI(vocab,"wasGeneratedUsing"), factory.createLiteral(method));
//		conn.add(factory.createURI("http:///qald-gen.aksw.org/benchamrk"), factory.createURI(vocab,"hasGenerationTimeSec"), factory.createLiteral(exeTime));
//		conn.add(factory.createURI("http:///qald-gen.aksw.org/benchamrk"), factory.createURI(vocab,"hasSimilarityError"), factory.createLiteral(similarityScore));
//		conn.add(factory.createURI("http:///qald-gen.aksw.org/benchamrk"), factory.createURI(vocab,"hasDiversityScore"), factory.createLiteral(diversityScore));
		String values = getValues(queryIds);
		Query consQ = QueryFactory.create("Construct {?s ?p ?o} WHERE { ?s ?p ?o values ?s { "+values+"} }");
		QueryExecution qe = QueryExecutionFactory.sparqlService("http://localhost:8890/sparql", consQ);
		com.hp.hpl.jena.rdf.model.Model	 model =  qe.execConstruct() ;
		//model.write(arg0, arg1, arg2)
	//	System.out.println("Total query containment tests: " + (testNo-1));
		//RepositoryResult<Statement> statements =  conn.getStatements(null, null, null, true);
	//	 model = (com.hp.hpl.jena.rdf.model.Model) Iterations.addAll(statements, new LinkedHashModel());
		model.add(model.createResource("http://qald-gen.aksw.org/benchamrk"), model.createProperty("http://qald-gen.aksw.org/vocab#wasGeneratedUsing"), model.createLiteral(method));
		model.add(model.createResource("http://qald-gen.aksw.org/benchamrk"), model.createProperty("http://qald-gen.aksw.org/vocab#hasGenerationTime"), model.createLiteral(""+exeTime+""));
		model.add(model.createResource("http://qald-gen.aksw.org/benchamrk"), model.createProperty("http://qald-gen.aksw.org/vocab#hasSimilarityError"), model.createLiteral(""+similarityScore+""));
		model.add(model.createResource("http://qald-gen.aksw.org/benchamrk"), model.createProperty("http://qald-gen.aksw.org/vocab#hasDiversityScore"), model.createLiteral(""+diversityScore+""));

		writeModel(model,outputFile);
	}
	private static String getValues(Set<String> queryIds) {
		String values ="";
		for (String id:queryIds)
			values = values + "<http://qald-gen.aksw.org/question#"+id+"> ";
		return values;
	}
}
