/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
 *   SPDX-License-Identifier: Apache-2.0
 */

package org.apache.jena.query.text;

import java.io.File ;
import java.io.Reader ;
import java.io.StringReader ;
import java.util.Arrays ;
import java.util.HashSet ;
import java.util.Set ;

import org.apache.jena.assembler.Assembler ;
import org.apache.jena.atlas.lib.StrUtils ;
import org.apache.jena.query.Dataset ;
import org.apache.jena.query.text.assembler.TextAssembler ;
import org.apache.jena.rdf.model.Model ;
import org.apache.jena.rdf.model.ModelFactory ;
import org.apache.jena.rdf.model.Resource ;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import org.apache.jena.vocabulary.RDFS;
import org.apache.jena.vocabulary.SKOS;

/**
 * This class defines a setup configuration for a dataset that uses a standard analyzer with a Lucene index.
 */
public class TestTextPropLists02 extends AbstractTestDatasetWithTextIndexBase {
    private static final String INDEX_PATH = "target/test/TestDatasetWithLuceneIndex";
    private static final File indexDir = new File(INDEX_PATH);

    private static final String RES_BASE = "http://example.org/resource#";
    private static final String SPEC_BASE = "http://example.org/spec#";
    private static final String SPEC_ROOT_LOCAL = "lucene_text_dataset";
    private static final String SPEC_ROOT_URI = SPEC_BASE + SPEC_ROOT_LOCAL;

    protected static final String TURTLE_PROLOG2 =
            StrUtils.strjoinNL(
                    "@prefix  res:  <" + RES_BASE + "> .",
                    "@prefix  spec: <" + SPEC_BASE + "> .",
                    "@prefix text: <http://jena.apache.org/text#> .",
                    "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .",
                    "@prefix skos: <http://www.w3.org/2004/02/skos/core#> ."
                    );
    protected static final String QUERY_PROLOG2 =
            StrUtils.strjoinNL(
                    "prefix res:  <" + RES_BASE + "> ",
                    "prefix spec: <" + SPEC_BASE + "> ",
                    "prefix text: <http://jena.apache.org/text#> ",
                    "prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> ",
                    "prefix skos: <http://www.w3.org/2004/02/skos/core#> "
                    );

    private static final String SPEC;
    static {
        SPEC = StrUtils.strjoinNL(
                    "prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> ",
                    "prefix skos: <http://www.w3.org/2004/02/skos/core#> ",
                    "prefix ja:   <http://jena.hpl.hp.com/2005/11/Assembler#> ",
                    "prefix tdb:  <http://jena.hpl.hp.com/2008/tdb#> ",
                    "prefix text: <http://jena.apache.org/text#> ",
                    "prefix spec: <" + SPEC_BASE + "> ",
                    "",
                    "[] ja:loadClass       \"org.apache.jena.query.text.TextQuery\" .",
                    "text:TextDataset      rdfs:subClassOf   ja:RDFDataset .",
                    "text:TextIndexLucene  rdfs:subClassOf   text:TextIndex .",

                    "spec:" + SPEC_ROOT_LOCAL,
                    "    a              text:TextDataset ;",
                    "    text:dataset   spec:dataset ;",
                    "    text:index     spec:indexLucene ;",
                    "    .",
                    "",
                    "spec:dataset",
                    "    a               ja:RDFDataset ;",
                    "    ja:defaultGraph spec:graph ;",
                    ".",
                    "spec:graph",
                    "    a               ja:MemoryModel ;",
                    ".",
                    "",
                    "spec:indexLucene",
                    "    a text:TextIndexLucene ;",
                    "    text:directory   \"mem\" ;",
                    "    text:storeValues true ;",
                    "    text:entityMap   spec:entMap ;",
                    "#    text:multilingualSupport true ;",
                    "    text:propLists (",
                    "      [ text:propListProp spec:labels ;",
                    "        text:props ( skos:prefLabel ",
                    "                     skos:altLabel ",
                    "                     rdfs:label ) ;",
                    "      ]",
                    "      [ text:propListProp spec:workStmts ;",
                    "        text:props ( rdfs:comment ",
                    "                     spec:workColophon ",
                    "                     spec:workAuthorshipStatement ",
                    "                     spec:workEditionStatement ) ;",
                    "      ]",
                    "    )",
                    "    .",
                    "",
                    "spec:entMap",
                    "    a text:EntityMap ;",
                    "    text:entityField      \"uri\" ;",
                    "    text:defaultField     \"label\" ;",
                    "    text:langField        \"lang\" ;",
                    "    text:graphField       \"graph\" ;",
                    "    text:map (",
                    "#         [ text:field \"label\" ; text:predicate rdfs:label ]",
                    "         [ text:field \"label\" ; ",
                    "           text:predicate rdfs:label ;",
                    "           text:analyzer [ a text:StandardAnalyzer ; text:stopWords ( 'foo'  'bar' ) ]",
                    "         ]",
                    "         [ text:field \"altLabel\" ; text:predicate skos:altLabel ]",
                    "         [ text:field \"prefLabel\" ; text:predicate skos:prefLabel ]",
                    "         [ text:field \"comment\" ; text:predicate rdfs:comment ]",
                    "         [ text:field \"workAuthorshipStatement\" ; text:predicate spec:workAuthorshipStatement ]",
                    "         [ text:field \"workEditionStatement\" ; text:predicate spec:workEditionStatement ]",
                    "         [ text:field \"workColophon\" ; text:predicate spec:workColophon ]",
                    "         ) ."
                    );
    }

    public void init() {
        Reader reader = new StringReader(SPEC);
        Model specModel = ModelFactory.createDefaultModel();
        specModel.read(reader, "", "TURTLE");
        TextAssembler.init();
        indexDir.mkdirs();
        Resource root = specModel.getResource(SPEC_ROOT_URI);
        dataset = (Dataset) Assembler.general().open(root);
    }


    public void deleteOldFiles() {
        dataset.close();
        if (indexDir.exists()) TextSearchUtil.emptyAndDeleteDirectory(indexDir);
    }

    @BeforeEach public void beforeClass() {
        init();
    }

    @AfterEach public void afterClass() {
        deleteOldFiles();
    }

    @Test
    public void test02ForExpectation01() {
        final String turtle = StrUtils.strjoinNL(
                TURTLE_PROLOG2,
                "res:oneThing rdfs:label 'bar the barfoo foo'",
                "."
                );
        String qyString = StrUtils.strjoinNL(
                QUERY_PROLOG2,
                "SELECT ?s",
                "WHERE {",
                "    ?s text:query 'barfoo' .",
                "}"
                );
        Set<String> expectedURIs = new HashSet<>() ;
        expectedURIs.addAll( Arrays.asList(RES_BASE+"oneThing")) ;
        doTestSearch(turtle, qyString, expectedURIs);
    }

    @Test
    public void testForExpectation02() {
        final String turtle = StrUtils.strjoinNL(
                TURTLE_PROLOG2,
                "res:oneThing rdfs:label 'bar the barfoo foo'",
                "."
                );
        // the standard analyzer not to have 'the' as a stop word
        String qyString = StrUtils.strjoinNL(
                QUERY_PROLOG2,
                "SELECT ?s",
                "WHERE {",
                "    ?s text:query ( rdfs:label 'barfoo' 10 ) .",
                "}"
                );
        Set<String> expectedURIs = new HashSet<>() ;
        expectedURIs.addAll( Arrays.asList(RES_BASE+"oneThing")) ;
        doTestSearch(turtle, qyString, expectedURIs);
    }

    @Test
    public void testForExpectation03() {
        final String turtle = StrUtils.strjoinNL(
                TURTLE_PROLOG2,
                "res:oneThing skos:prefLabel 'bar the barfoo foo'",
                "."
                );
        // the standard analyzer not to have 'the' as a stop word
        String qyString = StrUtils.strjoinNL(
                QUERY_PROLOG2,
                "SELECT ?s",
                "WHERE {",
                "    ?s text:query ( skos:prefLabel 'bar' 10 ) .",
                "}"
                );
        Set<String> expectedURIs = new HashSet<>() ;
        expectedURIs.addAll( Arrays.asList(RES_BASE+"oneThing")) ;
        doTestSearch(turtle, qyString, expectedURIs);
    }

    @Test
    public void testSingleTextProp01() {
        final String turtle = StrUtils.strjoinNL(
                TURTLE_PROLOG2,
                "res:oneThing rdfs:label 'bar is surely the barfoo foo for me and you'",
                "."
                );
        // the standard analyzer not to have 'the' as a stop word
        String qyString = StrUtils.strjoinNL(
                QUERY_PROLOG2,
                "SELECT ?s",
                "WHERE {",
                "    (?ss ?sc ?lit ?g ?s) text:query ( rdfs:label 'surely' 10 ) .",
                "}"
                );
        Set<String> expectedURIs = new HashSet<>() ;
        expectedURIs.addAll( Arrays.asList(RDFS.getURI()+"label")) ;
        doTestSearch(turtle, qyString, expectedURIs);
    }

    @Test
    public void testSingleTextProp02() {
        final String turtle = StrUtils.strjoinNL(
                TURTLE_PROLOG2,
                "res:oneThing skos:altLabel 'bar is surely the barfoo foo for me and you'",
                "."
                );
        // the standard analyzer not to have 'the' as a stop word
        String qyString = StrUtils.strjoinNL(
                QUERY_PROLOG2,
                "SELECT ?s",
                "WHERE {",
                "    (?ss ?sc ?lit ?g ?s) text:query ( skos:altLabel 'surely' 10 'highlight:' ) .",
                "}"
                );
        Set<String> expectedURIs = new HashSet<>() ;
        expectedURIs.addAll( Arrays.asList(SKOS.getURI()+"altLabel")) ;
        doTestSearch(turtle, qyString, expectedURIs);
    }

    @Test
    public void testListTextProp01() {
        final String turtle = StrUtils.strjoinNL(
                TURTLE_PROLOG2,
                "res:oneThing skos:prefLabel \"bar the barfoo foo is hidden\"",
                "."
                );
        String qyString = StrUtils.strjoinNL(
                QUERY_PROLOG2,
                "SELECT ?s",
                "WHERE {",
                "    (?ss ?sc ?lit ?g ?s) text:query ( spec:labels 'foo' 10 ) .",
                "}"
                );
        Set<String> expectedURIs = new HashSet<>() ;
        expectedURIs.addAll( Arrays.asList(SKOS.getURI()+"prefLabel")) ;
        doTestSearch(turtle, qyString, expectedURIs);
    }

    @Test
    public void testListTextProp02() {
        final String turtle = StrUtils.strjoinNL(
                TURTLE_PROLOG2,
                "",
                "res:oneThing skos:prefLabel \"bar the barfoo foo is hidden\" ",
                ".",
                "res:twoThing skos:altLabel \"there is no bar to the hidden foo of the flow\" ",
                ".",
                "res:threeThing rdfs:label \"if there had been a f o o then it would not bar a hit\" ",
                "."
                );
        String qyString = StrUtils.strjoinNL(
                QUERY_PROLOG2,
                "",
                "SELECT ?s",
                "WHERE {",
                "    (?ss ?sc ?lit ?g ?s) text:query ( spec:labels 'foo' 10 ) .",
                "}"
                );
        Set<String> expectedURIs = new HashSet<>() ;
        expectedURIs.addAll( Arrays.asList(SKOS.getURI()+"prefLabel", SKOS.getURI()+"altLabel")) ;
        doTestSearch(turtle, qyString, expectedURIs);
    }

    @Test
    public void testListTextProp03() {
        final String turtle = StrUtils.strjoinNL(
                TURTLE_PROLOG2,
                "",
                "res:oneThing rdfs:label \"bar the barfoo foo is hidden\" ",
                ".",
                "res:twoThing skos:altLabel \"there is no bar to the hidden foo of the flow\" ",
                ".",
                "res:threeThing skos:prefLabel \"if there had been a f o o then it would not bar a hit\" ",
                "."
                );
        String qyString = StrUtils.strjoinNL(
                QUERY_PROLOG2,
                "",
                "SELECT ?s",
                "WHERE {",
                "    (?ss ?sc ?lit ?g ?s) text:query ( spec:labels 'foo' 10 'highlight:' ) .",
                "}"
                );
        Set<String> expectedURIs = new HashSet<>() ;
        expectedURIs.addAll( Arrays.asList(SKOS.getURI()+"altLabel")) ;
        doTestSearch(turtle, qyString, expectedURIs);
    }

    @Test
    public void testListTextProp04() {
        final String turtle = StrUtils.strjoinNL(
                TURTLE_PROLOG2,
                "",
                "res:oneThing rdfs:label \"bar the barfoo foo is hidden\" ",
                ".",
                "res:twoThing skos:altLabel \"there is no bar to the hidden foo of the flow\" ",
                ".",
                "res:threeThing skos:prefLabel \"if there had been a f o o then it would not bar a hit\" ",
                "."
                );
        String qyString = StrUtils.strjoinNL(
                QUERY_PROLOG2,
                "",
                "SELECT ?s",
                "WHERE {",
                "    (?ss ?sc ?lit ?g ?s) text:query ( spec:labels 'bar' 10 'highlight:' ) .",
                "}"
                );
        Set<String> expectedURIs = new HashSet<>() ;
        expectedURIs.addAll( Arrays.asList(SKOS.getURI()+"prefLabel", SKOS.getURI()+"altLabel")) ;
        doTestSearch(turtle, qyString, expectedURIs);
    }

    @Test
    public void testListTextProp05() {
        final String turtle = StrUtils.strjoinNL(
                TURTLE_PROLOG2,
                "",
                "res:oneThing rdfs:label \"bar the barfoo foo is hidden\" ",
                ".",
                "res:twoThing skos:altLabel \"there is no bar to the hidden foo of the flow\" ",
                ".",
                "res:threeThing skos:prefLabel \"if there had been a f o o then it would not bar a hit\" ",
                "."
                );
        String qyString = StrUtils.strjoinNL(
                QUERY_PROLOG2,
                "",
                "SELECT ?s",
                "WHERE {",
                "    (?ss ?sc ?lit ?g ?s) text:query ( skos:prefLabel skos:altLabel rdfs:label 'bar' 10 'highlight:' ) .",
                "}"
                );
        Set<String> expectedURIs = new HashSet<>() ;
        expectedURIs.addAll( Arrays.asList(SKOS.getURI()+"prefLabel", SKOS.getURI()+"altLabel")) ;
        doTestSearch(turtle, qyString, expectedURIs);
    }
}
