package jp.ac.osaka_u.sanken.sparql.plugin.compare;


import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.swing.JFileChooser;

import com.hp.hpl.jena.rdf.model.RDFNode;
import com.ibm.icu.text.SimpleDateFormat;

import jp.ac.osaka_u.sanken.sparql.EndpointSettings;
import jp.ac.osaka_u.sanken.sparql.EndpointSettingsManager;
import jp.ac.osaka_u.sanken.sparql.PlainSparqlAccessor;
import jp.ac.osaka_u.sanken.sparql.SparqlQueryListener;
import jp.ac.osaka_u.sanken.sparql.SparqlResultSet;

public class Compare {

	private HashMap<String, PlainSparqlAccessor> accessorMap;
	private List<String> labels;
	private SparqlQueryListener listener;

	public Compare(File inputFile, File endpointFile){
		this(inputFile, endpointFile, null);
	}


	public Compare(File inputFile, File endpointFile, SparqlQueryListener listener){
		/*
		 * ・Endpointを複数指定する
		 * ・Labelが一行に一つずつ記述されたTextを喰わせる
		 * ・設定はAccessorFormのデータを利用
		 */
		accessorMap = new HashMap<String, PlainSparqlAccessor>();

		loadSetting("settings.xml");

		List<String> endpoints = FileUtil.readFileText(endpointFile, "UTF-8");

		setEndpoint(endpoints);

		labels = FileUtil.readFileText(inputFile, "UTF-8");
//		setLabel();

		this.listener = listener;
	}

	public void addEndpoint(String endpoint){
		EndpointSettings settings = EndpointSettingsManager.instance.getSetting(endpoint);

		PlainSparqlAccessor sa = new PlainSparqlAccessor(settings);
		accessorMap.put(endpoint, sa);
//		sa.findTripleFromSubject("select ?s {?s <http://www.w3.org/2000/01/rdf-schema#label> "+"")
	}

	private void setEndpoint(List<String> endpoints){
		for (String ep : endpoints){
			addEndpoint(ep);
		}
	}


	private Thread thread;
	private boolean finalizeThread = false;

	public void outputResult(int targetType, boolean fullMatch, File out, CompareResultListener listener) {
		thread = new QueryThread(new Object[]{new Integer(targetType), new Boolean(fullMatch), out}, listener){
			public void run(){
				try {
					Integer type = (Integer)((Object[])getOption())[0];
					Boolean fullMatch = (Boolean)((Object[])getOption())[1];
					File file = (File)((Object[])getOption())[2];
					getCompareResultListener().resultReceived(outputResult(type, fullMatch, file));
				} catch(Exception e){
					throw new RuntimeException(e);
				}
			}
		};
		thread.setUncaughtExceptionHandler(listener);
		thread.start();

	}

	public void stop(){
		println(getCurrentTime()+"Stop Request");
		finalizeThread = true;
	}


	public boolean outputResult(int targetType, boolean fullMatch, File out) throws IOException{
		/*
		// header
		System.out.print("\"\",");
		for (String endpoint : accessorMap.keySet()){
			System.out.print("\""+endpoint + "\",");
		}
		System.out.println();

		for (String label : labels){
			System.out.print("\"" + label + "\",");
			for (String endpoint : accessorMap.keySet()){
				SparqlAccessor sa = accessorMap.get(endpoint);
				try {
					List<Map<String, RDFNode>> res  = sa.findSubject(label, true, 10, type);//executeQuery("select ?s {{?s <http://www.w3.org/2000/01/rdf-schema#label> \""+label+"\"@ja} UNION {?s <http://www.w3.org/2000/01/rdf-schema#label> \""+label+"\"@en} UNION {?s <http://www.w3.org/2000/01/rdf-schema#label> \""+label+"\"}}");
					if (res != null && res.size() > 0){
						Map<String, RDFNode> r = res.get(0);
						RDFNode s = r.get("s");
						System.out.print("\"" + s.toString() + "\",");
					} else {
						System.out.print(",");
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			System.out.println();
		}
		*/
		if (out.getParentFile() != null && !out.getParentFile().exists()){
			out.getParentFile().mkdirs();
		}
		out.createNewFile();
		if (!out.canWrite()){
			return false;
		}

		return outputResult(targetType, fullMatch, new PrintWriter(new OutputStreamWriter(new FileOutputStream(out), "SJIS")));
	}

	private boolean outputResult(int targetType, boolean fullMatch, PrintWriter out){
		String typeStr = "all";
		if (targetType == PlainSparqlAccessor.FIND_TARGET_SUBJECT){
			typeStr = "subject";
		}
		if (targetType == PlainSparqlAccessor.FIND_TARGET_SPECIFIC_OBJECT){
			typeStr = "object (label only)";
		}
		if (targetType == PlainSparqlAccessor.FIND_TARGET_OBJECT){
			typeStr = "object";
		}
		println("find type :["+typeStr+"]");
		println("full match :["+fullMatch + "]");

		println("target endpoints:");
		for (String endpoint : accessorMap.keySet()){
			print("["+endpoint + "]");
		}
		println();
		println(getCurrentTime()+"query start.");

		out.print("\"\",");
		for (String endpoint : accessorMap.keySet()){
			out.print("\""+endpoint + "\",");
		}
		out.println();

		int index = 0;

		for (String label : labels){
			print(getCurrentTime()+ "No." + (++index)+":searching :["+label+"].");
			out.print("\"" + label + "\",");
			for (String endpoint : accessorMap.keySet()){
				print("*");
				PlainSparqlAccessor sa = accessorMap.get(endpoint);
				try {
					SparqlResultSet res  = sa.findSubject(label, fullMatch, 10, null, targetType, null);//executeQuery("select ?s {{?s <http://www.w3.org/2000/01/rdf-schema#label> \""+label+"\"@ja} UNION {?s <http://www.w3.org/2000/01/rdf-schema#label> \""+label+"\"@en} UNION {?s <http://www.w3.org/2000/01/rdf-schema#label> \""+label+"\"}}");
					List<Map<String, RDFNode>> list = res.getDefaultResult();
					if (list != null && list.size() > 0){
						Map<String, RDFNode> r = list.get(0);
						RDFNode s = r.get("s");
						out.print("\"" + s.toString() + "\",");
					} else {
						out.print(",");
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
				if (finalizeThread){
					break;
				}
			}
			if (finalizeThread){
				break;
			}
			println();
			out.println();
		}
		out.flush();
		out.close();

		println(getCurrentTime()+"query end.");

		return true;
	}

	private String getCurrentTime(){
		Timestamp time = new Timestamp(new Date().getTime());

		return new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(time) + ":";
	}

	private void println(){
		println("");
	}

	private void println(String str){
		print(str + "\n");
	}

	private void print(String str){
		if (listener != null){
			listener.sparqlExecuted(str);
		}
	}

	private int loadSetting(String settingFile){
		// 出力先決定
		File file = new File(settingFile);
		try {
			EndpointSettings[] settings = EndpointSettings.inputXML(new FileInputStream(file));
			if (settings != null){
				EndpointSettingsManager.instance.setSettings(settings);

				return 0;
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			return JFileChooser.ERROR;
		} finally {
		}
		return JFileChooser.ERROR;
	}

	private class QueryThread extends Thread {

		private Object option;
		private CompareResultListener listener;


		public QueryThread(Object option, CompareResultListener listener){
			this.option = option;
			this.listener = listener;
		}

		protected Object getOption(){
			return this.option;
		}

		protected CompareResultListener getCompareResultListener(){
			return this.listener;
		}

	}
}
