package eu.dnetlib.data.mdstore.modular.mongodb.utils;

import java.io.StringReader;
import java.util.List;
import javax.xml.ws.Endpoint;

import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import com.mongodb.client.MongoCollection;
import eu.dnetlib.data.mdstore.MDStoreServiceException;
import eu.dnetlib.data.mdstore.modular.connector.MDStoreDao;
import eu.dnetlib.data.mdstore.modular.mongodb.MDStoreDaoImpl;
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpException;
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService;
import eu.dnetlib.enabling.locators.UniqueServiceLocator;
import eu.dnetlib.soap.EndpointReferenceBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;
import org.springframework.beans.factory.annotation.Required;

public class MetadataCheckJob {

	private static final Log log = LogFactory.getLog(MetadataCheckJob.class); // NOPMD by marko on 11/24/08 5:02 PM

	/**
	 * service locator.
	 */
	private UniqueServiceLocator serviceLocator;

	/**
	 * {@link Endpoint}
	 */
	private Endpoint endpoint;

	/**
	 * {@link EndpointReferenceBuilder}
	 */
	private EndpointReferenceBuilder<Endpoint> eprBuilder;

	/**
	 * MDStore dao.
	 */
	private MDStoreDao dao;

	private boolean runOnStart;

	public void runOnStart() throws MDStoreServiceException {
		if (isRunOnStart()) {
			log.info("running mdStore metadata check on service start");
			repairMetadata();
		}
	}

	/**
	 * Job execution method.
	 *
	 * @throws MDStoreServiceException in case of ISLookUpException or DocumentException
	 */
	public void repairMetadata() throws MDStoreServiceException {
		MongoCollection<DBObject> metadata = ((MDStoreDaoImpl) getDao()).getDb().getCollection("metadata", DBObject.class);
		if (metadata.count() != 0) {
			log.debug("mdStore metadata doesn't need to be repaired");
			return;
		}
		try {
			List<String> mdStores =
					serviceLocator.getService(ISLookUpService.class).quickSearchProfile(
							"//RESOURCE_PROFILE[" +
									".//RESOURCE_TYPE/@value='MDStoreDSResourceType' and " +
									".//RESOURCE_URI/@value='" + getServiceAddress() + "']");

			log.debug("repairing mdstore metadata");

			if (mdStores != null) {
				for (String MDStoreProfile : mdStores) {
					final DBObject mdInfo = getMdInfo(MDStoreProfile);
					metadata.findOneAndReplace(new BasicDBObject("mdId", mdInfo.get("mdId")), mdInfo);
				}
			}
			log.debug("FINISHED repairing mdstore metadata");

		} catch (ISLookUpException | DocumentException e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * Helper method, gets an MDStore profile and returns a DBObject.
	 *
	 * @param MDStoreProfile as obtain from the IS
	 * @return a DBObject representing the metadata informations
	 * @throws DocumentException when parsing invalid xml
	 */
	private DBObject getMdInfo(final String MDStoreProfile) throws DocumentException {
		Document doc = new SAXReader().read(new StringReader(MDStoreProfile));

		DBObject dbo = new BasicDBObject();
		dbo.put("mdId", doc.valueOf("//RESOURCE_IDENTIFIER/@value"));
		dbo.put("format", doc.valueOf("//METADATA_FORMAT/text()"));
		dbo.put("layout", doc.valueOf("//METADATA_FORMAT_LAYOUT/text()"));
		dbo.put("interpretation", doc.valueOf("//METADATA_FORMAT_INTERPRETATION/text()"));
		dbo.put("size", doc.valueOf("//NUMBER_OF_RECORDS/text()"));

		return dbo;
	}

	private String getServiceAddress() {
		return getEprBuilder().getAddress(getEndpoint()) + "?wsdl";
	}

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

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

	public Endpoint getEndpoint() {
		return endpoint;
	}

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

	public MDStoreDao getDao() {
		return dao;
	}

	@Required
	public void setDao(final MDStoreDao dao) {
		this.dao = dao;
	}

	public boolean isRunOnStart() {
		return runOnStart;
	}

	@Required
	public void setRunOnStart(final boolean runOnStart) {
		this.runOnStart = runOnStart;
	}

	public UniqueServiceLocator getServiceLocator() {
		return serviceLocator;
	}
	
	@Required
	public void setServiceLocator(UniqueServiceLocator serviceLocator) {
		this.serviceLocator = serviceLocator;
	}

}
