package jp.ac.osaka_u.sanken.sparql;

import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.LinkedHashMap;

public class EndpointSettings implements Serializable {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = -6928422841511501314L;

	public static final int RESULT_TYPE_XML = 0;

	public static final int RESULT_TYPE_JSON = 1;

	public static final int RESULT_TYPE_SSE = 2;

	public static final int RESULT_TYPE_TSV = 3;

	public static final String RESULT_TYPE_XML_STR = "XML/RDF";

	public static final String RESULT_TYPE_JSON_STR = "JSON";

	public static final String RESULT_TYPE_SSE_STR = "SPARQL Syntax Expressions";

	public static final String RESULT_TYPE_TSV_STR = "TSV";

	private static HashMap<String, Integer> dataTypeMap;

	
	private String endpoint;
	
	private boolean useCustomParam = false;
	
	private String queryKey = "q";

	private String option = "type=json&LIMIT=100";

	private String encoding = "UTF-8";
	
	private String namespaces = "";
	
	private int resultType = EndpointSettings.RESULT_TYPE_JSON;
	
	private boolean editable = false;

	private String repositoryURL;

	private String repository;
	
	private String user;
	
	private String pass;

	static {
		dataTypeMap = new LinkedHashMap<String, Integer>();
		dataTypeMap.put(RESULT_TYPE_XML_STR, new Integer(RESULT_TYPE_XML));
		dataTypeMap.put(RESULT_TYPE_JSON_STR, new Integer(RESULT_TYPE_JSON));
		dataTypeMap.put(RESULT_TYPE_SSE_STR, new Integer(RESULT_TYPE_SSE));
		dataTypeMap.put(RESULT_TYPE_TSV_STR, new Integer(RESULT_TYPE_TSV));

	}

	public EndpointSettings(){
		
	}

	
	public EndpointSettings(String endpoint){
		this.endpoint = endpoint;
		
		this.namespaces = makeDefaultNamespaces(endpoint);
		
		makeDefaultRepository(endpoint);
	}
	
	private String makeDefaultNamespaces(String endpoint){
		String ret = "";
		
		if (endpoint == null){
			return ret;
		}

		// endpoint最後の"/"を削除
		if (endpoint.endsWith("/")){
			endpoint = endpoint.substring(0, endpoint.length() - "/".length());
		}
		int index = endpoint.lastIndexOf("/");
		if (index > 0){
			endpoint = endpoint.substring(0, index);
		}

		ret = endpoint + "/class," + endpoint + "/instance," + endpoint + "/resource";
		
		
		return ret;
	}
	
	private void makeDefaultRepository(String endpoint){
		int index = endpoint.indexOf("/endpoint/");
		if (index >= 0){
			this.repositoryURL = endpoint.substring(0, index);
			this.repository = endpoint.substring(index + "/endpoint/".length());
		}
		
	}
	
	/**
	 * @return endpoint
	 */
	public String getEndpoint() {
		return endpoint;
	}

	/**
	 * @param endpoint セットする endpoint
	 */
	public void setEndpoint(String endpoint) {
		this.endpoint = endpoint;
	}

	/**
	 * @return useCustomParam
	 */
	public boolean isUseCustomParam() {
		return useCustomParam;
	}

	/**
	 * @param useCustomParam セットする useCustomParam
	 */
	public void setUseCustomParam(boolean useCustomParam) {
		this.useCustomParam = useCustomParam;
	}

	/**
	 * @return queryKey
	 */
	public String getQueryKey() {
		return queryKey;
	}

	/**
	 * @param queryKey セットする queryKey
	 */
	public void setQueryKey(String queryKey) {
		this.queryKey = queryKey;
	}

	/**
	 * @param namespaces セットする namespaces
	 */
	public void setNamespaces(String namespaces) {
		this.namespaces = namespaces;
	}

	/**
	 * @return namespaces
	 */
	public String getNamespaces() {
		return namespaces;
	}
	
	public String[] getNamespaceList(){
		return namespaces.split(",");
	}

	/**
	 * @return option
	 */
	public String getOption() {
		return option;
	}

	/**
	 * @param option セットする option
	 */
	public void setOption(String option) {
		this.option = option;
	}

	/**
	 * @return encoding
	 */
	public String getEncoding() {
		return encoding;
	}

	/**
	 * @param encoding セットする encoding
	 */
	public void setEncoding(String encoding) {
		this.encoding = encoding;
	}

	/**
	 * @param resultType セットする resultType
	 */
	public void setResultType(int resultType) {
		this.resultType = resultType;
	}

	/**
	 * @return resultType
	 */
	public int getResultType() {
		return resultType;
	}
	
	/**
	 * @return editable
	 */
	public boolean isEditable() {
		return editable;
	}


	/**
	 * @param editable セットする editable
	 */
	public void setEditable(boolean editable) {
		this.editable = editable;
	}


	/**
	 * @return repositoryURL
	 */
	public String getRepositoryURL() {
		return repositoryURL;
	}


	/**
	 * @param repositoryURL セットする repositoryURL
	 */
	public void setRepositoryURL(String repositoryURL) {
		this.repositoryURL = repositoryURL;
	}


	/**
	 * @return repository
	 */
	public String getRepository() {
		return repository;
	}


	/**
	 * @param repository セットする repository
	 */
	public void setRepository(String repository) {
		this.repository = repository;
	}


	/**
	 * @return user
	 */
	public String getUser() {
		return user;
	}


	/**
	 * @param user セットする user
	 */
	public void setUser(String user) {
		this.user = user;
	}


	/**
	 * @return pass
	 */
	public String getPass() {
		return pass;
	}


	/**
	 * @param pass セットする pass
	 */
	public void setPass(String pass) {
		this.pass = pass;
	}


	/* 以下はutilクラスにわけるほうがいい？ */
	

	public static String[] getResultDataTypeList(){
		return dataTypeMap.keySet().toArray(new String[]{});
	}
	
	public static Integer getResultDataType(String str){
		return dataTypeMap.get(str);
	}

	public static String getResultDataType(Integer type){
		for (String key : dataTypeMap.keySet()){
			if (dataTypeMap.get(key).equals(type)){
				return key;
			}
		}
		
		return null;
	}

	public static void outputXML(OutputStream os, EndpointSettings[] settings){
		XMLEncoder enc = new XMLEncoder(os);
		enc.writeObject(settings);
		enc.close();
	}
	
	public static EndpointSettings[] inputXML(InputStream is){
		XMLDecoder dec = new XMLDecoder(is);
		EndpointSettings[] ret = (EndpointSettings[])dec.readObject();
		
		return ret;
	}
	
}
