package eu.dnetlib.functionality.alert.dao;

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

import eu.dnetlib.domain.functionality.AlertSubscription;
import eu.dnetlib.domain.functionality.AlertTemplate;

/**
 * This bean implements alert DAO using sets to store templates and subscriptions in memory. It does not support transactions at all.
 * @author thanos@di.uoa.gr
 *
 */
public class MockAlertDAO implements AlertDAO {
	private final SortedSet<AlertTemplate> templates;
	private final SortedSet<AlertSubscription> subscriptions;
	
	public MockAlertDAO() {
		templates = new TreeSet<AlertTemplate>();
		subscriptions = new TreeSet<AlertSubscription>();
	}

	@Override
	public int countTemplates() {
		return templates.size();
	}

	@Override
	public SortedSet<AlertTemplate> getTemplates(final int limit, final int offset) {
		final SortedSet<AlertTemplate> result = new TreeSet<AlertTemplate>();
		int i = 0;
		for (AlertTemplate template : templates) {
			if (i < offset) // skip
				i++;
			else if (i < offset + limit) { // add to result
				result.add(template);
				i++;
			} else // done
				break;
		}
		return result;
	}

	@Override
	public AlertTemplate getTemplate(final String templateId) {
		for (AlertTemplate template : templates) {
			if (template.getTemplateId().equals(templateId))
				return template;
		}
		return null;
	}

	@Override
	public void saveTemplate(final AlertTemplate template) {
		templates.add(template);
	}

	@Override
	public void deleteTemplate(final String templateId) {
		for (Iterator<AlertTemplate> i = templates.iterator(); i.hasNext(); ) { // remove template
			if (i.next().getTemplateId().equals(templateId)) {
				i.remove();
				break;
			}
		}
		for (Iterator<AlertSubscription> i = subscriptions.iterator(); i.hasNext(); ) { // remove subscriptions
			if (i.next().getTemplateId().equals(templateId))
				i.remove();
		}
	}

	@Override
	public int countSubscriptions() {
		return subscriptions.size();
	}

	@Override
	public SortedSet<AlertSubscription> getSubscriptions(final int limit, final int offset) {
		final SortedSet<AlertSubscription> result = new TreeSet<AlertSubscription>();
		int i = 0;
		for (AlertSubscription subscription : subscriptions) {
			if (i < offset) // skip
				i++;
			else if (i < offset + limit) { // add to result
				result.add(subscription);
				i++;
			} else // done
				break;
		}
		return result;
	}
	
	@Override
	public SortedSet<AlertSubscription> getSubscriptions(final String alertMode, final String subscriber, final int limit, final int offset) {
		final SortedSet<AlertSubscription> result = new TreeSet<AlertSubscription>();
		int i = 0;
		for (AlertSubscription subscription : subscriptions) {
			if (i < offset) { // skip
				if (subscription.getAlertMode().equals(alertMode) && subscription.getSubscriber().toString().startsWith(subscriber))
					i++;
			} else if (i < offset + limit) { // add to result
				if (subscription.getAlertMode().equals(alertMode) && subscription.getSubscriber().toString().startsWith(subscriber)) {
					result.add(subscription);
					i++;
				}
			} else // done
				break;
		}
		return result;
	}

	@Override
	public SortedSet<AlertSubscription> getEnabledSubscriptions(final int limit, final int offset) {
		final SortedSet<AlertSubscription> result = new TreeSet<AlertSubscription>();
		int i = 0;
		for (AlertSubscription subscription : subscriptions) {
			if (i < offset) { // skip
				if (subscription.isEnabled())
					i++;
			} else if (i < offset + limit) { // add to result
				if (subscription.isEnabled()) {
					result.add(subscription);
					i++;
				}
			} else // done
				break;
		}
		return result;
	}
	
	@Override
	public SortedSet<AlertSubscription> getEnabledSubscriptions(final URL notificationService, final String queryId, final int limit, final int offset) {
		final SortedSet<AlertSubscription> result = new TreeSet<AlertSubscription>();
		int i = 0;
		for (AlertSubscription subscription : subscriptions) {
			if (i < offset) { // skip
				if (subscription.isEnabled() && subscription.getNotificationService().equals(notificationService) && subscription.getQueryId().equals(queryId))
					i++;
			} else if (i < offset + limit) { // add to result
				if (subscription.isEnabled() && subscription.getNotificationService().equals(notificationService) && subscription.getQueryId().equals(queryId)) {
					result.add(subscription);
					i++;
				}
			} else // done
				break;
		}
		return result;
	}

	@Override
	public AlertSubscription getSubscription(final String templateId, final URL notificationService, final String queryId, final String resultId, final String alertMode, final URI subscriber) {
		for (AlertSubscription subscription : subscriptions) {
			if (subscription.getTemplateId().equals(templateId) && subscription.getNotificationService().equals(notificationService) && subscription.getQueryId().equals(queryId) && subscription.getResultId().equals(resultId) &&
					subscription.getAlertMode().equals(alertMode) && subscription.getSubscriber().equals(subscriber))
				return subscription;
		}
		return null;
	}

	@Override
	public void saveSubscription(final AlertSubscription subscription) throws AlertDAOException {
		subscriptions.add(subscription);
	}

	@Override
	public void deleteSubscription(final String templateId, final URL notificationService, final String queryId, final String resultId, final String alertMode, final URI subscriber) {
		for (Iterator<AlertSubscription> i = subscriptions.iterator(); i.hasNext(); ) {
			final AlertSubscription subscription = i.next();
			if (subscription.getTemplateId().equals(templateId) && subscription.getNotificationService().equals(notificationService) && subscription.getQueryId().equals(queryId) && subscription.getResultId().equals(resultId) &&
					subscription.getAlertMode().equals(alertMode) && subscription.getSubscriber().equals(subscriber)) {
				i.remove();
				return;
			}
		}
	}
}
