<?php

use CorpusParole\Libraries\Mappers\CocoonCollectionRdfMapper;
use CorpusParole\Libraries\CocoonUtils;

use EasyRdf\Graph;
use EasyRdf\Resource;
use EasyRdf\Literal;

use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;

class CocoonCollectionRdfMapperTest extends TestCase
{

    const TEST_INPUT_DOCS = [
        'BASE' => <<<EOT
        @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
        @prefix owl: <http://www.w3.org/2002/07/owl#> .
        @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
        @prefix fn: <http://www.w3.org/2005/xpath-functions#> .
        @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
        @prefix sesame: <http://www.openrdf.org/schema/sesame#> .
        @prefix v: <http://rdf.data-vocabulary.org/#> .
        <http://purl.org/poi/crdo.vjf.cnrs.fr/crdo-COLLECTION_CFPP2000> a <http://crdo.risc.cnrs.fr/schemas/Resource> ;
            <http://purl.org/dc/elements/1.1/description> "Corpus de Français Parlé Parisien des années 2000."@fr , "Le Corpus de FranÃ§ais ParlÃ© Parisien (CFPP2000) est composÃ© d'un ensemble d'interviews non directives sur les quartiers de Paris et de la proche banlieue. Les entretiens, transcrits en orthographe et alignÃ©s au tour de parole, sont disponibles sur le net ; ils sont librement employables en Ã©change de la mention dans la bibliographie des travaux qui en seraient tirÃ©s d'une part de l'adresse du site: http://cfpp2000.univ-paris3.fr/ et d'autre part du document de prÃ©sentation suivant : Branca-Rosoff S., Fleury S., Lefeuvre F., Pires M., 2012, \"Discours sur la ville. PrÃ©sentation du Corpus de FranÃ§ais ParlÃ© Parisien des annÃ©es 2000 (CFPP2000)\". En fÃ©vrier 2013, ce corpus comprenait environ 550 000 mots. Un certain nombre d'outils en ligne, notamment un concordancier et  des outils textomÃ©triques permettent de mener des requÃªtes lexicales et grammaticales. CFPP2000 est particuliÃ¨rement destinÃ© Ã  des analyses sur le franÃ§ais oral. Le projet sous-jacent au corpus est par ailleurs l'Ã©tude des modifications et des variations qui interviennent dans ce qu'on peut considÃ©rer comme un parisien vÃ©hiculaire en tension entre le pÃ´le du standard et le pÃ´le du vernaculaire. Par ailleurs, il comporte des activitÃ©s linguistiques diversifiÃ©es (description de quartier, anecdotes, argumentationâ¦) et on peut par consÃ©quent travailler sur la syntaxe propre Ã  ces diffÃ©rentes utilisations du langage. Il permet enfin d'opposer dialogues (entre enquÃªteur et enquÃªtÃ©s) et multilogues (oÃ¹ la prÃ©sence de plusieurs enquÃªtÃ©s favorise le passage Ã  un registre familier).  CFPP2000 est constituÃ© d'interviews longues (d'une heure en moyenne) intÃ©gralement transcrites. Il est donc utilisable pour examiner les singularitÃ©s qui reviennent Ã  l'idiolecte propre Ã  une personne donnÃ©e, par opposition aux variantes diffusÃ©es dans des groupes plus larges (quartiers, groupes socio-culturels, classe d'Ã¢ge, etc.). Le corpus constitue enfin un ensemble de tÃ©moignages intÃ©ressants sur les reprÃ©sentations de Paris et de sa proche banlieue qui est susceptible d'intÃ©resser des analystes du discours, des sociologues, ou tout simplement des curieux de la ville."@fr ;
            <http://purl.org/dc/elements/1.1/type> <http://purl.org/dc/dcmitype/Collection> ;
            <http://purl.org/dc/elements/1.1/subject> <http://lexvo.org/id/iso639-3/fra> ;
            <http://purl.org/dc/elements/1.1/language> <http://lexvo.org/id/iso639-3/gsw> ;
            <http://purl.org/dc/terms/created> "start=1988; end=1989"^^<http://purl.org/dc/terms/Period> ;
            <http://purl.org/dc/elements/1.1/rights> "Copyright (c) Département de dialectologie alsacienne et mosellane de l'Université de Strasbourg" ;
            <http://www.language-archives.org/OLAC/1.1/depositor> <http://viaf.org/viaf/93752300> ;
            <http://purl.org/dc/elements/1.1/publisher> <http://viaf.org/viaf/142432638> , "Fédération CLESTHIA" , <http://viaf.org/viaf/154862993> ;
            <http://purl.org/dc/elements/1.1/title> "Corpus de Français Parlé Parisien des années 2000 (CFPP)"@fr ;
            <http://www.language-archives.org/OLAC/1.1/interviewer> "Branca-Rosoff, Sonia" , "Lefeuvre, Florence" , "Pires, Mat" ;
            <http://purl.org/dc/terms/accessRights> "Freely available for non-commercial use" ;
            <http://purl.org/dc/terms/license> <http://creativecommons.org/licenses/by-nc-sa/3.0/> ;
            <http://purl.org/dc/terms/spatial> "FR"^^<http://purl.org/dc/terms/ISO3166> , "France, Paris, Université Sorbonne Nouvelle Paris 3, site Censier"@fr , <http://vocab.getty.edu/tgn/7008038> ;
            <http://purl.org/dc/terms/available> "2013-04-12"^^<http://purl.org/dc/terms/W3CDTF> ;
            <http://purl.org/dc/terms/issued> "2013-04-12T22:20:23+02:00"^^<http://purl.org/dc/terms/W3CDTF> ;
            <http://purl.org/dc/terms/modified> "2014-05-10T20:16:27+02:00"^^<http://purl.org/dc/terms/W3CDTF> ;
            <http://www.language-archives.org/OLAC/1.1/transcriber> "Branca-Rosoff, Sonia" , "Lefeuvre, Florence" , "Pires, Mat" ;
            <http://www.w3.org/2003/01/geo/wgs84_pos#long> "2.3333"^^xsd:float ;
            <http://www.w3.org/2003/01/geo/wgs84_pos#lat> "48.8667"^^xsd:float ;
            <http://www.language-archives.org/OLAC/1.1/compiler> "Branca-Rosoff, Sonia" , "Fleury, Serge" , "Lefeuvre, Florence" , "Pires, Mat" ;
            <http://www.language-archives.org/OLAC/1.1/data_inputter> "Branca-Rosoff, Sonia" , "Lefeuvre, Florence" , "Pires, Mat" ;
            <http://www.language-archives.org/OLAC/1.1/researcher> "Branca-Rosoff, Sonia" , "Fleury, Serge" , "Lefeuvre, Florence" , "Pires, Mat" ;
            <http://www.language-archives.org/OLAC/1.1/sponsor> "Ville de Paris " , "Délégation générale à la langue française et aux langues de France " ;
            <http://www.language-archives.org/OLAC/1.1/developer> "Fleury, Serge" ;
            <http://purl.org/dc/terms/isPartOf> <http://purl.org/poi/crdo.vjf.cnrs.fr/crdo-COLLECTION_ALA> .
EOT
    ];

    const TEST_INPUT_ID = "crdo-COLLECTION_CFPP2000";

    private $inputGraphes = [];
    private $resGraphes = [];
    private $mappers = [];

    function __construct(string $name = null) {
        parent::__construct($name);
    }

    public function setUp() {
        parent::setUp();

        $this->testGraphUri = config('corpusparole.corpus_doc_id_base_uri').CocoonCollectionRdfMapperTest::TEST_INPUT_ID;

        foreach(CocoonCollectionRdfMapperTest::TEST_INPUT_DOCS as $key => $inputDoc) {
            $this->inputGraphes[$key] = new Graph("http://purl.org/poi/crdo.vjf.cnrs.fr/crdo-COLLECTION_CFPP2000", $inputDoc);
            $this->mappers[$key] = new CocoonCollectionRdfMapper($this->inputGraphes[$key]);
            $this->mappers[$key]->mapGraph();
            $this->resGraphes[$key] = $this->mappers[$key]->getOutputGraphes()[$this->inputGraphes[$key]->getUri()];
        }
    }

    public function tearDown() {
        parent::tearDown();
    }

    /**
     * Just test that the construct and setup are ok
     *
     * @return void
     */
    public function testInit()
    {
        $this->assertTrue(true);
    }

    /**
     * Test that the returned graph has the same uri that the original.
     *
     * @return void
     */
    public function testUri() {

        //echo $this->resGraphes['BASE']->serialise('turtle');
        //echo var_export($this->resGraphes['BASE']->toRdfPhp());

        $this->assertNotNull($this->resGraphes['BASE']);
        $this->assertEquals($this->testGraphUri, $this->resGraphes['BASE']->getUri(), "URIS must be translated");
     }

    /**
      * Test that the return graph has one edm:Collection resource
      *
      * @return void
      */
    public function testAggregationResource() {

        $resources = $this->resGraphes['BASE']->allOfType('edm:Collection');

        $this->assertCount(1, $resources, "Must found only one resources of type edm:Collection");
        $this->assertEquals($this->testGraphUri,$resources[0]);
    }

    /**
    * Test one to one mapping spatial info
    *
    * @return void
    */
    public function testSpatial() {

        $coll = $this->resGraphes['BASE']->get('edm:Collection', '^rdf:type');
        $sourceNode = $this->inputGraphes['BASE']->get('http://crdo.risc.cnrs.fr/schemas/Resource', '^rdf:type');

        $this->assertNotNull($coll);
        $this->assertNotNull($sourceNode);

        $spatials = $coll->all($this->resGraphes['BASE']->resource('http://purl.org/dc/terms/spatial'));

        $this->assertCount(1, $spatials, "Must have only one spatial node");
        $spatial = $spatials[0];
        $this->assertTrue($spatial->isBNode(),"spatial node must be blank");
        $this->assertEquals("edm:Place", $spatial->type(), "spatial node type must be edm:Place");

        $lats = $spatial->all('geo:lat');
        $this->assertCount(1, $lats, "One latitude");
        $this->assertInstanceOf("EasyRdf\Literal", $lats[0], "Latitude must be a litteral");
        $this->assertEquals(Literal::create("48.8667", null, 'xsd:float'), $lats[0], "lat must be '48.8667'^^xsd:float");

        $longs = $spatial->all('geo:long');
        $this->assertCount(1, $longs, "One longitude");
        $this->assertInstanceOf("EasyRdf\Literal", $longs[0], "Longitude must be a litteral");
        $this->assertEquals(Literal::create("2.3333", null, 'xsd:float'), $longs[0], "long must be '1.90'^^xsd:float");

        $notes = $spatial->all('skos:note');
        $this->assertCount(2, $notes, "2 notes");
        $this->assertContainsOnlyInstancesOf("EasyRdf\Literal", $notes, "Notes mus be only literals");
        $this->assertEquals(Literal::create("FR", null, "dc:ISO3166"), $notes[0], "notes contains 'FR'^^dc:ISO3166");
        $this->assertEquals(Literal::create("France, Paris, Université Sorbonne Nouvelle Paris 3, site Censier", "fr", null), $notes[1], "notes contains 'France, Paris, Université Sorbonne Nouvelle Paris 3, site Censier'@fr");

        $sameas = $spatial->all('owl:sameAs');
        $this->assertCount(1, $sameas, "1 same as");
        $this->assertContainsOnlyInstancesOf("EasyRdf\Resource", $sameas, "Notes mus be only resources");
        $this->assertEquals('http://vocab.getty.edu/tgn/7008038', $sameas[0]->getUri(), "uri must be http://vocab.getty.edu/tgn/7008038");
    }

    /**
     * Test one to one mapping
     *
     * @return void
     */
    public function testOneToOnePropsIdentity() {

        $properties = [
            'http://purl.org/dc/elements/1.1/description',
            'http://purl.org/dc/elements/1.1/language',
            'http://purl.org/dc/elements/1.1/publisher',
            'http://purl.org/dc/elements/1.1/rights',
            'http://purl.org/dc/terms/license',
            'http://purl.org/dc/elements/1.1/subject',
            'http://purl.org/dc/elements/1.1/title',
            'http://purl.org/dc/terms/available',
            'http://purl.org/dc/terms/created',
            'http://purl.org/dc/terms/issued',
            'http://purl.org/dc/elements/1.1/type',
            'http://purl.org/dc/elements/1.1/language',
            'http://purl.org/dc/terms/modified',
        ];

        $coll = $this->resGraphes['BASE']->get('edm:Collection', '^rdf:type');
        $sourceNode = $this->inputGraphes['BASE']->get('http://crdo.risc.cnrs.fr/schemas/Resource', '^rdf:type');

        $this->assertNotNull($coll);
        $this->assertNotNull($sourceNode);

        foreach ($properties as $prop) {
            $outputValuesStr = [];
            foreach($coll->all($this->resGraphes['BASE']->resource($prop)) as $outputValue) {
                array_push($outputValuesStr, strval($outputValue));
            }
            $this->assertNotEmpty($outputValuesStr, "we must found some values to test $prop");
            foreach ($sourceNode->all($this->inputGraphes['BASE']->resource($prop)) as $value) {
                $this->assertContains(strval($value), $outputValuesStr, "$prop not found in output graph");
            }
        }

    }

    public function testLinkToCocoonCollection() {
        $coll = $this->resGraphes['BASE']->get('edm:Collection', '^rdf:type');
        $sourceNode = $this->inputGraphes['BASE']->get('http://crdo.risc.cnrs.fr/schemas/Resource', '^rdf:type');

        $this->assertNotNull($coll);
        $this->assertNotNull($sourceNode);

        $versionOfRes = $coll->all("<http://purl.org/dc/terms/isVersionOf>");
        $this->assertCount(1, $versionOfRes, "Must have only on isVersionOf");
        $versionOfRes = $versionOfRes[0];
        $this->assertInstanceOf("EasyRdf\Resource", $versionOfRes, "version Res must be a resource");
        $this->assertEquals($sourceNode->getUri(), $versionOfRes->getUri(), "versionof res uri must be sams than source");

    }

    /**
     * Test mapping for isPartOf
     *
     * @return void
     */
    public function testOneToOneCollectionIsPartOf() {
        $collection = $this->resGraphes['BASE']->get('edm:Collection', '^rdf:type');
        $sourceNode = $this->inputGraphes['BASE']->get('http://crdo.risc.cnrs.fr/schemas/Resource', '^rdf:type');

        $this->assertNotNull($collection);
        $this->assertNotNull($sourceNode);

        $ispartOf = $collection->all('<http://www.europeana.eu/schemas/edm/isGatheredInto>');
        $this->assertCount(1, $ispartOf, "Must have one collection node");

        $this->assertEquals(config('corpusparole.corpus_doc_id_base_uri')."crdo-COLLECTION_ALA", strval($collection->get('<http://www.europeana.eu/schemas/edm/isGatheredInto>')), "the isPartOf mus equals ".config('corpusparole.corpus_doc_id_base_uri')."crdo-COLLECTION_ALA");
    }


}
