package eu.dnetlib.enabling.is.sn;

import static org.junit.Assert.assertNotNull;
import static org.mockito.Matchers.argThat;
import static org.mockito.Mockito.verify;

import java.io.IOException;
import java.io.StringReader;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateNotificationDetector;
import eu.dnetlib.enabling.tools.OpaqueResource;

/**
 * Test NotificationTriggerImpl, a simple forwarder.
 * 
 * @author marko
 * 
 */
@RunWith(MockitoJUnitRunner.class)
public class NotificationTriggerImplTest {

	/**
	 * Check that the resource has the expected properties.
	 * 
	 * @author marko
	 * 
	 */
	private static final class MatchResource implements ArgumentMatcher<OpaqueResource> {
		/**
		 * {@inheritDoc}
		 * 
		 * @see org.mockito.ArgumentMatcher#matches(java.lang.Object)
		 */
		@Override
		public boolean matches(final OpaqueResource argument) {
			return argument.getResourceId().equals("123") && argument.getResourceType().equals("type") && argument.getResourceKind().equals("kind");
		}
	}

	/**
	 * test old document version.
	 */
	private static final String OLD_DOC = "<RESOURCE_PROFILE><HEADER><RESOURCE_KIND value=\"kind\"/><RESOURCE_TYPE value=\"type\"/><RESOURCE_IDENTIFIER value=\"123\"/></HEADER><BODY>old</BODY></RESOURCE_PROFILE>";

	/**
	 * test old document version.
	 */
	private static final String NEW_DOC = "<RESOURCE_PROFILE><HEADER><RESOURCE_KIND value=\"kind\"/><RESOURCE_TYPE value=\"type\"/><RESOURCE_IDENTIFIER value=\"123\"/></HEADER><BODY>new</BODY></RESOURCE_PROFILE>";

	/**
	 * class under test.
	 */
	private transient NotificationTriggerImpl trigger;

	/**
	 * detector mock.
	 */
	@Mock
	private transient ResourceStateNotificationDetector<OpaqueResource> detector;

	/**
	 * common preparation.
	 * 
	 */
	@Before
	public void setUp() {
		trigger = new NotificationTriggerImpl();
		trigger.setName("test trigger");
		trigger.setDetector(detector);
	}

	/**
	 * test created.
	 * 
	 * @throws IOException
	 *             never
	 * @throws SAXException
	 *             never
	 * @throws ParserConfigurationException
	 *             never
	 */

	@Test
	public void testCreated() throws ParserConfigurationException, SAXException, IOException {
		trigger.created("someFile", "someCollection", parse(NEW_DOC));
		verify(detector).resourceCreated(argThat(new MatchResource()));

		assertNotNull("dummy", detector);
	}

	/**
	 * test deleted.
	 * 
	 * @throws IOException
	 *             never
	 * @throws SAXException
	 *             never
	 * @throws ParserConfigurationException
	 *             never
	 */
	@Test
	public void testDeleted() throws ParserConfigurationException, SAXException, IOException {
		trigger.deleted("someFile", "someCollection", parse(OLD_DOC));
		verify(detector).resourceDeleted(argThat(new MatchResource()));

		assertNotNull("dummy", detector);
	}

	/**
	 * test updated.
	 * 
	 * @throws IOException
	 *             never
	 * @throws SAXException
	 *             never
	 * @throws ParserConfigurationException
	 *             never
	 */
	@Test
	public void testUpdated() throws ParserConfigurationException, SAXException, IOException {
		trigger.updated("someFile", "someCollection", parse(OLD_DOC), parse(NEW_DOC));
		verify(detector).resourceUpdated(argThat(new MatchResource()), argThat(new MatchResource()));

		assertNotNull("dummy", detector);
	}

	/**
	 * helper method.
	 * 
	 * @param source
	 *            xml source
	 * @return DOM object
	 * @throws ParserConfigurationException
	 *             shouldn't happen
	 * @throws SAXException
	 *             shouldn't happen
	 * @throws IOException
	 *             shouldn't happen
	 */
	private Document parse(final String source) throws ParserConfigurationException, SAXException, IOException {
		final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
		return builder.parse(new InputSource(new StringReader(source)));
	}

}
