<?php

// +-------------------------------------------------+
// © 2002-2004 PMB Services / www.sigb.net pmb@sigb.net et contributeurs (voir www.sigb.net)
// +-------------------------------------------------+
// $Id: storyplay.class.php,v 1.3.4.2 2025/10/30 08:13:36 gneveu Exp $

if (stristr($_SERVER['REQUEST_URI'], ".class.php")) {
    die("no access");
}

global $class_path;
require_once $class_path . '/connecteurs.class.php';
require_once $class_path . '/curl.class.php';

/**
 * Connecteur Storyplay
 * Permet l'acces au streaming Storyplay via authentification CAS
 * Pas d'enrichissement - uniquement connexion CAS
 */
class storyplay extends connector
{
    /**
     * URL de connexion Storyplay par defaut
     */
    public const STORYPLAY_BASE_URL = "https://www.storyplayr.com";

    /**
     * Type de document
     */
    public const STORYPLAY_TYPE_DOC = "a";

    /**
     * Configuration Storyplay
     */
    protected $config = null;

    /**
     * Nombre de notices recues
     *
     * @var int
     */
    public $n_recu;

    /**
     * Nombre total de notices
     *
     * @var int
     */
    public $n_total;

    /**
     * {@inheritDoc}
     */
    public function get_id()
    {
        return "storyplay";
    }

    /**
     * {@inheritDoc}
     */
    public function is_repository()
    {
        return static::REPOSITORY_YES;
    }

    /**
     * {@inheritDoc}
     */
    public function enrichment_is_allow()
    {
        return connector::ENRICHMENT_YES;
    }

    /**
     * Recupere les proprietes de la source
     *
     * @param int $source_id
     * @return array
     */
    protected function fetch_parameters($source_id)
    {
        $params = $this->get_source_params($source_id);
        if (empty($params['PARAMETERS'])) {
            return [];
        }
        return unserialize($params['PARAMETERS']);
    }

    /**
     * Formulaire pour les proprietes de la source
     *
     * @param int $source_id
     * @return string
     */
    public function source_get_property_form($source_id)
    {
        global $charset;

        $parameters = $this->fetch_parameters($source_id);

        $storyplay_url = $parameters['storyplay_url'] ?? self::STORYPLAY_BASE_URL;
        $storyplay_url_server_cas = $parameters['storyplay_url_server_cas'] ?? '';
        $storyplay_bibli_id = $parameters['storyplay_bibli_id'] ?? '';
        $storyplay_api_url = $parameters['storyplay_api_url'] ?? '';

        return '
        <div class="row">
            <div class="colonne3">
                <label for="storyplay_url">'.htmlentities($this->msg['storyplay_url'], ENT_QUOTES, $charset).'</label>
            </div>
            <div class="colonne_suite">
                <input type="text" required class="saisie-30em" name="storyplay_url" id="storyplay_url" placeholder="'.self::STORYPLAY_BASE_URL.'" value="'. htmlentities($storyplay_url, ENT_QUOTES, $charset) .'">
            </div>
        </div>
        <div class="row">
            <div class="colonne3">&nbsp;</div>
            <div class="colonne_suite">
                <small>'.htmlentities($this->msg['storyplay_url_help'], ENT_QUOTES, $charset).'</small>
            </div>
        </div>
        <div class="row">
            <div class="colonne3">
                <label for="storyplay_url_server_cas">'.htmlentities($this->msg['storyplay_url_server_cas'], ENT_QUOTES, $charset).'</label>
            </div>
            <div class="colonne_suite">
                <input type="text" class="saisie-50em" name="storyplay_url_server_cas" id="storyplay_url_server_cas" value="'.htmlentities($storyplay_url_server_cas, ENT_QUOTES, $charset).'">
            </div>
        </div>
        <div class="row">
            <div class="colonne3">
                <label for="storyplay_bibli_id">'.htmlentities($this->msg['storyplay_bibli_id'], ENT_QUOTES, $charset).'</label>
            </div>
            <div class="colonne_suite">
                <input type="text" class="saisie-50em" name="storyplay_bibli_id" id="storyplay_bibli_id" value="'.htmlentities($storyplay_bibli_id, ENT_QUOTES, $charset).'">
            </div>
        </div>
        <div class="row">
            <div class="colonne3">
                <label for="storyplay_api_url">'.htmlentities($this->msg['storyplay_api_url'], ENT_QUOTES, $charset).'</label>
            </div>
            <div class="colonne_suite">
                <input type="text" required class="saisie-50em" name="storyplay_api_url" id="storyplay_api_url" value="'.htmlentities($storyplay_api_url, ENT_QUOTES, $charset).'">
            </div>
        </div>
        <div class="row">
            <div class="colonne3">&nbsp;</div>
            <div class="colonne_suite">
                <small>'.htmlentities($this->msg['storyplay_api_url_help'], ENT_QUOTES, $charset).'</small>
            </div>
        </div>
    ';
    }

    /**
     * Recupere les proprietes de la source
     *
     * @param int $source_id
     * @return void
     */
    public function make_serialized_source_properties($source_id)
    {
        global $storyplay_url, $storyplay_url_server_cas, $storyplay_bibli_id, $storyplay_api_url;

        $params = [
            'storyplay_url' => trim($storyplay_url),
            'storyplay_url_server_cas' => trim($storyplay_url_server_cas),
            'storyplay_bibli_id' => trim($storyplay_bibli_id),
            'storyplay_api_url' => trim($storyplay_api_url),
        ];

        $this->sources[$source_id]['PARAMETERS'] = serialize($params);
    }

    /**
     * Formulaire pour les proprietes globales du connecteur
     *
     * @return string
     */
    public function get_property_form()
    {
        return '';
    }


    /**
     * Recupere la configuration Storyplay
     *
     * @return array
     */
    protected function get_storyplay_config()
    {
        if (isset($this->config)) {
            return $this->config;
        }
        $contents = [];
        $config_file = __DIR__.'/storyplay.json';
        if (is_readable($config_file)) {
            $contents = file_get_contents($config_file);
            $this->config = encoding_normalize::json_decode($contents, true);
        }
        return $this->config;
    }

    /**
     * M.A.J. Entrepot lie a une source
     *
     * @param int $source_id ID de la source
     * @param string $callback_progress Fonction de progression
     * @param boolean $recover
     * @param string $recover_env
     * @return int Nombre de documents mis a jour
     */
    public function maj_entrepot($source_id, $callback_progress = "", $recover = false, $recover_env = "")
    {
        $this->callback_progress = $callback_progress;
        $this->fetch_global_properties();

        $parameters = $this->fetch_parameters($source_id);
        $storyplay_api_url = $parameters['storyplay_api_url'] ?? '';

        if (empty($storyplay_api_url)) {
            $this->error = true;
            $this->error_message = $this->msg["storyplay_error_config"];
            return 0;
        }

        // Recuperation du flux OPDS
        $curl = new Curl();
        $curl->timeout = 60;
        $curl->set_option('CURLOPT_SSL_VERIFYPEER', false);
        @mysql_set_wait_timeout();

        $response = $curl->get($storyplay_api_url);

        if ($response->headers['Status-Code'] != 200) {
            $this->error = true;
            $this->error_message = $this->msg["storyplay_error_curl"];
            return 0;
        }

        // Parse du flux OPDS (Atom XML)
        $xml = simplexml_load_string($response->body);
        if ($xml === false) {
            $this->error = true;
            $this->error_message = $this->msg["storyplay_error_xml"];
            return 0;
        }

        // Enregistrement des namespaces
        $namespaces = $xml->getNamespaces(true);

        $this->source_id = $source_id;
        $this->n_recu = 0;
        $this->n_total = count($xml->entry);

        // Traitement de chaque entree
        foreach ($xml->entry as $entry) {
            $unimarc_record = $this->get_unimarc_record($entry, $namespaces);
            $statut = $this->rec_record($unimarc_record, $source_id);

            $this->n_recu++;
            $this->progress();

            if ($statut === false) {
                break;
            }
        }

        return $this->n_recu;
    }

    /**
     * Progress
     *
     * @return void
     */
    protected function progress()
    {
        $callback_progress = $this->callback_progress;
        if ($this->n_total) {
            $percent = ($this->n_recu / $this->n_total);
        } else {
            $percent = 0;
        }
        call_user_func($callback_progress, $percent, $this->n_recu, $this->n_total ?? 'inconnu');
    }


    /**
     * Nettoyage du texte
     *
     * @param string $value
     * @return string
     */
    protected function clean(string $value)
    {
        global $charset;

        if ($charset != "utf-8") {
            $value = encoding_normalize::clean_cp1252($value, 'utf-8');
            $value = encoding_normalize::utf8_decode($value);
        }
        return $value;
    }

    /**
     * Insertion des champs dans l'entrepot
     *
     * @param int $source_id
     * @param array $unimarc_record
     * @param string $date_import
     * @param int $recid
     * @param string $search_id
     * @return void
     */
    protected function insert_fields($source_id, $unimarc_record, $date_import, $recid, $search_id = '')
    {
        $field_order = 0;
        $id_unimarc = $unimarc_record['001'][0];

        foreach ($unimarc_record as $field => $val) {
            for ($i = 0; $i < count($val); $i++) {
                if (is_array($val[$i])) {
                    foreach ($val[$i] as $sfield => $vals) {
                        for ($j = 0; $j < count($vals); $j++) {
                            $this->insert_content_into_entrepot(
                                $source_id,
                                $id_unimarc,
                                $date_import,
                                $field,
                                $sfield,
                                $field_order,
                                $j,
                                $this->clean($vals[$j] ?? ''),
                                $recid,
                                $search_id
                            );
                        }
                    }
                } else {
                    $this->insert_content_into_entrepot(
                        $source_id,
                        $id_unimarc,
                        $date_import,
                        $field,
                        '',
                        $field_order,
                        0,
                        $this->clean($val[$i] ?? ''),
                        $recid,
                        $search_id
                    );
                }
                $field_order++;
            }
        }
    }

    /**
     * Ajout de la notice dans l'entrepot
     *
     * @param array $unimarc_record
     * @param integer $source_id
     * @param string $search_id
     * @return bool
     */
    protected function rec_record(array $unimarc_record, int $source_id, $search_id = '')
    {
        $id_unimarc = $unimarc_record['001'][0];
        if (empty($id_unimarc)) {
            return false;
        }

        $this->delete_from_entrepot($source_id, $id_unimarc);
        $this->delete_from_external_count($source_id, $id_unimarc);

        // On recupere la date d'import
        $date_import = date("Y-m-d H:i:s", time());

        $recid = $this->insert_into_external_count($source_id, $id_unimarc);

        //Insertion de l'entete
        $n_header = [];
        $n_header["rs"] = "*";
        $n_header["ru"] = "*";
        $n_header["el"] = "1";
        $n_header["bl"] = "m";
        $n_header["hl"] = "0";
        $n_header["dt"] = "a";

        //Recuperation d'un ID
        foreach ($n_header as $hc => $code) {
            $this->insert_header_into_entrepot($source_id, $id_unimarc, $date_import, $hc, $code, $recid, $search_id);
        }

        $this->insert_fields($source_id, $unimarc_record, $date_import, $recid, $search_id);
        $this->rec_isbd_record($source_id, $id_unimarc, $recid);

        return true;
    }

    /**
     * Convert une entree OPDS en record Unimarc
     *
     * @param SimpleXMLElement $entry
     * @param array $namespaces
     * @return array
     */
    protected function get_unimarc_record($entry, $namespaces)
    {
        $unimarc = [];
        // Namespace par defaut (Atom)
        $entry->registerXPathNamespace('atom', 'http://www.w3.org/2005/Atom');

        // Namespace ermes (pour les images)
        if (isset($namespaces['ermes'])) {
            $entry->registerXPathNamespace('ermes', $namespaces['ermes']);
        }

        // 001 - Identifiant unique
        $id = (string)$entry->id;
        $unimarc['001'][0] = $id;

        // 010 - ISBN
        if (isset($entry->isbn) && (string)$entry->isbn != 'null') {
            $unimarc['010'][0]['a'][0] = (string)$entry->isbn;
        }

        // 101 - Langue
        if (isset($entry->language)) {
            $lang_code = (string)$entry->language;
            $unimarc['101'][0]['a'][0] = $this->get_language_code($lang_code);
        }

        // 200 - Titre
        $unimarc['200'][0]['a'][0] = (string)$entry->title;

        // 330 - Resume
        if (isset($entry->content)) {
            $content = (string)$entry->content;
            // Nettoyage du HTML
            $content = strip_tags($content);
            $unimarc['330'][0]['a'][0] = $content;
        }

        // 610 - Mots-cles (categories)
        $categories = $entry->category;
        if ($categories && count($categories) > 0) {
            $keywords = [];
            foreach ($categories as $category) {
                $term = (string)$category['term'];
                if (!empty($term)) {
                    $keywords[] = $term;
                }
            }
            if (!empty($keywords)) {
                $unimarc['610'][0]['a'][0] = implode('; ', $keywords);
            }
        }

        // 700 - Auteur principal
        if (isset($entry->author)) {
            $authors = $entry->author;
            $author_index = 0;
            $first = true;
            foreach ($authors as $author) {
                if (isset($author->name) && $first) {
                    $unimarc['700'][$author_index]['a'][0] = (string)$author;
                    $unimarc['700'][$author_index]['4'][0] = '070'; // Code fonction auteur
                    $first = false;
                } else {
                    $unimarc['701'][$author_index]['a'][0] = (string)$author;
                    $unimarc['701'][$author_index]['4'][0] = '070'; // Code fonction auteur
                    $author_index++;
                }
            }
        }

        // 210 - Editeur
        if (isset($entry->editor)) {
            $unimarc['210'][0]['c'][0] = (string)$entry->editor;
        }

        // 856 - URL d'acces
        $link = $entry->link;
        if ($link) {
            $unimarc['856'][0]['u'][0] = (string)$link['href'];
        }

        // 896 - Vignette (extension ermes)
        $thumbnail_large = $entry->xpath('ermes:thumbnailLarge');
        $thumbnail_small = $entry->xpath('ermes:thumbnailSmall');

        if (!empty($thumbnail_large)) {
            $unimarc['896'][0]['a'][0] = (string)$thumbnail_large[0];
        } elseif (!empty($thumbnail_small)) {
            $unimarc['896'][0]['a'][0] = (string)$thumbnail_small[0];
        }

        return $unimarc;
    }

    /**
     * Convertit un code langue en code MARC
     *
     * @param string $lang_code
     * @return string
     */
    protected function get_language_code(string $lang_code)
    {
        // Extraction du code principal (ex: fr-FR -> fr)
        $code = strtolower(substr($lang_code, 0, 2));

        $lang_map = [
            'fr' => 'fre',
            'en' => 'eng',
            'es' => 'spa',
            'de' => 'ger',
            'it' => 'ita',
            'pt' => 'por',
            'nl' => 'dut',
        ];

        return $lang_map[$code] ?? $code;
    }

    /**
     * Renvoie le type d'enrichissement
     *
     * @param int $source_id
     * @return array
     */
    public function getTypeOfEnrichment($source_id)
    {
        return [
            'source_id' => $source_id,
            'type' => [
                ['code' => $this->get_id(), 'label' => $this->msg['storyplay_title']],
            ],
        ];
    }

    public static function get_resource_link($ref, $params)
    {
        if (empty($params['source_id']) || empty($params['empr_id'])) {
            return "";
        }
        $storyplay = new self();
        $storyplay_params = $storyplay->unserialize_source_params($params['source_id']);
        return $storyplay_params['PARAMETERS']['storyplay_url_server_cas'] . "?service=" . urlencode(str_replace("?", "?mediathequeid=" . $storyplay_params['PARAMETERS']['storyplay_bibli_id'] . "&", $params['link']));
    }

}
