package eu.dnetlib.enabling.is.store;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.annotation.Resource;
import javax.jws.WebService;
import javax.xml.ws.Endpoint;

import com.google.common.collect.Iterators;
import eu.dnetlib.enabling.is.store.rmi.ISStoreException;
import eu.dnetlib.enabling.is.store.rmi.ISStoreService;
import eu.dnetlib.enabling.tools.AbstractBaseService;
import eu.dnetlib.soap.EndpointReferenceBuilder;
import eu.dnetlib.xml.database.XMLDatabase;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.Job;
import org.quartz.JobExecutionException;
import org.xmldb.api.base.XMLDBException;

/**
 * ISStore service implementation.
 * 
 * @author marko
 * 
 */
@WebService(targetNamespace = "http://services.dnetlib.eu/")
public class ISStoreServiceImpl extends AbstractBaseService implements ISStoreService { // NOPMD by marko on 11/24/08

	/**
	 * logger.
	 */
	private static final Log log = LogFactory.getLog(ISStoreServiceImpl.class); // NOPMD by marko on 11/24/08 4:46 PM

	/**
	 * xml database used by the ISStore.
	 */
	private XMLDatabase xmlDatabase;

	/**
	 * Service endpoint.
	 */
	private Endpoint endpoint;

	/**
	 * injected EPR builder.
	 */
	@Resource(name = "jaxwsEndpointReferenceBuilder")
	private EndpointReferenceBuilder<Endpoint> eprBuilder;

	/**
	 * initializer job
	 */
	private Job contentInitializerJob;

	@Override
	public void start() {
		super.start();

		new Thread(new Runnable() {

			@Override
			public void run() {
				try {
					Thread.sleep(500);
					contentInitializerJob.execute(null);
				} catch (JobExecutionException e) {
					log.fatal("failed to initialize xmldb", e);
				} catch (InterruptedException e) {
					log.fatal("failed to initialize xmldb", e);
				}
			}
		}).start();

	}

	/**
	 * web service context (not really useful right now).
	 */
	// @Resource
	// private WebServiceContext context;
	/**
	 * {@inheritDoc}
	 * 
	 * @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#createFileColl(java.lang.String)
	 */
	@Override
	public boolean createFileColl(final String fileColl) throws ISStoreException {
		try {
			xmlDatabase.createCollection(fileColl);
		} catch (XMLDBException e) {
			throw new ISStoreException(e);
		}
		return true;
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#deleteFileColl(java.lang.String)
	 */
	@Override
	public boolean deleteFileColl(final String fileColl) throws ISStoreException {
		try {
			xmlDatabase.removeCollection(fileColl);
		} catch (XMLDBException e) {
			throw new ISStoreException(e);
		}
		return true;
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#deleteXML(java.lang.String, java.lang.String)
	 */
	@Override
	public boolean deleteXML(final String fileName, final String fileColl) throws ISStoreException {
		try {
			return xmlDatabase.remove(fileName, fileColl);
		} catch (XMLDBException e) {
			throw new ISStoreException(e);
		}
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#executeXUpdate(java.lang.String)
	 */
	@Override
	public boolean executeXUpdate(final String query) throws ISStoreException {
		getXMLbyQuery(query);
		return true;
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#getFileColls()
	 */
	@Override
	public List<String> getFileColls() throws ISStoreException {
		try {
			return xmlDatabase.listChildCollections(xmlDatabase.getRootCollection());
		} catch (XMLDBException e) {
			throw new ISStoreException(e);
		}
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#getFileNames(java.lang.String)
	 */
	@Override
	public List<String> getFileNames(final String fileColl) throws ISStoreException {
		try {
			return xmlDatabase.list(fileColl);
		} catch (XMLDBException e) {
			throw new ISStoreException(e);
		}
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#getXML(java.lang.String, java.lang.String)
	 */
	@Override
	public String getXML(final String fileName, final String fileColl) throws ISStoreException {
		try {
			return xmlDatabase.read(fileName, fileColl);
		} catch (XMLDBException e) {
			throw new ISStoreException(e);
		}
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#getXMLbyQuery(java.lang.String)
	 */
	@Override
	public String getXMLbyQuery(final String query) throws ISStoreException {
		log.debug(query);

		try {
			final Iterator<String> res = xmlDatabase.xquery(query);
			if (res == null) return null;
			if (!res.hasNext()) return null;
			return res.next();
		} catch (XMLDBException e) {
			throw new ISStoreException(e);
		}
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#insertXML(java.lang.String, java.lang.String, java.lang.String)
	 */
	@Override
	public boolean insertXML(final String fileName, final String fileColl, final String file) throws ISStoreException {
		try {
			xmlDatabase.create(fileName, fileColl, file);
		} catch (XMLDBException e) {
			throw new ISStoreException(e);
		}
		return true;
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#quickSearchXML(java.lang.String)
	 */
	@Override
	public List<String> quickSearchXML(final String query) throws ISStoreException {
		log.debug(query);
		try {
			final Iterator<String> res = xmlDatabase.xquery(query);
			if (res == null) return new ArrayList<>();

			final ArrayList<String> ans = new ArrayList<String>();
			Iterators.addAll(ans, res);
			return ans;
		} catch (XMLDBException e) {
			log.fatal("searching", e);
			throw new ISStoreException(e);
		}
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#reindex()
	 */
	@Override
	public boolean reindex() {
		return true;
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#sync()
	 */
	@Override
	public boolean sync() {
		log.info("TEST: " + endpoint);

		return true;
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#updateXML(java.lang.String, java.lang.String, java.lang.String)
	 */
	@Override
	public boolean updateXML(final String fileName, final String fileColl, final String file) throws ISStoreException {
		try {
			xmlDatabase.update(fileName, fileColl, file);
		} catch (XMLDBException e) {
			throw new ISStoreException(e);
		}
		return true;
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#backup()
	 */
	@Override
	public String backup() throws ISStoreException {
		try {
			return xmlDatabase.backup();
		} catch (Exception e) {
			throw new ISStoreException(e);
		}
	}

	public XMLDatabase getXmlDatabase() {
		return xmlDatabase;
	}

	public void setXmlDatabase(final XMLDatabase xmlDatabase) {
		this.xmlDatabase = xmlDatabase;
	}

	@Override
	public boolean isRunning() {
		return true;
	}

	public Endpoint getEndpoint() {
		return endpoint;
	}

	public void setEndpoint(final Endpoint endpoint) {
		this.endpoint = endpoint;
	}

	protected EndpointReferenceBuilder<Endpoint> getEprBuilder() {
		return eprBuilder;
	}

	protected void setEprBuilder(final EndpointReferenceBuilder<Endpoint> eprBuilder) {
		this.eprBuilder = eprBuilder;
	}

	public Job getContentInitializerJob() {
		return contentInitializerJob;
	}

	public void setContentInitializerJob(final Job contentInitializerJob) {
		this.contentInitializerJob = contentInitializerJob;
	}

}
