<?php
namespace CorpusParole\Models;

use CorpusParole\Libraries\CorpusParoleException;
use CorpusParole\Libraries\RdfModel\RdfModelResource;
use CorpusParole\Libraries\Utils;
use JsonSerializable;
use Log;

/**
 */
class GeoResource extends RdfModelResource implements JsonSerializable {

    public function __construct($uri, $graph, $providedCHO) {
        parent::__construct($uri, $graph);
        $this->providedCHO = $providedCHO;
        $this->readOnly = true;
        $this->changePending = false;
        $this->needDelete = false;
    }

    private $providedCHO = null;
    private $readOnly = true;
    private $changePending = false;
    private $needDelete = false;

    private $refLocs = null;
    private $notes = null;
    private $latitude = false;
    private $longitude = false;

    public function getDeltaList() {
        if($this->changePending) {
            throw new CorpusParoleException('GetDeltaList called when changes are pending');
        }
        return parent::getDeltaList();
    }

    public function clearMemoizationCache() {
        $this->refLocs = null;
        $this->notes = null;
        $this->latitude = false;
        $this->longitude = false;
    }

    public function getRefLocs() {
        if(is_null($this->refLocs)) {
            $refLocs = $this->allResources("<http://www.w3.org/2002/07/owl#sameAs>");
            $this->refLocs = array_map(function($refLoc) { return $refLoc->getUri();}, $refLocs);
        }
        return $this->refLocs;
    }

    public function setRefLocs($refLocs) {
        if(!$this->changePending) {
            throw new CorpusParoleException('Can call setRefLocs only when changes are pending');
        }

        $this->delete("<http://www.w3.org/2002/07/owl#sameAs>");

        foreach($refLocs as $refLocUri) {
            $this->addResource("http://www.w3.org/2002/07/owl#sameAs", $refLocUri);
        }

        $this->clearMemoizationCache();

    }

    public function getNotes() {
        if(is_null($this->notes)) {
            $this->notes = $this->all('<http://www.w3.org/2004/02/skos/core#note>');
        }
        return $this->notes;
    }

    public function getLatitude() {
        if($this->latitude === false) {
            try {
                $this->latitude = $this->getLiteral('<http://www.w3.org/2003/01/geo/wgs84_pos#lat>');
            } catch(\Exception $e) {
                $this->latitude = null;
            }
        }
        return $this->latitude;
    }

    public function getLatitudeValue() {
        $lat = $this->getLatitude();
        return is_null($lat)?null:$lat->getValue();
    }

    public function getLongitude() {
        if($this->longitude === false) {
            try {
                $this->longitude = $this->getLiteral('<http://www.w3.org/2003/01/geo/wgs84_pos#long>');
            } catch(\Exception $e) {
                $this->longitude = null;
            }
        }
        return $this->longitude;
    }

    public function getLongitudeValue() {
        $long = $this->getLongitude();
        return is_null($long)?null:$long->getValue();
    }

    public function getGeonamesLocs() {
        return preg_grep(config('corpusparole.geonames_url_regexp'), $this->getRefLocs());
    }

    public function jsonSerialize() {
        $notes = array_map(
            function($note) { return Utils::processLiteralResourceOrString($note); },
            $this->getNotes()
        );
        return [
            'ref-locs' => $this->getRefLocs(),
            'notes' => $notes,
            'latitude' => $this->getLatitudeValue(),
            'longitude' => $this->getLongitudeValue(),
        ];
    }

    public function setReadOnly($ro) {
        if($this->readOnly and !$ro) {
            $this->changePending = true;
        }
        $this->readOnly = $ro;
    }

    public function setNeedDelete($nd) {
        $this->needDelete = $nd;
    }

    public function rollback() {
        $this->changePending = false;
    }

    public function commit() {

        // Do nothing if there is no change pending
        if(!$this->changePending) {
            return;
        }

        $delta = $this->startDelta();

        //delete the previous blank node
        if($this->needDelete) {
            $delta->addDeleteWhere(
                "?s ?p ?o. ".
                "{ ".
                "    ?_ <http://purl.org/dc/terms/spatial> ?s. ".
                "} ".
                "UNION { ".
                "    ?s <http://purl.org/dc/terms/spatial> ?o ".
                "}"
            );
        }

        // add the node
        $geoinfoNodeAdded = $delta->getAddedGraph()->newBNode("http://www.europeana.eu/schemas/edm/Place");
        $delta->getAddedGraph()->add($this->providedCHO, "http://purl.org/dc/terms/spatial", $geoinfoNodeAdded);

        foreach($this->propertyUris() as $prop) {
            if($prop == "http://www.w3.org/1999/02/22-rdf-syntax-ns#type") {
                continue;
            }
            foreach($this->all("<$prop>") as $propVal) {
                $delta->getAddedGraph()->add($geoinfoNodeAdded, $prop, $propVal);
            }
        }

        $this->changePending = false;

    }


}
