package it.unibz.inf.ontop.owlapi;

/**
 * Test case for Rais ontology.
 * Problem with OPTIONAL when the left join is having on the right multiple mappings
 */

import it.unibz.inf.ontop.injection.OntopSQLOWLAPIConfiguration;
import it.unibz.inf.ontop.owlapi.connection.OWLConnection;
import it.unibz.inf.ontop.owlapi.connection.OWLStatement;
import it.unibz.inf.ontop.owlapi.impl.SimpleOntopOWLEngine;
import it.unibz.inf.ontop.owlapi.resultset.OWLBindingSet;
import it.unibz.inf.ontop.owlapi.resultset.TupleOWLResultSet;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Connection;
import java.sql.DriverManager;

import static it.unibz.inf.ontop.utils.OWLAPITestingTools.executeFromFile;
import static org.junit.Assert.assertEquals;

public class LeftJoinMultipleMatchingTest {
    private final Logger log = LoggerFactory.getLogger(this.getClass());

    private static final String owlFile = "src/test/resources/ljoptional/rais-ontology.owl";
    private static final String obdaFile = "src/test/resources/ljoptional/rais-ontology-small.obda";

    private Connection sqlConnection;

    static final String URL = "jdbc:h2:mem:raisjunit";
    static final String USER = "sa";
    static final String PASSWORD = "";

    @Before
    public void setUp() throws Exception {
        sqlConnection = DriverManager.getConnection(URL, USER, PASSWORD);
        executeFromFile(sqlConnection, "src/test/resources/ljoptional/rais-create-h2.sql");
    }

    @After
    public void tearDown() throws Exception{
        if (!sqlConnection.isClosed()) {
            executeFromFile(sqlConnection, "src/test/resources/ljoptional/rais-drop-h2.sql");
            sqlConnection.close();
        }
    }

    @Test
    public void testRaisNoOptional() throws Exception {
        executeSelectQuery("PREFIX owl: <http://www.w3.org/2002/07/owl#>\n" +
                "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>\n" +
                "PREFIX rais: <http://www.ontorais.de/>\n" +
                "SELECT DISTINCT ?ao ?title ?date WHERE {\n" +
                "?ao a rais:ArchiveObject .\n" +
                "?ao rais:title ?title.\n" +
                "?ao rais:archivalDate ?date.\n" +
                "}");
    }

    @Test
    public void testRaisOptional() throws Exception {
        executeSelectQuery("PREFIX owl: <http://www.w3.org/2002/07/owl#>\n" +
                "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>\n" +
                "PREFIX rais: <http://www.ontorais.de/>\n" +
                "SELECT DISTINCT ?ao ?title ?date WHERE {\n" +
                "?ao a rais:ArchiveObject .\n" +
                "?ao rais:title ?title.\n" +
                " OPTIONAL{ ?ao rais:archivalDate ?date.}\n" +
                "}");
    }

    @Test
    public void testOptionalQuery() throws Exception {
        executeSelectQuery("PREFIX owl: <http://www.w3.org/2002/07/owl#>\n" +
                "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>\n" +
                "PREFIX rais: <http://www.ontorais.de/>\n" +
                "SELECT DISTINCT ?ao ?date WHERE {\n" +
                "?ao a rais:ArchiveObject .\n" +
                " OPTIONAL{ ?ao rais:archivalDate ?date.}\n" +
                "}\n");
    }

    private void executeSelectQuery(String query) throws Exception {

        // Creating a new instance of the reasoner
        OntopSQLOWLAPIConfiguration config = OntopSQLOWLAPIConfiguration.defaultBuilder()
                .ontologyFile(owlFile)
                .nativeOntopMappingFile(obdaFile)
                .jdbcUrl(URL)
                .jdbcUser(USER)
                .jdbcPassword(PASSWORD)
                .enableTestMode()
                .build();

        try (OntopOWLEngine reasoner = new SimpleOntopOWLEngine(config);
                OWLConnection conn = reasoner.getConnection();
                OWLStatement st = conn.createStatement()) {

            log.debug("Executing query: ");
            log.debug("Query: \n{}", query);

            long start = System.nanoTime();
            TupleOWLResultSet res = st.executeSelectQuery(query);
            long end = System.nanoTime();

            int count = 0;
            while (res.hasNext()) {
                OWLBindingSet binding = res.next();
                count++;
            }
            log.debug("Total result: {}", count);
            assertEquals(2, count);
            log.debug("Elapsed time: {} ms", (end - start) / 1_000_000);
        }
    }
}

