package eu.dnetlib.data.textengine.ws;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.jws.WebService;
import javax.xml.ws.wsaddressing.W3CEndpointReference;

import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.dom4j.io.DocumentResult;

import eu.dnetlib.common.interfaces.ws.ServiceException;
import eu.dnetlib.common.nh.Notification;
import eu.dnetlib.common.utils.XMLException;
import eu.dnetlib.common.utils.XMLUtils;
import eu.dnetlib.common.ws.DriverServiceImpl;
import eu.dnetlib.common.ws.dataprov.DataProviderException;
import eu.dnetlib.common.ws.dataprov.ResultsResponse;
import eu.dnetlib.data.textengine.ITextEngineService;
import eu.dnetlib.data.textengine.RecognizeType;
import eu.dnetlib.enabling.resultset.rmi.ResultSetService;


@WebService(serviceName="TextEngineService",
		endpointInterface="eu.dnetlib.data.textengine.ITextEngineService",
		targetNamespace="http://schemas.xmlsoap.org/soap/envelope/")
public class TextEngineServiceFacade extends DriverServiceImpl implements ITextEngineService{

	private TextEngineDataProviderImpl dataProvider;
	private String serviceAddress;
	private String resultsetAddress;
	private String dataProviderAddress;
	
	private ResultSetService resultsetService;
	
	/**
	 * @return the dataProvider
	 */
	public TextEngineDataProviderImpl getDataProvider() {
		return dataProvider;
	}

	/**
	 * @param dataProvider the dataProvider to set
	 */
	public void setDataProvider(TextEngineDataProviderImpl dataProvider) {
		this.dataProvider = dataProvider;
	}

	public void init(){
		log.debug(notifier.toString());
		this.addListener(notifier);
	};
	
	
	/* (non-Javadoc)
	 * @see eu.dnetlib.data.textengine.ITextEngineService#recognize(java.lang.String, eu.dnetlib.data.textengine.RecognizeType)
	 */
	public String recognize(String text, RecognizeType recognize_type)
			throws ServiceException {
		String language = "";
		Notification notification = new Notification();
		Map<String, String> parameters = new HashMap<String, String>();
		parameters.put(NotificationParameter.TEXT, text);
		//parameters.put(NotificationParameter.TYPE, "GETRECORD");
		notification.setParameters(parameters);
		language = this.getNotifier().processRequest(notification);
		return language;
	}
	
	/* (non-Javadoc)
	 * @see eu.dnetlib.data.textengine.ITextEngineService#recognizeRS(java.lang.String, eu.dnetlib.data.textengine.RecognizeType)
	 */
	public W3CEndpointReference recognizeRS(W3CEndpointReference epr, RecognizeType recognize_type)
			throws ServiceException {
		log.debug("TextEngine: recognizeRS");
		// optional blacklist, whitelist
		W3CEndpointReference langEpr = null;
		try {
			log.debug("epr: " + epr.toString());
			Map<String, String> nsMap = new HashMap<String, String>();
			nsMap.put("ResourceIdentifier", "http://www.driver.org");
			XMLUtils.setNamespaces(nsMap);
			DocumentResult infoset = new DocumentResult();
			epr.writeTo(infoset);
			String rsId = XMLUtils.evaluate(infoset.getDocument(), "//ResourceIdentifier:ResourceIdentifier/text()");
			String rsLocation = XMLUtils.evaluate(infoset.getDocument(), "//*[local-name()='Address']");
			log.debug("rsLocation: " + rsLocation);
			log.debug("rsId: " + rsId);
			
            JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
            factory.setServiceClass(ResultSetService.class);
            factory.setAddress(rsLocation);
            ResultSetService remoteRsService = (ResultSetService) factory.create();
			
			log.debug("resultset identify: " + remoteRsService.identify());
			String rsType = remoteRsService.getProperty(rsId, "rsType");
			log.debug("rsType " + rsType + " for rsId: " + rsId);
			
			TextEngineDataProviderProperties dataProps = dataProvider.createDataProviderProperties();
			//dataProps.setWhiteList(whiteList);
			//dataProps.setBlacklist(blacklist);
			dataProps.setEpr(epr);
			dataProps.setRsType(rsType);
			
			String bdId = dataProvider.createBulkData(dataProps);
			int initialPageSize = 50;
			int expiryTime = 5000;
			int keepAliveTime = 5000;
			String stylesheet = "";
			int total = remoteRsService.getNumberOfElements(rsId);
			
			log.debug("dataprovAddress: " + dataProviderAddress + " bdId: " + bdId +
					" initPageSize: " + initialPageSize + " expTime: " + expiryTime + 
					" keepalive: " + keepAliveTime + " total: " + total );
			log.debug("internal resultset: " + resultsetService.identify());

			langEpr = resultsetService.createPullRS(dataProviderAddress, bdId, 
					initialPageSize, expiryTime, stylesheet, 
					Integer.valueOf(keepAliveTime), Integer.valueOf(total));
			if (langEpr == null){
				log.error("langEpr is null");
			} 
			
		} catch (XMLException e) {
			log.error(e);
			throw new ServiceException(e);
		} catch (Exception e) {
			log.error(e);
			throw new ServiceException(e);
		}

		return langEpr;
	}
	
	/* (non-Javadoc)
	 * @see eu.dnetlib.data.textengine.ITextEngineService#recognizeFile(java.lang.String)
	 */
	public String recognizeFile(String file) throws ServiceException {
		String language = "";
		Notification notification = new Notification();
		Map<String, String> parameters = new HashMap<String, String>();
		parameters.put(NotificationParameter.FILE, file);
		notification.setParameters(parameters);
		try{
			language = this.getNotifier().processRequest(notification);			
		}catch(Exception e){
			log.error(e);
			throw new ServiceException("error occured when processing 'recognizeFile'," + e.getMessage(), e);
		}
		return language;
	}

	public List<String> getBulkData(String bd_id, int fromPosition, int toPosition)
			throws DataProviderException {
		return dataProvider.getBulkData(bd_id, fromPosition, toPosition);
	}

	public ResultsResponse getNumberOfResults(String bd_id)
			throws DataProviderException {
		return dataProvider.getNumberOfResults(bd_id);
	}

	/**
	 * @param serviceAddress the serviceAddress to set
	 */
	public void setServiceAddress(String serviceAddress) {
		this.serviceAddress = serviceAddress;
	}

	/**
	 * @return the serviceAddress
	 */
	public String getServiceAddress() {
		return serviceAddress;
	}

	/**
	 * @param resultsetAddress
	 */
	public void setResultsetAddress(String resultsetAddress) {
		this.resultsetAddress = resultsetAddress;
	}

	/**
	 * @return the resultset address
	 */
	public String getResultsetAddress() {
		return resultsetAddress;
	}
	
	public void setDataProviderAddress(String dataProviderAddress) {
		this.dataProviderAddress = dataProviderAddress;
	}

	public String getDataProviderAddress() {
		return dataProviderAddress;
	}

	public ResultSetService getResultsetService() {
		return resultsetService;
	}

	public void setResultsetService(ResultSetService resultsetService) {
		this.resultsetService = resultsetService;
	}
	
}
