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

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

import java.util.Collection;

import org.apache.commons.beanutils.BeanComparator;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;

/**
 * testing MemoryResourceStateSubscriptionDAOImpl.
 * 
 * @author marko
 * 
 */
public abstract class AbstractResourceStateSubscriptionDAOImplTest {

	/**
	 * update topic prefix.
	 */
	private static final String UPDATE = "UPDATE";

	/**
	 * 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 = "123";

	/**
	 * class under test.
	 */
	private ResourceStateSubscriptionDAO dao;

	/**
	 * test subscription.
	 */
	private transient ResourceStateSubscription sub;

	/**
	 * test subscription.
	 */
	private transient ResourceStateSubscription sub2;

	/**
	 * test subscription.
	 */
	private transient ResourceStateSubscription sub3;

	/**
	 * test subscription.
	 */
	private transient ResourceStateSubscription sub4;

	/**
	 * test subscription.
	 */
	private transient ResourceStateSubscription sub5;
	
	/**
	 * common setup.
	 */
	@Before
	public void setUp() {
		prepareDao();

		sub = new ResourceStateSubscription();
		sub.setSubscriptionId("sn123");
		sub.setPrefix(CREATE);
		sub.setType(SOME_TYPE);
		sub.setXpath("somePath");

		sub2 = new ResourceStateSubscription();
		sub2.setSubscriptionId("sn666");
		sub2.setPrefix(UPDATE);
		sub2.setType(SOME_TYPE);
		sub2.setXpath("somePath");

		sub3 = new ResourceStateSubscription();
		sub3.setSubscriptionId("sn000");
		sub3.setPrefix(CREATE);
		sub3.setType(SOME_TYPE);
		sub3.setXpath("somePath");

		sub4 = new ResourceStateSubscription();
		sub4.setSubscriptionId("sn987");
		sub4.setPrefix(CREATE);
		sub4.setType("*");
		sub4.setResourceId(SOME_ID);
		
		sub5 = new ResourceStateSubscription();
		sub5.setSubscriptionId("sn888");
		sub5.setPrefix(UPDATE);
		sub5.setType(SOME_TYPE);
		sub5.setResourceId(SOME_ID);
	}

	/**
	 * subsclasses should implement this in order to plug their implementation of the dao.
	 */
	protected abstract void prepareDao();

	/**
	 * compare two subscriptions.
	 * 
	 * @param left
	 *            lhs
	 * @param right
	 *            rhs
	 * @return true if the objects are equal
	 */
	protected boolean compare(final ResourceStateSubscription left, final ResourceStateSubscription right) {
		return new BeanComparator("subscriptionId").compare(left, right) == 0 && new BeanComparator("prefix").compare(left, right) == 0
		&& new BeanComparator("type").compare(left, right) == 0 && new BeanComparator("resourceId").compare(left, right) == 0;
	}

	/**
	 * test list subscriptions for prefix and type.
	 */
	@Test
	public void testListSubscriptionsStringString() {
		dao.addSubscription(sub);
		dao.addSubscription(sub2);
		dao.addSubscription(sub3);
		dao.addSubscription(sub4);

		for (ResourceStateSubscription s : dao.listSubscriptions(UPDATE, SOME_TYPE, SOME_ID))
			assertTrue("check subscription", compare(s, sub2));

		assertEquals("check size", 2, dao.listSubscriptions(CREATE, SOME_TYPE, "*").size());

		for (ResourceStateSubscription s : dao.listSubscriptions(CREATE, "*", SOME_ID))
			assertTrue("check subscription star", compare(s, sub4));

		assertEquals("check size star", 1, dao.listSubscriptions(CREATE, "*", SOME_ID).size());	
	}
	
	/**
	 * enable this test when the manual merging of subscriptions is removed from the ResourceStateSubscriptionRegistry.
	 * The ResourceState subscription DAO alone should be able to quickly resolve wildcards. 
	 */
	@Test
	@Ignore
	public void testListSubscriptionsStar() {
		dao.addSubscription(sub);
		dao.addSubscription(sub2);
		dao.addSubscription(sub3);
		dao.addSubscription(sub4);

		for (ResourceStateSubscription s : dao.listSubscriptions(CREATE, SOME_OTHER_TYPE, SOME_ID))
			assertTrue("check subscription fixed star", compare(s, sub4));

		assertEquals("check size fixed tar", 1, dao.listSubscriptions(CREATE, SOME_OTHER_TYPE, SOME_ID).size());

	}

	/**
	 * test get a specific subscription by id.
	 */
	@Test
	public void testGetSubscription() {

		dao.addSubscription(sub);

		assertNotNull("check that it's registered", dao.getSubscription(sub.getSubscriptionId()));
	}

	/**
	 * test list all subscriptions.
	 */
	@Test
	public void testListSubscriptions() {
		dao.addSubscription(sub);
		for (ResourceStateSubscription s : dao.listSubscriptions())
			assertTrue("check subscription", compare(s, sub));

		assertEquals("check size", 1, dao.listSubscriptions().size());
	}
	
	/**
	 * test specific subscription.
	 */
	@Test
	public void testSpecificSubscription() {
		dao.addSubscription(sub5);
		
		final Collection<ResourceStateSubscription> res = dao.listSubscriptions(UPDATE, SOME_TYPE, SOME_ID);
		assertEquals("only one", 1, res.size());
		
		assertNotNull("", res.iterator().next());
	}

	/**
	 * test list subscriptions for a given prefix.
	 */
	@Test
	public void testListSubscriptionsString() {
		dao.addSubscription(sub);
		dao.addSubscription(sub2);

		for (ResourceStateSubscription s : dao.listSubscriptions(UPDATE))
			assertTrue("check subscription", compare(s, sub2));
	}

	public ResourceStateSubscriptionDAO getDao() {
		return dao;
	}

	public void setDao(final ResourceStateSubscriptionDAO dao) {
		this.dao = dao;
	}

	public ResourceStateSubscription getSub() {
		return sub;
	}

	public void setSub(final ResourceStateSubscription sub) {
		this.sub = sub;
	}

	public ResourceStateSubscription getSub2() {
		return sub2;
	}

	public void setSub2(final ResourceStateSubscription sub2) {
		this.sub2 = sub2;
	}

	public ResourceStateSubscription getSub3() {
		return sub3;
	}

	public void setSub3(final ResourceStateSubscription sub3) {
		this.sub3 = sub3;
	}

	public ResourceStateSubscription getSub4() {
		return sub4;
	}

	public void setSub4(final ResourceStateSubscription sub4) {
		this.sub4 = sub4;
	}

}
