<?php
namespace CorpusParole\Services;

use CorpusParole\Services\ViafResolverInterface;

use Cache;
use Config;
use EasyRdf\Graph;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Cache\Repository as CacheRepository;

class ViafResolver implements ViafResolverInterface {

    private $client = null;

    public function __construct(Client $httpClient) {
        $this->client = $httpClient;
    }

    /**
     * make the viaf query.
     */
    public function queryName($id) {

        $url = config('corpusparole.viaf_base_url').$id;

        try {
            $response = $this->client->get($url."/", ['headers'=>['Accept' => 'application/rdf+xml'],]);
        }
        catch(ClientException $e) {
            if($e->getResponse()->getStatusCode() === 404) {
                return null;
            } else {
                throw new ViafResolverException(
                    $e->getMessage(),
                    $e->getResponse()->getStatusCode(),
                    $e
                );
            }
        }
        catch(RequestException $e) {
            throw new ViafResolverException(
                $e->getMessage(),
                $e->hasResponse()?$e->getResponse()->getStatusCode():500,
                $e
            );
        }

        $graph = new Graph($url, $response->getBody());
        $names = [];
        foreach ($graph->allLiterals("<$url>", "schema:name") as $nameLit) {
            $lang = $nameLit->getLang();
            if(!$lang && !isset($names[''])) {
                $names[''] = $nameLit->getvalue();
            } elseif (strpos($lang, 'fr') === 0 && !isset($names['fr'])) {
                $names['fr'] = $nameLit->getvalue();
            } elseif (strpos($lang, 'en') === 0 && !isset($names['en'])) {
                $names['en'] = $nameLit->getvalue();
            } else {
                $names[$lang] = $nameLit->getvalue();
            }
        }

        $firstVal = reset($names);
        if($firstVal === false) {
            $firstVal = null;
        }
        return (isset($names['fr'])) ? $names['fr'] : ((isset($names['en'])) ? $names['en'] : $firstVal);

    }

    /**
     * Check viaf id format
     */
    private function checkViafIdFormat($viafid) {
        return ctype_digit($viafid);
    }

    /**
     * Get name from Viaf id
     * @param string $id The id to resolve. Can be an url starting with http://viaf.org/viaf/
     * @return a string with the name
     */
    public function getName($id) {
        $viafid = $id;
        if(strpos($id, config('corpusparole.viaf_base_url')) === 0) {
            $viafid = substr($id, strlen(config('corpusparole.viaf_base_url')));
        }
        $viafid = rtrim($viafid, '/');

        if(!$this->checkViafIdFormat($viafid)) {
            throw new ViafResolverException("ViafId not in correct format", 400);
        }

        $that = $this;

        return Cache::remember("viaf:$viafid", config('corpusparole.viaf_cache_expiration'), function() use ($that, $viafid)  {

            return $that->queryName($viafid);

        });

    }

    /**
     * Get a list of names from an array of viaf ids.
     * @param array $ids The array of ids to resolve.
     *                   Each id can be an url starting with http://viaf.org/viaf/
     */
    public function getNames(array $ids) {

        if(count($ids) > config('corpusparole.viaf_max_ids')) {
            throw new ViafResolverException("Too manys ids provided");
        }

        return array_combine($ids, array_map([$this,'getName'], $ids));
    }


}
