<?php

use CorpusParole\Libraries\Mergers\CocoonSoundRdfMerger;
use CorpusParole\Libraries\Mergers\CocoonTextRdfMerger;
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 CocoonTextRdfMergerTest extends TestCase
{
    const TEST_INPUT_DOCS = [
        'SOUND' => __DIR__.'/files/CocoonTextRdfMergerTest/sound.ttl',
        'SOUND_NO_MOD' => __DIR__.'/files/CocoonTextRdfMergerTest/sound_no_mod.ttl',
        'SOUND_NO_CREATED' => __DIR__.'/files/CocoonTextRdfMergerTest/sound_no_created.ttl',
        'TEXT' => __DIR__.'/files/CocoonTextRdfMergerTest/text.ttl',
        'TEXT_CREATED' => __DIR__.'/files/CocoonTextRdfMergerTest/text_created.ttl'
    ];

    private $inputGraphes = [];
    private $resGraph = [];

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

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

        foreach(CocoonTextRdfMergerTest::TEST_INPUT_DOCS as $key => $inputDoc) {
            $this->inputGraphes[$key] = new Graph("http://purl.org/poi/crdo.vjf.cnrs.fr/crdo-CFPP2000_35_SOUND", file_get_contents($inputDoc));
        }

        $merger = new CocoonTextRdfMerger();
        $this->resGraph['SOUND_TEXT'] = $merger->mergeGraph($this->inputGraphes['SOUND'], $this->inputGraphes['TEXT']);
        $merger = new CocoonSoundRdfMerger();
        $this->resGraph['TEXT_SOUND'] = $merger->mergeGraph($this->inputGraphes['TEXT'], $this->inputGraphes['SOUND']);
        $merger = new CocoonTextRdfMerger();
        $this->resGraph['SOUND_NO_MOD_TEXT'] = $merger->mergeGraph($this->inputGraphes['SOUND_NO_MOD'], $this->inputGraphes['TEXT']);
        $merger = new CocoonSoundRdfMerger();
        $this->resGraph['TEXT_SOUND_NO_MOD'] = $merger->mergeGraph($this->inputGraphes['TEXT'], $this->inputGraphes['SOUND_NO_MOD']);

        $merger = new CocoonSoundRdfMerger();
        $this->resGraph['CREATED_TEXT_NO_CREATED_SOUND_NO_CREATED'] = $merger->mergeGraph($this->inputGraphes['TEXT'], $this->inputGraphes['SOUND_NO_CREATED']);
        $merger = new CocoonSoundRdfMerger();
        $this->resGraph['CREATED_TEXT_SOUND_NO_CREATED'] = $merger->mergeGraph($this->inputGraphes['TEXT_CREATED'], $this->inputGraphes['SOUND_NO_CREATED']);
        $merger = new CocoonSoundRdfMerger();
        $this->resGraph['CREATED_TEXT_NO_CREATED_SOUND'] = $merger->mergeGraph($this->inputGraphes['TEXT'], $this->inputGraphes['SOUND']);
        $merger = new CocoonSoundRdfMerger();
        $this->resGraph['CREATED_TEXT_SOUND'] = $merger->mergeGraph($this->inputGraphes['TEXT_CREATED'], $this->inputGraphes['SOUND']);

        $merger = new CocoonTextRdfMerger();
        $this->resGraph['CREATED_SOUND_NO_CREATED_TEXT_NO_CREATED'] = $merger->mergeGraph($this->inputGraphes['SOUND_NO_CREATED'], $this->inputGraphes['TEXT']);
        $merger = new CocoonTextRdfMerger();
        $this->resGraph['CREATED_SOUND_TEXT_NO_CREATED'] = $merger->mergeGraph($this->inputGraphes['SOUND'], $this->inputGraphes['TEXT']);
        $merger = new CocoonTextRdfMerger();
        $this->resGraph['CREATED_SOUND_NO_CREATED_TEXT'] = $merger->mergeGraph($this->inputGraphes['SOUND_NO_CREATED'], $this->inputGraphes['TEXT_CREATED']);
        $merger = new CocoonTextRdfMerger();
        $this->resGraph['CREATED_SOUND_TEXT'] = $merger->mergeGraph($this->inputGraphes['SOUND'], $this->inputGraphes['TEXT_CREATED']);

    }

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

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

    /**
     * Test merge modified merge TEXT into SOUND
     *
     * @return void
     */
    public function testModifiedSoundText() {

        $resGraph = $this->resGraph["SOUND_TEXT"];

        $providedCHO = $resGraph->get('edm:ProvidedCHO', '^rdf:type');
        $baseNode = $this->inputGraphes['SOUND']->get('edm:ProvidedCHO', '^rdf:type');
        $this->assertNotNull($providedCHO);
        $this->assertNotNull($baseNode);

        $outputValuesStr = [];
        foreach($providedCHO->all($resGraph->resource("http://purl.org/dc/terms/modified")) as $outputValue) {
            array_push($outputValuesStr, strval($outputValue));
        }
        $this->assertNotEmpty($outputValuesStr, "we must found some values to test http://purl.org/dc/terms/modified");
        foreach ($baseNode->all($this->inputGraphes['SOUND']->resource("http://purl.org/dc/terms/modified")) as $value) {
            $this->assertContains(strval($value), $outputValuesStr, "http://purl.org/dc/terms/modified not found in output graph");
        }

    }


    /**
     * Test merge dc11:creator from SOUND
     *
     * @return void
     */
    public function testCreatorSoundText() {

        $resGraph = $this->resGraph["SOUND_TEXT"];

        $providedCHO = $resGraph->get('edm:ProvidedCHO', '^rdf:type');
        $baseNode = $this->inputGraphes['SOUND']->get('edm:ProvidedCHO', '^rdf:type');
        $this->assertNotNull($providedCHO);
        $this->assertNotNull($baseNode);

        $outputValuesStr = [];
        foreach($providedCHO->all($resGraph->resource("http://purl.org/dc/elements/1.1/creator")) as $outputValue) {
            array_push($outputValuesStr, strval($outputValue));
        }
        $this->assertNotEmpty($outputValuesStr, "we must found some values to test http://purl.org/dc/elements/1.1/creator");
        $this->assertCount(2, $outputValuesStr, "we must found 2 values http://purl.org/dc/elements/1.1/creator");
    }

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

        $resGraph = $this->resGraph["TEXT_SOUND"];

        $providedCHO = $resGraph->get('edm:ProvidedCHO', '^rdf:type');
        $baseNode = $this->inputGraphes['SOUND']->get('edm:ProvidedCHO', '^rdf:type');
        $this->assertNotNull($providedCHO);
        $this->assertNotNull($baseNode);

        $outputValuesStr = [];
        foreach($providedCHO->all($resGraph->resource("http://purl.org/dc/terms/modified")) as $outputValue) {
            array_push($outputValuesStr, strval($outputValue));
        }
        $this->assertNotEmpty($outputValuesStr, "we must found some values to test http://purl.org/dc/terms/modified");
        foreach ($baseNode->all($this->inputGraphes['SOUND']->resource("http://purl.org/dc/terms/modified")) as $value) {
            $this->assertContains(strval($value), $outputValuesStr, "http://purl.org/dc/terms/modified not found in output graph");
        }

    }

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

        $resGraph = $this->resGraph["SOUND_NO_MOD_TEXT"];

        $providedCHO = $resGraph->get('edm:ProvidedCHO', '^rdf:type');
        $baseNode = $this->inputGraphes['TEXT']->get('edm:ProvidedCHO', '^rdf:type');
        $this->assertNotNull($providedCHO);
        $this->assertNotNull($baseNode);

        $outputValuesStr = [];
        foreach($providedCHO->all($resGraph->resource("http://purl.org/dc/terms/modified")) as $outputValue) {
            array_push($outputValuesStr, strval($outputValue));
        }
        $this->assertNotEmpty($outputValuesStr, "we must found some values to test http://purl.org/dc/terms/modified");
        // must contain the TEXT modified value (since SOUND has none)
        foreach ($baseNode->all($this->inputGraphes['TEXT']->resource("http://purl.org/dc/terms/modified")) as $value) {
            $this->assertContains(strval($value), $outputValuesStr, "http://purl.org/dc/terms/modified not found in output graph");
        }

    }


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

        $resGraph = $this->resGraph["TEXT_SOUND_NO_MOD"];

        $providedCHO = $resGraph->get('edm:ProvidedCHO', '^rdf:type');
        $baseNode = $this->inputGraphes['TEXT']->get('edm:ProvidedCHO', '^rdf:type');
        $this->assertNotNull($providedCHO);
        $this->assertNotNull($baseNode);

        $outputValuesStr = [];
        foreach($providedCHO->all($resGraph->resource("http://purl.org/dc/terms/modified")) as $outputValue) {
            array_push($outputValuesStr, strval($outputValue));
        }
        $this->assertNotEmpty($outputValuesStr, "we must found some values to test http://purl.org/dc/terms/modified");
        // must contain the TEXT modified value (since SOUND has none)
        foreach ($baseNode->all($this->inputGraphes['TEXT']->resource("http://purl.org/dc/terms/modified")) as $value) {
            $this->assertContains(strval($value), $outputValuesStr, "http://purl.org/dc/terms/modified not found in output graph");
        }

    }


    public function testRightsWebResource() {
        $properties = [
            "http://purl.org/dc/elements/1.1/rights",
            'http://purl.org/dc/terms/license',
            'http://purl.org/dc/terms/accessRights',
        ];

        $resGraph = $this->resGraph["SOUND_TEXT"];
        $webResourceList = $resGraph->all('edm:WebResource', '^rdf:type');

        //just check that they have all these resources.
        //TODO: check that the same rights are kept (difficult)
        foreach ($webResourceList as $webResource) {
            foreach ($properties as $prop) {
                $outputValuesStr = [];
                foreach($webResource->all($resGraph->resource($prop)) as $outputValue) {
                    array_push($outputValuesStr, strval($outputValue));
                }
                $this->assertNotEmpty($outputValuesStr, "we must found some values to test $prop");
            }
        }
    }

    public function testRightDifferent() {
        $resGraph = $this->resGraph["SOUND_TEXT"];

        $aggregationRes = $resGraph->get('ore:Aggregation', '^rdf:type');

        $license = $aggregationRes->get('<http://www.europeana.eu/schemas/edm/rights>');

        $this->assertNotNull($license, "The licence must not be null");
        $this->assertInstanceOf("EasyRdf\Resource", $license, "Licence must be a resource");
        $this->assertEquals('http://creativecommons.org/licenses/by-nc-nd/4.0/', $license->getUri(), "License must be sound licence");
    }

    public function testRightSame() {
        $resGraph = $this->resGraph["SOUND_NO_MOD_TEXT"];

        $aggregationRes = $resGraph->get('ore:Aggregation', '^rdf:type');

        $license = $aggregationRes->get('<http://www.europeana.eu/schemas/edm/rights>');

        $this->assertNotNull($license, "The licence must not be null");
        $this->assertInstanceOf("EasyRdf\Resource", $license, "Licence must be a resource");
        $this->assertEquals('http://creativecommons.org/licenses/by-nc-sa/4.0/', $license->getUri(), "License must be default licence");
    }


    /**
     * Test merge created merge TEXT with no created into SOUND with no created
     * Should have no values
     * @return void
     */
    public function testCreatedSoundNocreatedTextNoCreated() {

        $resGraph = $this->resGraph["CREATED_SOUND_NO_CREATED_TEXT_NO_CREATED"];

        $providedCHO = $resGraph->get('edm:ProvidedCHO', '^rdf:type');
        $this->assertNotNull($providedCHO);

        $outputValuesStr = [];
        foreach($providedCHO->all($resGraph->resource("http://purl.org/dc/terms/created")) as $outputValue) {
            array_push($outputValuesStr, strval($outputValue));
        }
        $this->assertEmpty($outputValuesStr, "we must found no values to test http://purl.org/dc/terms/created");
    }

    /**
     * Test merge created merge TEXT with created into SOUND with no created
     * Should have no values
     * @return void
     */
    public function testCreatedSoundNoCreatedTextCreated() {

        $resGraph = $this->resGraph["CREATED_SOUND_NO_CREATED_TEXT"];

        $providedCHO = $resGraph->get('edm:ProvidedCHO', '^rdf:type');
        $this->assertNotNull($providedCHO);

        $outputValuesStr = [];
        foreach($providedCHO->all($resGraph->resource("http://purl.org/dc/terms/created")) as $outputValue) {
            array_push($outputValuesStr, strval($outputValue));
        }
        $this->assertEmpty($outputValuesStr, "we must found no values to test http://purl.org/dc/terms/created");

    }

    /**
     * Test merge created
     * Merge TEXT with no created into SOUND with created
     * Should have no values
     * @return void
     */
    public function testCreatedSoundCreatedTextNoCreated() {

        $resGraph = $this->resGraph["CREATED_SOUND_TEXT_NO_CREATED"];

        $providedCHO = $resGraph->get('edm:ProvidedCHO', '^rdf:type');
        $baseNode = $this->inputGraphes['SOUND']->get('edm:ProvidedCHO', '^rdf:type');
        $this->assertNotNull($providedCHO);
        $this->assertNotNull($baseNode);

        $outputValuesStr = [];
        foreach($providedCHO->all($resGraph->resource("http://purl.org/dc/terms/created")) as $outputValue) {
            array_push($outputValuesStr, strval($outputValue));
        }
        $this->assertNotEmpty($outputValuesStr, "we must foundvalues to test http://purl.org/dc/terms/created");
        $this->assertCount(1, $outputValuesStr, "We should have one value");
        $baseCreated = $baseNode->get("<http://purl.org/dc/terms/created>");
        $this->assertEquals($outputValuesStr[0], strval($baseCreated), "We must same value than in sound");

    }

    /**
     * Test merge created
     * Merge TEXT with created into SOUND with created
     * Should have no values
     * @return void
     */
    public function testCreatedSoundCreatedTextCreated() {

        $resGraph = $this->resGraph["CREATED_SOUND_TEXT"];

        $providedCHO = $resGraph->get('edm:ProvidedCHO', '^rdf:type');
        $baseNode = $this->inputGraphes['SOUND']->get('edm:ProvidedCHO', '^rdf:type');
        $this->assertNotNull($providedCHO);
        $this->assertNotNull($baseNode);

        $outputValuesStr = [];
        foreach($providedCHO->all($resGraph->resource("http://purl.org/dc/terms/created")) as $outputValue) {
            array_push($outputValuesStr, strval($outputValue));
        }
        $this->assertNotEmpty($outputValuesStr, "we must found values to test http://purl.org/dc/terms/created");
        $this->assertCount(1, $outputValuesStr, "We should have one value");
        $baseCreated = $providedCHO->get("<http://purl.org/dc/terms/created>");
        $this->assertEquals($outputValuesStr[0], strval($baseCreated), "We must same value than in sound");

    }


    /**
     * Test merge created merge SOUND with no created into TEXT with no created
     * Should have no values
     * @return void
     */
    public function testCreatedTextNocreatedSoundNoCreated() {

        $resGraph = $this->resGraph["CREATED_TEXT_NO_CREATED_SOUND_NO_CREATED"];

        $providedCHO = $resGraph->get('edm:ProvidedCHO', '^rdf:type');
        $this->assertNotNull($providedCHO);

        $outputValuesStr = [];
        foreach($providedCHO->all($resGraph->resource("http://purl.org/dc/terms/created")) as $outputValue) {
            array_push($outputValuesStr, strval($outputValue));
        }
        $this->assertEmpty($outputValuesStr, "we must found no values to test http://purl.org/dc/terms/created");
    }

    /**
     * Test merge created merge SOUND with created into TEXT with no created
     * Should have one value from sound
     * @return void
     */
    public function testCreatedTextNoCreatedSoundCreated() {

        $resGraph = $this->resGraph["CREATED_TEXT_NO_CREATED_SOUND"];

        $providedCHO = $resGraph->get('edm:ProvidedCHO', '^rdf:type');
        $soundNode = $this->inputGraphes['SOUND']->get('edm:ProvidedCHO', '^rdf:type');
        $this->assertNotNull($providedCHO);
        $this->assertNotNull($soundNode);

        $outputValuesStr = [];
        foreach($providedCHO->all($resGraph->resource("http://purl.org/dc/terms/created")) as $outputValue) {
            array_push($outputValuesStr, strval($outputValue));
        }
        $this->assertNotEmpty($outputValuesStr, "we must foundvalues to test http://purl.org/dc/terms/created");
        $this->assertCount(1, $outputValuesStr, "We should have one value");
        $soundCreated = $soundNode->get("<http://purl.org/dc/terms/created>");
        $this->assertEquals($outputValuesStr[0], strval($soundCreated), "We must same value than in sound");

    }

    /**
     * Test merge created
     * Merge SOUND with no created into TEXT with created
     * Should have no values
     * @return void
     */
    public function testCreatedTextCreatedSoundNoCreated() {

        $resGraph = $this->resGraph["CREATED_TEXT_SOUND_NO_CREATED"];

        $providedCHO = $resGraph->get('edm:ProvidedCHO', '^rdf:type');
        $this->assertNotNull($providedCHO);

        $outputValuesStr = [];
        foreach($providedCHO->all($resGraph->resource("http://purl.org/dc/terms/created")) as $outputValue) {
            array_push($outputValuesStr, strval($outputValue));
        }
        $this->assertEmpty($outputValuesStr, "we must found no values to test http://purl.org/dc/terms/created");

    }

    /**
     * Test merge created
     * Merge SOUND with created into TEXT with created
     * Should have one value
     * @return void
     */
    public function testCreatedTextCreatedSoundCreated() {

        $resGraph = $this->resGraph["CREATED_TEXT_SOUND"];

        $providedCHO = $resGraph->get('edm:ProvidedCHO', '^rdf:type');
        $soundNode = $this->inputGraphes['SOUND']->get('edm:ProvidedCHO', '^rdf:type');
        $this->assertNotNull($providedCHO);
        $this->assertNotNull($soundNode);

        $outputValuesStr = [];
        foreach($providedCHO->all($resGraph->resource("http://purl.org/dc/terms/created")) as $outputValue) {
            array_push($outputValuesStr, strval($outputValue));
        }
        $this->assertNotEmpty($outputValuesStr, "we must found values to test http://purl.org/dc/terms/created");
        $this->assertCount(1, $outputValuesStr, "We should have one value");
        $soundCreated = $soundNode->get("<http://purl.org/dc/terms/created>");
        $this->assertEquals($outputValuesStr[0], strval($soundCreated), "We must same value than in sound");

    }

}
