package eu.dnetlib.enabling.is.sn.resourcestate;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import java.util.Collection;

import eu.dnetlib.test.utils.EPRTestUtil;
import org.junit.Before;
import org.junit.Test;

import eu.dnetlib.enabling.is.sn.SubscriptionRequest;
import eu.dnetlib.enabling.is.sn.rmi.SubscriptionRequestRejectedException;

/**
 * Common tests for resource state subscription registry tests.
 *
 * @author marko
 *
 */
public abstract class AbstractResourceStateSubscriptionRegistryTest {

	/**
	 * star.
	 */
	private static final String STAR = "*";

	/**
	 * create topic prefix.
	 */
	private static final String CREATE = "CREATE";

	/**
	 * test resource type.
	 */
	private static final String SOME_TYPE = "someType";

	/**
	 * test other resource type.
	 */
	private static final String SOME_OTHER_TYPE = "someOtherType";

	/**
	 * test resource id.
	 */
	private static final String SOME_ID = "sub123";

	/**
	 * instance under test.
	 */
	private ResourceStateSubscriptionRegistry registry;

	/**
	 * test subscritpion request.
	 */
	private transient SubscriptionRequest sub;

	/**
	 * setup registry. subclasses should set the dao.
	 */
	@Before
	public void setUpRegistry() {
		registry = new ResourceStateSubscriptionRegistry();

		final SubscriptionRequestFilter filter = new SubscriptionRequestFilter();
		filter.setActive(true);
		registry.setSubscriptionRequestFilter(filter);

		setUpDao();

		sub = new SubscriptionRequest(SOME_ID, EPRTestUtil.getTestEpr(), "CREATE/*/*/someXpath", 0);
	}

	/**
	 * test subscription registration.
	 *
	 * @throws SubscriptionRequestRejectedException
	 */
	@Test
	public void testRegisterSubscription() throws SubscriptionRequestRejectedException {
		registry.registerSubscription(sub);

		final Collection<ResourceStateSubscription> res = registry.listMatchingSubscriptions(CREATE, STAR, STAR);
		for (final ResourceStateSubscription r : res) {
			assertEquals("check add subscription", SOME_ID, r.getSubscriptionId());
		}

		assertEquals("check that is really added", 1, res.size());
	}

	/**
	 * test match.
	 *
	 * @throws SubscriptionRequestRejectedException
	 */
	@Test
	public void testMatch() throws SubscriptionRequestRejectedException {
		registry.registerSubscription(sub);

		ResourceStateSubscription re1 = null; // NOPMD
		ResourceStateSubscription re2 = null; // NOPMD

		final Collection<ResourceStateSubscription> res = registry.listMatchingSubscriptions(CREATE, SOME_TYPE, STAR);
		for (final ResourceStateSubscription r : res) {
			re1 = r; // NOPMD
			assertEquals("check match subscription", SOME_ID, r.getSubscriptionId());
		}

		assertEquals("check that only one matched", 1, res.size());

		final Collection<ResourceStateSubscription> res2 = registry.listMatchingSubscriptions(CREATE, SOME_OTHER_TYPE, STAR);
		for (final ResourceStateSubscription r : res2) {
			re2 = r; // NOPMD
			assertEquals("check match subscription", SOME_ID, r.getSubscriptionId());
		}

		assertEquals("check that only one matched", 1, res2.size());
		assertEquals("check that the same subscription is returned", re1, re2);
	}

	/**
	 * multiple subscriptions should be registered only once.
	 *
	 * @throws SubscriptionRequestRejectedException
	 */
	@Test
	public void testMultiple() throws SubscriptionRequestRejectedException {
		final String subId = registry.registerSubscription(sub);
		final String subId2 = registry.registerSubscription(sub);

		assertEquals("avoid duplicates", subId, subId2);
	}

	/**
	 * test unsubscribe.
	 *
	 * @throws SubscriptionRequestRejectedException
	 */
	@Test
	public void testUnsubscribe() throws SubscriptionRequestRejectedException {
		final String subId = registry.registerSubscription(sub);
		final boolean res = registry.unsubscribe(subId);

		assertTrue("unsubscribed", res);

		final boolean res2 = registry.unsubscribe(subId);

		assertFalse("not unsubscribed", res2);
	}

	/**
	 * subclasses should implement this with a specific instance of the dao.
	 */
	protected abstract void setUpDao();

	public ResourceStateSubscriptionRegistry getRegistry() {
		return registry;
	}

	public void setRegistry(final ResourceStateSubscriptionRegistry registry) {
		this.registry = registry;
	}

}
