/**
 * 
 */
package eu.dnetlib.helpers.data.search;

import eu.dnetlib.api.data.BrowseDataNotAvailableException;
import eu.dnetlib.api.data.SearchService;
import eu.dnetlib.api.data.SearchServiceException;
import eu.dnetlib.clients.data.search.ws.SearchWebService;
import eu.dnetlib.clients.data.search.ws.SearchWebServiceClient;
import eu.dnetlib.domain.EPR;
import eu.dnetlib.domain.data.BrowseData;
import gr.uoa.di.driver.enabling.resultset.ResultSet;
import gr.uoa.di.driver.enabling.resultset.ResultSetFactory;
import gr.uoa.di.driver.web.search.BrowseDataUtil;

import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;

/**
 * @author stoumpos
 *
 */
public class SearchServiceClientMain {
	
	public static void main(String[] args) {
		
		BasicConfigurator.configure();
		Logger.getRootLogger().setLevel(Level.WARN);
		// turn-on logging for clients package
		Logger.getLogger("eu.dnetlib.data.search.app").setLevel(Level.DEBUG);
		// turn-on logging for specific class
		//Logger.getLogger(ResultSet.class).setLevel(Level.DEBUG);
		
		JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
		if (false) {
			factory.getInInterceptors().add(new LoggingInInterceptor());
			factory.getOutInterceptors().add(new LoggingOutInterceptor());
		}
		factory.setServiceClass(SearchWebService.class);
		factory.setAddress("http://localhost:8090/app/services/searchWebService");
		SearchWebService webservice = (SearchWebService) factory.create();
		SearchService search = new SearchWebServiceClient();
		((SearchWebServiceClient) search).setWebService(webservice);
		
		// SEARCH:
		callSearch(search, "test");
		callSearch(search, "tenon-existent-st");
		
		// REFINE: creator, contributor, publisher, source,
		// subject, CobjCategory, language, repositoryName
		List<String> fields = new ArrayList<String>();
		fields.add("creator");
		fields.add("contributor");
		fields.add("publisher");
		fields.add("source");
		fields.add("subject");
		fields.add("CobjCategory");
		fields.add("language");
		fields.add("repositoryName");  
		callRefine(search, "test", fields);
		
		// BROWSE: CobjCategory, language, repositoryName
		callBrowse(search, "d", "CobjCategory");
		callBrowse(search, "", "language");
		callBrowse(search, "a", "language");
		callBrowse(search, "G", "repositoryCountry");
		callBrowse(search, "a", "repositoryName");
	}
	
	private static void callSearch(SearchService search, String query) {
		try {
			System.out.println("Search for \"" + query + "\"...");
			EPR epr = search.search(query);
			System.out.println("Response EPR: " + epr);
			printRS(ResultSetFactory.createResultSet(epr));
			
		} catch (SearchServiceException sse) {
			System.err.println("Error searching for \"" + query + "\": "
					+ sse.getMessage());
			sse.printStackTrace();
		}
	}

	private static void callRefine(SearchService search,
			String query, Collection<String> fields) {
		try {
			System.out.println("Refine \"" + query + "\" for " + fields + "...");
			EPR epr = search.refine(query, fields);
			System.out.println("Response EPR: " + epr);
			BrowseData data = createBD(ResultSetFactory.createResultSet(epr));
			System.out.println(data.toString());
			
		} catch (SearchServiceException sse) {
			System.err.println("Error refining query \"" + query + "\": "
					+ sse.getMessage());
			sse.printStackTrace();
		}
	}

	private static void callBrowse(SearchService search,
			String prefix, String field) {
		try {
			System.out.println("Browse field " + field + " for prefix \"" + prefix + "\" ");
			BrowseData data = search.browse(prefix, field);
			System.out.println("browse data: "
					+ data.getFields().size() + " field(s)");
			System.out.println(data.toString());
			
		} catch (BrowseDataNotAvailableException bdna) {
			System.out.println("Error getting browsing data: "
					+ bdna.getMessage());
		} catch (SearchServiceException sse) {
			System.err.println("Error browsing \"" + field + "\": "
					+ sse.getMessage());
			sse.printStackTrace();
		}
	}

	private static BrowseData createBD(ResultSet<String> rs) {
		BrowseData data = new BrowseData();
		
		int n = rs.size();
		int count = 0;
		int page = 1000;
		System.out.println("Total records: "+ n);
		while (count < n) {
			System.out.println("start: " + (count+1)
					+ " -- end: " + Math.min(count+page, n));
			List<String> list = rs.get(count+1, Math.min(count+page, n));
			for (int i = 0; i < list.size(); i++) {
				String record = list.get(i);
				count++;
				//System.out.print("[" + (count) + "/" + n + "] ");
				//System.out.print("add " + record.replaceAll("\n", " "));
				//System.out.println("");
				if (record == null || record.trim().equals("")) {
					System.out.println("skipping empty record...");
				} else {
					BrowseDataUtil.addFieldEntry(data, record);
				}
			}
		}
		
		return data;
	}

	private static void printRS(ResultSet<String> rs) {
		int n = rs.size();
		int p = 500; // page size
		int count = 0;
		System.out.println("Numbeer of documents in RS: " + rs.size());
		while (count < n) {
			List<String> list = rs.get(count+1, Math.min(count+p, n));
			for (int i = 0; i < list.size(); i++) {
				String text = list.get(i).replace("\n", " ");
				count++;
				System.out.print("[" + (count) + "] " + md5Hash(text));
				//System.out.print(" " + list.get(i).replace("\n", " "));
				System.out.println("");
			}
		}
	}
	
	private static String md5Hash(String data) {
		try {
			MessageDigest m = MessageDigest.getInstance("MD5");
			m.update(data.getBytes());
			BigInteger bint = new BigInteger(1, m.digest());
			return bint.toString(16);
			
		} catch (NoSuchAlgorithmException nsae) {
			throw new RuntimeException("Failed to find MD5 algorithm.", nsae);
		}
	}
}


