package eu.dnetlib.oai.sync;

import java.util.concurrent.Callable;

import eu.dnetlib.oai.conf.OAIConfigurationExistReader;
import eu.dnetlib.oai.mongo.MongoPublisherStore;
import eu.dnetlib.oai.mongo.MongoPublisherStoreDAO;
import eu.dnetlib.rmi.provision.OaiPublisherException;
import eu.dnetlib.rmi.provision.OaiPublisherRuntimeException;
import eu.dnetlib.utils.MetadataReference;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;

public class OAIStoreSynchronizer {

	private static final Log log = LogFactory.getLog(OAIStoreSynchronizer.class); // NOPMD by marko on 11/24/08 5:02 PM
	/**
	 * OAI Publisher configuration.
	 */
	@Autowired
	private OAIConfigurationExistReader configuration;
	@Autowired
	private MongoPublisherStoreDAO publisherStoreDAO;

	public void synchronize(final Iterable<String> records,
			final MetadataReference sourceMetadataFormat,
			final String recordSource,
			final String dbName,
			final boolean alwaysNewRecord,
			final Callable<?> callback,
			final Callable<?> failCallback) {
		try {
			log.fatal("Synchronizing content for source metadata format " + sourceMetadataFormat);
			log.fatal("Record source: "+recordSource);
			MongoPublisherStore store = this.getStore(sourceMetadataFormat, dbName, alwaysNewRecord);
			int count = store.feed(records, recordSource);

			log.info("Content synchronized: store " + sourceMetadataFormat + " fed with " + count + " records");
			executeCallback(callback);
		} catch (Exception e) {
			log.error(e);
			executeCallback(failCallback);
		}
	}

	/**
	 * Gets the OAI store for the given source metadata format. If the store does not exists, then a new one is created.
	 *
	 * @param mdRef MDFInfo about the metadata format of the store to get
	 * @return a MongoPublisherStore instance
	 */
	private MongoPublisherStore getStore(final MetadataReference mdRef, final String dbName, final boolean alwaysNewRecord) {
		this.publisherStoreDAO.setAlwaysNewRecord(alwaysNewRecord);
		MongoPublisherStore store = this.publisherStoreDAO.getStore(mdRef.getFormat(), mdRef.getInterpretation(), mdRef.getLayout(), dbName);
		if (store == null) {
			log.debug("Creating store for metadata format: \n" + mdRef + " in db: " + dbName);
			try {
				store = this.publisherStoreDAO.createStore(mdRef.getFormat(), mdRef.getInterpretation(), mdRef.getLayout(), dbName);
				log.debug("Created store with id: " + store.getId());
			} catch (OaiPublisherException e) {
				throw new OaiPublisherRuntimeException(e);
			}
		}
		return store;
	}

	protected void executeCallback(final Callable<?> callback) {
		if (callback != null) {
			try {
				callback.call();
			} catch (Exception e) {
				log.error("Error executing callback", e);
			}
		}
	}

	public OAIConfigurationExistReader getConfiguration() {
		return configuration;
	}

	public void setConfiguration(final OAIConfigurationExistReader configuration) {
		this.configuration = configuration;
	}

	public MongoPublisherStoreDAO getPublisherStoreDAO() {
		return publisherStoreDAO;
	}

	public void setPublisherStoreDAO(final MongoPublisherStoreDAO publisherStoreDAO) {
		this.publisherStoreDAO = publisherStoreDAO;
	}

}
