<?php
namespace CorpusParole\Models;

use Config;
use CorpusParole\Libraries\Utils;
use CorpusParole\Libraries\CocoonUtils;
use CorpusParole\Libraries\RdfModel\RdfModelResource;
use JsonSerializable;
use Log;
use EasyRdf\Literal;
use EasyRdf\Resource;
use EasyRdf\Graph;


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

    public function __construct($uri, $graph = null) {
        //print($graph->dump('html'));
        parent::__construct($uri, $graph);
    }

    private $id = null;
    private $cocoonId = null;
    private $countryCode = false;

    // memoization
    private $providedCHO = null;
    private $title = false;
    private $langs = null;
    private $langsResolved = null;
    private $issued = false;
    private $modified = false;
    private $created = false;

    public function getProvidedCHO() {
        if(is_null($this->providedCHO)) {
            $this->providedCHO = $this->get("<http://www.europeana.eu/schemas/edm/aggregatedCHO>");
        }
        return $this->providedCHO;
    }

    protected function clearMemoizationCache() {
        $this->providedCHO = null;
        $this->title = false;
        $this->langs = null;
        $this->langsResolved = null;
        $this->issued = false;
        $this->modified = false;
        $this->created = false;
    }

    public function getId() {
        if(is_null($this->id)) {
            $ids = $this->getProvidedCHO()->all('<http://purl.org/dc/elements/1.1/identifier>');
            foreach ($ids as $id) {
                if($id instanceof Literal && strpos($id->getValue(), config('corpusparole.corpus_id_scheme')) === 0) {
                    $this->id = $id->getValue();
                }
            }
            if(is_null($this->id)) {
                $this->id = CocoonUtils::getIdFromCorpusUri($this->uri);
            }
        }
        return $this->id;
    }

    public function getCocoonId() {
        if(is_null($this->cocoonId)) {
            $this->cocoonId = CocoonUtils::getCocoonIdFromCorpusUri($this->uri);
            if(is_null($this->cocoonId)) {
                $ids = $this->getProvidedCHO()->all('<http://purl.org/dc/elements/1.1/identifier>');
                foreach ($ids as $id) {
                    if($id instanceof Literal && strpos($id->getValue(), config('corpusparole.cocoon_doc_id_base')) === 0) {
                        $this->cocoonId = substr($id->getValue(), strlen(config('corpusparole.cocoon_doc_id_base')));
                    }
                }
            }
        }
        return $this->cocoonId;
    }

    public function getLanguages() {
        if(is_null($this->langs)) {
            try {
                $this->langs = $this->getProvidedCHO()->all('<http://purl.org/dc/elements/1.1/language>');
            } catch(\Exception $e) {
                $this->langs = [];
            }
        }
        return $this->langs;
    }

    public function getLanguagesValue() {
        return array_map(function($lang) {
            if($lang instanceof Resource) {
                return $lang->getUri();
            } else if($lang instanceof Literal) {
                return $lang->getValue();
            }
        }, $this->getLanguages());
    }

    public function getLanguagesResolved() {
        return $this->langsResolved;
    }

    public function setLanguagesResolved($languagesResolved) {
        $this->langsResolved = $languagseResolved;
    }


    public function getTitle() {
        if($this->title === false) {
            try {
                $this->title = $this->getProvidedCHO()->getLiteral('<http://purl.org/dc/elements/1.1/title>');
            } catch(\Exception $e) {
                $this->title = null;
            }
        }
        return $this->title;
    }

    public function setTitle($value, $lang="fr") {
        $oldTitle = $this->getTitle();
        if($oldTitle && $oldTitle->getValue() != $value && $oldTitle->getLang() != $lang) {
            $literalTitle = new Literal($value, $lang, null);
            $this->setSimpleProperty($this->getProvidedCHO(), 'http://purl.org/dc/elements/1.1/title', $oldTitle, $literalTitle);
            //clear cache
            $this->title = false;
        }
    }



    public function getTitleValue() {
        $title = $this->getTitle();
        return is_null($title)?null:$title->getValue();
    }

    public function getIssued() {
        if($this->issued === false) {
            try {
                $this->issued = $this->getProvidedCHO()->getLiteral("<http://purl.org/dc/terms/issued>");
            } catch(\Exception $e) {
                $this->issued = null;
            }
        }
        return $this->issued;
    }

    public function getIssuedValue() {
        $issued = $this->getIssued();
        return is_null($issued)?null:$issued->getValue();
    }

    public function getCreated() {
        if($this->created === false) {
            try {
                $this->created = $this->getProvidedCHO()->getLiteral("<http://purl.org/dc/terms/created>");
            } catch(\Exception $e) {
                $this->created = null;
            }
        }
        return $this->created;
    }

    public function getCreatedValue() {
        $created = $this->getCreated();
        return is_null($created)?null:$created->getValue();
    }


    public function getModified() {
        if($this->modified === false) {
            try {
                $this->modified = $this->getProvidedCHO()->getLiteral("<http://purl.org/dc/terms/modified>");
                if(is_null($this->modified)) {
                    $this->modified = $this->getIssued();
                }
            } catch(\Exception $e) {
                $this->modified = null;
            }
        }
        return $this->modified;
    }

    public function setModified($value = null) {
        if(is_null($value)) {
            $value = gmdate(\DateTime::ATOM);
        } elseif ($value instanceof \DateTime) {
            $value = $value->format(\DateTime::ATOM);
        }
        $value = preg_replace('/[\+\-]00(\:?)00$/', 'Z', $value);

        $modified = $this->getModified();
        if($value && (!$modified || $modified->getValue() !== $value) ) {

            $newModified = new Literal($value, null, "http://purl.org/dc/terms/W3CDTF");
            $this->setSimpleProperty($this->getProvidedCHO(), 'http://purl.org/dc/terms/modified', $modified, $newModified);

            $this->modified = false;
        }
    }


    public function getModifiedValue() {
        $modified = $this->getModified();
        return is_null($modified)?null:$modified->getValue();
    }

    public function getCountryCode() {
        return $this->countryCode;
    }

    public function setCountryCode($code) {
        $this->countryCode = $code;
    }


    public function jsonSerialize() {
        if(!$this->graph) {
            return [
                'id' => $this->getId(),
            ];
        } else {
            $res = [
                'id' => $this->getId(),
                'cocoonId' => $this->getCocoonId(),
                'uri' => $this->getUri(),
                'title' => $this->getTitleValue(),
                'languages' => $this->getLanguagesValue(),
                'modified' => $this->getModifiedValue(),
                'issued' => $this->getIssuedValue(),
                'created' => $this->getCreatedValue()
            ];

            if($this->languagesResolved) {
                $res['languages_resolved'] = $this->getLanguagesResolved();
            }
            if($this->getCountryCode() !== false) {
                $res['countryCode'] = $this->getCountryCode();
            }

            return $res;
        }
    }
}
