<?php
namespace CorpusParole\Libraries\Mappers;

use Config;

use CorpusParole\Libraries\Utils;
use CorpusParole\Libraries\CocoonUtils;

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


RdfNamespace::set('edm', 'http://www.europeana.eu/schemas/edm/');
RdfNamespace::set('ore', 'http://www.openarchives.org/ore/terms/');
RdfNamespace::set('crdo', 'http://crdo.risc.cnrs.fr/schemas/');
RdfNamespace::set('olac', 'http://www.language-archives.org/OLAC/1.1/');
RdfNamespace::set('skos', 'http://www.w3.org/2004/02/skos/core#');


/**
 *
 */
abstract class CocoonAbstractRdfMapper implements RdfMapper {

    public function __construct(Graph $inputGraph, $uri=null) {
        $this->inputGraph = $inputGraph;
        $this->uri = is_null($uri)?$inputGraph->getUri():$uri;
        $this->outputGraphes = [];
    }

    abstract protected function mapResource($res, $outputGraph);
    abstract protected function getResourceBaseId($res=null);

    public function getOutputGraphes() {
        return $this->outputGraphes;
    }

    /**
     * Map a Cocoon Rdf Graph to a CP graph
     * @return the new mapped graph
     */
    public function mapGraph() {

        $outputGraph = $this->buildOutputGraph();

        $resources = $this->inputGraph->allOfType('crdo:Resource');
        foreach ($resources as $res) {
            $this->mapResource($res, $outputGraph);
        }
    }

    /**
     * Build the main outputgraph
     * @return the new empty graph
     */
     protected function buildOutputGraph() {

         //$soundRes = $this->inputGraph->resource($this->uri)->get('http://purl.org/dc/terms/requires');
         $id = CocoonUtils::getIdFromUri($this->getResourceBaseId());

         $outputGraph = new Graph(CocoonUtils::getCorpusUriFromId($id));
         $this->outputGraphes[$this->getResourceBaseId()] = $outputGraph;

         return $outputGraph;
     }


    protected function propertyOlacRoleMap($targetRes, $prop, $value) {
        $targetRes->add($prop, $value);
        $targetRes->add('http://purl.org/dc/elements/1.1/contributor', $value);
    }

    protected function propertyIdentityMap($targetRes, $prop, $value) {
        $targetRes->add($prop, $value);
    }

    protected function propertyTrimMap($providedCHOResource, $prop, $value) {
        $providedCHOResource->add($prop, trim($value));
    }

    protected function propertyCollectionMap($providedCHOResource, $prop, $value) {
        // if this is a collection, we use the edm:isGatheredInto property
        if(CocoonUtils::isResourceCollection($value)) {
            $resId = CocoonUtils::getIdFromUri($value->getUri());
            $resUri = CocoonUtils::getCorpusUriFromId($resId);
            $providedCHOResource->addResource('http://www.europeana.eu/schemas/edm/isGatheredInto', $resUri);
        } elseif (strpos($value->getUri(), config('corpusparole.cocoon_doc_id_base_uri')) === 0 ) {
            $resId = CocoonUtils::getIdFromUri($value->getUri());
            $resUri = CocoonUtils::getCorpusUriFromId($resId);
            $providedCHOResource->add($prop, $resUri);
        } else {
            $providedCHOResource->add($prop, $value);
        }
    }


    protected function addSpatialProperties($destRes, $res, $outputGraph) {
        $spatials = $res->all($this->inputGraph->resource('http://purl.org/dc/terms/spatial'));
        $lats = $res->all($this->inputGraph->resource('http://www.w3.org/2003/01/geo/wgs84_pos#lat'));
        $longs = $res->all($this->inputGraph->resource('http://www.w3.org/2003/01/geo/wgs84_pos#long'));
        $alts = $res->all($this->inputGraph->resource('http://www.w3.org/2003/01/geo/wgs84_pos#alt'));

        if( count($spatials) > 0 || count($lats) > 0 || count($longs) > 0 || count($alts)) {
            $placeNode = $outputGraph->newBNode(['edm:Place']);
            foreach($lats as $latitude) {
                $placeNode->addLiteral('http://www.w3.org/2003/01/geo/wgs84_pos#lat', $latitude);
            }
            foreach($longs as $longitude) {
                $placeNode->addLiteral('http://www.w3.org/2003/01/geo/wgs84_pos#long', $longitude);
            }
            foreach($spatials as $s) {
                if($s instanceof Literal) {
                    $placeNode->addLiteral('skos:note', $s);
                }
                elseif ($s instanceof Resource) {
                    $placeNode->addResource('owl:sameAs', $s);
                }
            }
            $destRes->add($outputGraph->resource('http://purl.org/dc/terms/spatial'), $placeNode);
        }
    }

    protected function applyPropertiesToRes($sourceRes, $targetRes, $properties) {

        foreach( $properties as list($prop, $mappingMethod)) {
            if( is_null($mappingMethod) ) {
                $mappingMethod = 'propertyIdentityMap';
            }

            foreach($sourceRes->all($this->inputGraph->resource($prop)) as $value) {
                call_user_func(array($this, $mappingMethod), $targetRes, $prop, $value);
            }
        }
    }

    /**
     * Add a date properties to a resource (providedCHO, WebResource,...)
     */
    protected function addDateProperties($targetRes, $res, $outputGraph) {
        $this->applyPropertiesToRes($res, $targetRes, [
            ['http://purl.org/dc/terms/available', null],
            ['http://purl.org/dc/terms/created', null],
            ['http://purl.org/dc/terms/issued', null],
            ['http://purl.org/dc/terms/modified', null],
        ]);
    }

    protected function mapCollections($res) {
        $collections = $res->all('dc:isPartOf');
        foreach($collections as $coll) {
            if(CocoonUtils::isResourceCollection($coll)) {
                $collId = CocoonUtils::getIdFromUri($coll->getUri());
                $collUri = CocoonUtils::getCorpusUriFromId($collId);
                $collectionGraph = new Graph($collUri);
                $this->outputGraphes[$collUri] = $collectionGraph;
                $collRes = $collectionGraph->resource($collUri, 'edm:Collection');
                $collRes->addResource("http://purl.org/dc/terms/isVersionOf",$coll->getUri());
            }
        }
    }


}
