package org.aksw.simba.benchmark.startup;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.aksw.simba.benchmark.Config;
import org.aksw.simba.benchmark.Queries;
import org.aksw.simba.benchmark.Similarity;
import org.aksw.simba.benchmark.clustring.QueryClustering;
import org.aksw.simba.benchmark.clustring.VoronoiPanel;
import org.aksw.simba.benchmark.comparisons.AvgStats;
import org.aksw.simba.benchmark.log.operations.CleanQueryReader;
import org.yooreeka.algos.clustering.hierarchical.Dendrogram;
import org.yooreeka.algos.clustering.hierarchical.SingleLinkAlgorithm;
import org.yooreeka.algos.clustering.model.DataPoint;

import com.hp.hpl.jena.query.Query;
import com.hp.hpl.jena.query.QueryFactory;
import com.hp.hpl.jena.query.Syntax;

/**
 * From  here you start your benchmark generation
 * @author Saleem
 *
 */
public class QuerySelecter {
	Map<String, Double[]> normalizedVectors;	
	
	public void initialze() throws IOException {
		//--Configuration and input files specifications ------------
		String queryFileWithStats = "SWDF-CleanQueries.txt";
		//String queryFileWithStats = "DBpedia3.5.1-CleanQueries.txt";
		int numberOfQueries = 6;  // number of queries (5) to be generated for a benchmark
				
		selectCustomFilters();
		long curTime = System.currentTimeMillis();
//		Set<String> queries = Queries.getBenchmarkQueries(queryFileWithStats,10);
						
		normalizedVectors = CleanQueryReader.getFeaturesVectors(queryFileWithStats);
				
		Map<Integer, double[]> distanceTable = getDistanceTable(normalizedVectors);	
		DataPoint[] elements = new DataPoint[normalizedVectors.keySet().size()];
		Set<String> keySet = normalizedVectors.keySet();
		String[] keys = keySet.toArray(new String[keySet.size()]);
		
		for(int n=0; n<normalizedVectors.keySet().size(); n++) {
			double[] value = distanceTable.get(n);
			elements[n] = new DataPoint(keys[n], value);
		}
		SingleLinkAlgorithm sla = new SingleLinkAlgorithm(elements, distanceTable);
		Dendrogram dnd = sla.cluster();
		String[] queries = dnd.print(numberOfQueries);
		
		Set<String> queriesIds = new HashSet<>();			
				
		Set<String> cSet = new HashSet<String>();
		for(int c = 0; c < queries.length; c++) {	
			String curCluster =queries[c];
			cSet.clear();
			
			String[] prts =  curCluster.replace("{", "").replace("}", "").replace("\n", "").split(",");
			for(String prt:prts) {
				cSet.add(prt);
			}
			if(cSet.size()==1)
				queriesIds.add(cSet.toArray()[0].toString());
			else
			queriesIds.add(new QueryClustering().getMostRepresentative(normalizedVectors, cSet));
//			clusters.add(queries[c]);
		}
		System.out.println(queriesIds);		
		for(String qry:queriesIds){
		    System.out.println("------------------\n"+qry);
		    }
		Set<String> benchmarkQueriesIds = new HashSet<String>(queriesIds); //we need to copy the query ids here/ later being used for similarity calculation. The next function will clear the queriesIds. So we have to copy before
		Set<String> fqueries = CleanQueryReader.getQueriesWithStats(queryFileWithStats,queriesIds); // they are actual queries
		int queryNo = 1;
		for(String qry:fqueries){
		    System.out.println(queryNo+"------------------\n"+qry);
		          queryNo++;
		    }
		String outputDir = "E:/Thesis/Workspace/New_Implementation_Feasible/benchmarks/";
		printBenchmarkQueries(fqueries,outputDir);
		System.out.println("\n-----\nBenchmark details saved to "+outputDir+"\nBenchmark generation time (sec): "+(System.currentTimeMillis()-curTime)/1000);
		
		Double similarityScore = Similarity.getSimilarityScore(CleanQueryReader.getNormalizedFeaturesVectors(queryFileWithStats),benchmarkQueriesIds);
		System.out.println("Similarity Error : " + similarityScore);
//		VoronoiPanel.drawVoronoiDiagram(normalizedVectors,outputDir+"voronoi.png");
		System.out.println("------------Detailed Analysis of the Generated Benchmark--------------");
		 AvgStats.getPercentUsedLogConstructs(outputDir+"queries-stats.txt");
//	
	}

		/**
	 * Print benchmark queries into console
	 * @param queries queries
	 * @param outputDir output dir
	 * @throws IOException 
	 */
	public static void printBenchmarkQueries(Set<String> queries, String outputDir) throws IOException {
		System.out.println("Total Queries: "+ queries.size());
		int count = 1;
		BufferedWriter	bwq= new BufferedWriter(new FileWriter(outputDir+"queries.txt")); //queries writer
		BufferedWriter	bw= new BufferedWriter(new FileWriter(outputDir+"queries-stats.txt"));
		for(String queryStr:queries)
		{
			String stats = "";
			//System.out.println(queryStr);
			String [] qryParts = queryStr.split("Query String:");
			Query query = QueryFactory.create(qryParts[1].trim());
			stats = "#-------------------------------------------------------\n";
			bwq.write(stats);
			stats=stats+"Query No: "+count+"\n";
			if(query.isAskType())
				stats=stats+"Query Type: ASK\n";
			else if (query.isConstructType())
				stats=stats+"Query Type: SELECT\n";
			else if (query.isDescribeType())
				stats=stats+"Query Type: DESCRIBE\n";
			else if (query.isSelectType())
				stats=stats+"Query Type: SELECT\n";
			stats=stats+qryParts[0];
			//System.out.print(stats);
			bwq.write(qryParts[1].trim()+"\n");
			//System.out.println("Query String: "+qryParts[1].trim());
			stats=stats+"Query String: "+java.net.URLEncoder.encode(qryParts[1].trim(), "UTF-8")+"\n";
			bw.write(stats);
			count++;
		}
		bw.write("#--end---");
		bwq.close();
  bw.close();
	}

	private Map<Integer, double[]> getDistanceTable(Map<String, Double[]> vectors) {
		Map<Integer, double[]> distance = new HashMap<>();	
		int size = vectors.keySet().size();
		for(int i=0; i<vectors.keySet().size(); i++) {
			double[] features = new double[size];
			int index = 0;
			for(int j=i; j<vectors.keySet().size(); j++) {					
				features[index] =new QueryClustering().getDistance(vectors.get(" "+i), vectors.get(" "+j));	
				index++;
			}
			distance.put(i, features);	
			size--;
		}		
		return distance;
			
	}


	public static void main(String[] args) throws IOException  {
//		QuerySelecter qs = new QuerySelecter();
//		qs.initialze();
		System.out.println("Successful");
	}
	/**
	 * Customize your benchmark by activating various filters. See examples below
	 */
	private static void selectCustomFilters() {
		Config.drawVoronoiDiagram = true ;
		// You can set various Filters on benchmark query features and SPARQL clauses . e.g  Resultsize should be between 5 to 10 and BGPs must be greater than 2
		// and Triple patterns should be less or equal to 10 or Mean triple pattern selectivity >= 0.0001
		//See the config file for further deatils
		//Config.featureFilter = "(RunTime >= 50)";
		//Config.featureFilter = "(ResultSize >= 5 AND ResultSize <= 100 AND BGPs >= 2 AND TriplePatterns <=10) OR (MeanTriplePatternsSelectivity >= 0.0001)";
		//Config.clauseFilter = "(OPTIONAL AND DISTINCT) OR (UNION)";
		//Config.featureFilter = "(ResultSize >= 100 AND TriplePatternsCount >= 2 AND TriplePatternsCount <= 5)";
		//Config.clauseFilter = "(DISTINCT AND FILTER) OR (GROUPBY)";
		//------ You can turn on/of basic query types -----
		//Config.ASK =false;
		//Config.DESCRIBE = false; 
		//Config.SELECT=false;
		//Config.CONSTRUCT = false;

	}



}
