package eu.dnetlib.functionality.alert.alerter.batch;

import java.net.URI;
import java.net.URL;
import java.util.SortedSet;

import org.apache.log4j.Logger;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import eu.dnetlib.functionality.alert.alerter.AlerterException;
import eu.dnetlib.functionality.alert.alerter.batch.dao.BatchAlerterDAO;
import eu.dnetlib.functionality.alert.alerter.batch.dao.BatchAlerterDAOException;
import eu.dnetlib.functionality.alert.alerter.batch.domain.BatchAlert;
import eu.dnetlib.functionality.alert.alerter.batch.domain.BatchSubscription;

public class BatchAlerterTransactionHelper {
	private static final Logger logger = Logger.getLogger(BatchAlerterTransactionHelper.class);
	
	private BatchAlerterDAO dao;
	
	/**
	 * Set the DAO.
	 * @param dao the batch alerter DAO to use
	 */
	public void setDao(final BatchAlerterDAO dao) {
		this.dao = dao;
	}
	
	/**
	 * Retrieve a subscription.
	 * @param templateId the unique identifier of the template of the subscription to retrieve
	 * @param notificationService the URL of the notification service of the subscription to retrieve
	 * @param queryId the unique identifier of the query of the subscription to retrieve
	 * @param resultId the unique identifier of the result of the subscription to retrieve
	 * @param alertMode the alert mode of the subscription to retrieve
	 * @param subscriber the URI of the subscriber of the subscription to retrieve
	 * @return the subscription specified or null if no such subscription exists
	 * @throws AlerterException if any errors occur
	 */
	@Transactional(isolation = Isolation.SERIALIZABLE, readOnly = true, rollbackFor = AlerterException.class)
	public BatchSubscription getSubscription(final String templateId, final URL notificationService, final String queryId, final String resultId, final String alertMode, final URI subscriber) throws AlerterException {
		try {
			final BatchSubscription subscription = dao.getSubscription(templateId, notificationService, queryId, resultId, alertMode, subscriber);
			logger.info((subscription == null) ? ("Subscription (template: " + templateId + ", notification service: " + notificationService + ", query: " + queryId + ", result: " + resultId + ", alert mode: " + alertMode +
					", subscriber: " + subscriber + ") does not exist") : ("Retrieved subscription (template: " + templateId + ", notification service: " + notificationService + ", query: " + queryId + ", result: " + resultId + ", alert mode: " + alertMode +
					", subscriber: " + subscriber + ")"));
			return subscription;
		} catch (final BatchAlerterDAOException e) {
			throw new AlerterException("error retrieving subscription (template: " + templateId + ", notification service: " + notificationService + ", query: " + queryId + ", result: " + resultId + ", alert mode: " +
					alertMode + ", subscriber: " + subscriber + ")", e);
		}
	}
	
	/**
	 * Retrieve some of the available alerts.
	 * @param subscription the subscription of the alerts to retrieve
	 * @param limit the maximum number of alerts to retrieve
	 * @param offset the offset to start at
	 * @return a sorted set containing alerts
	 * @throws AlerterException if any errors occur
	 */
	@Transactional(isolation = Isolation.SERIALIZABLE, readOnly = true, rollbackFor = AlerterException.class)
	public SortedSet<BatchAlert> getAlerts(final BatchSubscription subscription, final int limit, final int offset) throws AlerterException {
		try {
			final SortedSet<BatchAlert> alerts = dao.getAlerts(subscription, limit, offset);
			logger.info("Retrieved " + alerts.size() + " alerts for subscription " + subscription + " (limit: " + limit + ", offset: " + offset + ")");
			return alerts;
		} catch (final BatchAlerterDAOException e) {
			throw new AlerterException("error retrieving alerts for subscription " + subscription + " (limit: " + limit + ", offset: " + offset + ")", e);
		}
	}
	
	/**
	 * Remove alerts.
	 * @param subscription the subscription of the alerts to remove
	 * @throws AlerterException if any errors occur
	 */
	@Transactional(isolation = Isolation.SERIALIZABLE, rollbackFor = AlerterException.class)
	public void removeAlerts(final BatchSubscription subscription) throws AlerterException {
		try {
			dao.deleteAlerts(subscription);
			logger.info("Removed alerts of subscription " + subscription);
		} catch (final BatchAlerterDAOException e) {
			throw new AlerterException("error removing alerts of subscription " + subscription, e);
		}
	}

	/**
	 * Add a new alert.
	 * @param alert the alert to add
	 * @throws AlerterException if any errors occur
	 */
	@Transactional(isolation = Isolation.SERIALIZABLE, rollbackFor = AlerterException.class)
	public void addAlert(final BatchAlert alert) throws AlerterException {
		try {
			dao.saveAlert(alert);
			logger.info("Added alert " + alert);
		} catch (final BatchAlerterDAOException e) {
			throw new AlerterException("error adding alert " + alert, e);
		}
	}
}
