/**
 * 
 */
package com.github.podd.api.purl.test;

import java.io.InputStream;
import java.util.Set;

import junit.framework.Assert;

import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.openrdf.model.Statement;
import org.openrdf.model.URI;
import org.openrdf.model.impl.ValueFactoryImpl;
import org.openrdf.repository.Repository;
import org.openrdf.repository.RepositoryConnection;
import org.openrdf.repository.RepositoryResult;
import org.openrdf.repository.sail.SailRepository;
import org.openrdf.rio.RDFFormat;
import org.openrdf.sail.memory.MemoryStore;

import com.github.podd.api.purl.PoddPurlManager;
import com.github.podd.api.purl.PoddPurlProcessorFactoryRegistry;
import com.github.podd.api.purl.PoddPurlReference;

/**
 * Abstract class to test PoddPurlManager.
 * 
 * @author kutila
 */
public abstract class AbstractPoddPurlManagerTest
{
    
    protected static final String TEMP_URI_PREFIX = "urn:temp";
    
    private PoddPurlManager testPurlManager;
    
    private PoddPurlProcessorFactoryRegistry testRegistry;
    
    private Repository testRepository;
    
    private RepositoryConnection testRepositoryConnection;
    
    /**
     * @return A new PoddPurlManager instance for use by this test
     */
    public abstract PoddPurlManager getNewPoddPurlManager();
    
    /**
     * @return A new PurlProcessorFactory Registry for use by this test
     */
    public abstract PoddPurlProcessorFactoryRegistry getNewPoddPurlProcessorFactoryRegistry();
    
    /**
     * Helper method to load RDF statements from the specified resource to the given context in the
     * test Repository.
     * 
     * @param resourcePath
     *            Path to resource from which statements are to be loaded
     * @throws Exception
     */
    private void loadResourceToRepository(final String resourcePath, final URI context) throws Exception
    {
        if(resourcePath != null)
        {
            final InputStream inputStream = this.getClass().getResourceAsStream(resourcePath);
            Assert.assertNotNull("Could not find resource", inputStream);
            this.testRepositoryConnection.add(inputStream, "", RDFFormat.RDFXML, context);
        }
    }
    
    @Before
    public void setUp() throws Exception
    {
        this.testRegistry = this.getNewPoddPurlProcessorFactoryRegistry();
        Assert.assertNotNull("Null implementation of test Registry", this.testRegistry);
        
        this.testPurlManager = this.getNewPoddPurlManager();
        Assert.assertNotNull("Null implementation of test PurlManager", this.testPurlManager);
        
        this.testRepository = new SailRepository(new MemoryStore());
        this.testRepository.initialize();
        
        this.testRepositoryConnection = this.testRepository.getConnection();
        this.testRepositoryConnection.begin(); // Transaction per each test
        
        this.testPurlManager.setPurlProcessorFactoryRegistry(this.testRegistry);
    }
    
    @After
    public void tearDown() throws Exception
    {
        this.testRegistry.clear();
        this.testRepositoryConnection.rollback();
        this.testRepositoryConnection.close();
        this.testRepository.shutDown();
        
        this.testPurlManager = null;
    }
    
    /**
     * Tests that a PurlManager is able to replace temporary URIs in a given context of a Repository
     * with previously generated Purls.
     * 
     * This test makes use of PurlManager.extractPurlReferences() to generate new Purls.
     * 
     * @throws Exception
     */
    @Ignore
    @Test
    public void testConvertTemporaryUris() throws Exception
    {
        final String resourcePath = "/test/artifacts/basicProject-1-internal-object.rdf";
        final URI context = ValueFactoryImpl.getInstance().createURI("urn:testcontext");
        this.loadResourceToRepository(resourcePath, context);
        
        final Set<PoddPurlReference> purlSet =
                this.testPurlManager.extractPurlReferences(this.testRepositoryConnection, context);
        
        this.testPurlManager.convertTemporaryUris(purlSet, this.testRepositoryConnection, context);
        
        final RepositoryResult<Statement> repoContents =
                this.testRepositoryConnection.getStatements(null, null, null, false, context);
        while(repoContents.hasNext())
        {
            final Statement statement = repoContents.next();
            Assert.assertFalse("Temporary URI exists in Subject",
                    AbstractPoddPurlManagerTest.TEMP_URI_PREFIX.contains(statement.getSubject().stringValue()));
            Assert.assertFalse("Temporary URI exists in Object",
                    AbstractPoddPurlManagerTest.TEMP_URI_PREFIX.contains(statement.getObject().stringValue()));
        }
    }
    
    /**
     * Tests that a PurlManager is able to correctly identify temporary URIs in a given context of a
     * Repository and generate Purls for them.
     * 
     * @throws Exception
     */
    public void testExtractPurlReferencesCompareAsNTriples() throws Exception
    {
        final String resourcePath = "/test/artifacts/basicProject-1-internal-object.rdf";
        final URI context = ValueFactoryImpl.getInstance().createURI("urn:testcontext");
        this.loadResourceToRepository(resourcePath, context);
        
        final Set<PoddPurlReference> purlSet =
                this.testPurlManager.extractPurlReferences(this.testRepositoryConnection, context);
        
        Assert.assertNotNull("Extracted Purl references were null", purlSet);
        Assert.assertFalse("Extracted Purl references were empty", purlSet.isEmpty());
        Assert.assertEquals("Incorrect number of Purl references extracted", 3, purlSet.size());
        
        for(final PoddPurlReference purl : purlSet)
        {
            Assert.assertNotNull("Purl has null temporary URI", purl.getTemporaryURI());
            Assert.assertNotNull("Purl has null permanent URI", purl.getPurlURI());
            
            Assert.assertFalse("Purl and Temporary URI were same", purl.getPurlURI().equals(purl.getTemporaryURI()));
            
            // check that the temporary URI is present in the original RDF statements
            final RepositoryResult<Statement> resultSubjects =
                    this.testRepositoryConnection.getStatements(purl.getTemporaryURI(), null, null, false, context);
            if(!resultSubjects.hasNext())
            {
                final RepositoryResult<Statement> resultObjects =
                        this.testRepositoryConnection.getStatements(null, null, purl.getTemporaryURI(), false, context);
                Assert.assertTrue("Temporary URI not found in original RDF statements", resultObjects.hasNext());
            }
            
            // further Purl verification requires implementation awareness
        }
    }
    
    @Test
    public void testGetPurlProcessorFactoryRegistry() throws Exception
    {
        Assert.assertNotNull("getRegistry() returned null", this.testPurlManager.getPurlProcessorFactoryRegistry());
    }
    
    @Test
    public void testSetPurlProcessorFactoryRegistry() throws Exception
    {
        // first set the Registry to Null and verify it
        this.testPurlManager.setPurlProcessorFactoryRegistry(null);
        Assert.assertNull("Registry was not set to null", this.testPurlManager.getPurlProcessorFactoryRegistry());
        
        // set the Registry
        this.testPurlManager.setPurlProcessorFactoryRegistry(this.testRegistry);
        
        Assert.assertNotNull("getRegistry() returned null ", this.testPurlManager.getPurlProcessorFactoryRegistry());
    }
    
}

@@ -6196,17 +6196,8 @@
 eck 
-that the 
 temp
@@ -6251,69 +6251,80 @@
 ents
-%0A            final RepositoryResult%3CStatement%3E result
+ as a subject or object%0A            final boolean tempUriExistsAs
 Subject
-s
  =%0A 
@@ -6429,33 +6429,32 @@
  false, context)
-;
 %0A            if(
@@ -6454,122 +6454,86 @@
     
-if(!resultSubjects.hasNext())%0A            %7B%0A                final RepositoryResult%3CStatement%3E result
+                .hasNext();%0A            final boolean tempUriExistsAs
 Object
-s
  =%0A
-    
     
@@ -6639,30 +6639,65 @@
 se, context)
-;
 %0A
+     
     
+                   .hasNext();%0A
             
@@ -6772,47 +6772,77 @@
 s%22, 
-resultObjects.hasNext());%0A            %7D
+tempUriExistsAsSubject%0A                    %7C%7C tempUriExistsAsObject);
 %0A   

clarify assertion code