<?php
/**
 * DBFORM - 'document_instruction_importe'.
 *
 * @package openfoncier
 * @version SVN : $Id$
 */

//
require_once "../gen/obj/document_instruction_importe.class.php";

//
class document_instruction_importe extends document_instruction_importe_gen {


    /**
     * Définition des actions disponibles sur la classe.
     *
     * @return void
     */
    function init_class_actions() {

        parent::init_class_actions();

        // ACTION - 000 - ajouter
        // Modifie la condition d'affichage du bouton ajouter
        // TODO FIXME WARNING WORKAROUND_SOUS_FORM_DOCUMENT_INSTRUCTION_IMPORTE voir le commentaire dans la surcharge d'ajaxIt dans script.js
        // Le numéro de cette action est directement référencé dans la surcharge
        $this->class_actions[0]["condition"] = array("is_addable", "can_user_access_dossier_contexte_ajout");

        // ACTION - 001 - modifier
        //
        $this->class_actions[1]["condition"] = array("is_modifiable", "can_user_access_dossier_contexte_modification");
        
        // ACTION - 002 - supprimer
        //
        $this->class_actions[2]["condition"] = array("is_supprimable", "can_user_access_dossier_contexte_modification");

        // ACTION - 003 - consulter
        //
        $this->class_actions[3]["condition"] = "can_user_access_dossier_contexte_modification";

        // ACTION - 004 - view_tab
        // Interface spécifique du tableau des pièces
        $this->class_actions[4] = array(
            "identifier" => "preview_edition",
            "view" => "formulaire",
            "permission_suffix" => "tab",
        );

        //
        $this->class_actions[6] = array(
            "identifier" => "telecharger_editions",
            "view" => "view_telecharger_editions",
            "permission_suffix" => "om_fichier_instruction_telecharger",
        );
    }

    /**
     * @return array
     */
    function get_var_sql_forminc__champs() {
        return array(
            "document_instruction_importe",
            "uid",
            "dossier",
            "nom_fichier",
            "description",
            "document_type",
            "date_creation",
            "date_modification",
            "uid_dossier_final",
            "'' as live_preview",
            "uid_thumbnail",
        );
    }

    // Métadonnées spécifiques pour le .info
    var $metadata = array(
        "uid" => array(
            "filename" => "get_nom_fichier",
            "dossier" => "get_dossier",
        ),
    );

    protected function get_nom_fichier(): string {
        return $this->valF["nom_fichier"];
    }

    protected function get_dossier(): string {
        return $this->valF["dossier"];
    }

    /**
     * CONDITION - is_ajoutable.
     *
     * Condition pour pouvoir ajouter
     *
     * @return boolean
     */
    function is_ajoutable() {
        // Test du bypass
        if ($this->f->isAccredited($this->get_absolute_class_name()."_ajouter_bypass")) {
            return true;
        }
        // Test des autres conditions
        return $this->is_ajoutable_or_modifiable_or_supprimable($this->getParameter("idxformulaire"));
    }

    /**
     * CONDITION - is_modifiable.
     *
     * Condition pour afficher le bouton modifier
     *
     * @return boolean
     */
    function is_modifiable() {
        // Test du bypass
        if ($this->f->isAccredited($this->get_absolute_class_name()."_modifier_bypass")) {
            return true;
        }
        // Test des autres conditions
        return $this->is_ajoutable_or_modifiable_or_supprimable();
    }

    /**
     * CONDITION - is_supprimable.
     *
     * Condition pour afficher le bouton supprimer
     * @return boolean
     */
    function is_supprimable() {
        // Test du bypass
        if ($this->f->isAccredited($this->get_absolute_class_name()."_supprimer_bypass")) {
            return true;
        }
        // Test des autres conditions
        return $this->is_ajoutable_or_modifiable_or_supprimable();
    }


    /**
     * Conditions pour afficher les boutons modifier et supprimer
     *
     * @return boolean
     */
    function is_ajoutable_or_modifiable_or_supprimable() {
        // Tester si le dossier est cloturé ,
        // et si l'instructeur est de la même division
        if ($this->is_instructeur_from_division_dossier() === true &&
            $this->is_dossier_instruction_not_closed() === true){
            return true;
        }

        return false;
    }

    /**
     * Définition des types des champs du formulaire.
     */
    function setType(&$form,$maj) {
        parent::setType($form,$maj);

        //type
        $form->setType('document_instruction_importe','hidden');
        $form->setType('dossier','hidden');
        $form->setType('nom_fichier','hidden');
        $form->setType('live_preview', 'hidden');
        $form->setType('uid_dossier_final','hidden');
        $form->setType('uid_thumbnail', 'hidden');
        $form->setType('date_creation','datestatic');
        $form->setType('date_modification','datestatic');

        if (in_array($maj, array( 0, 1,))) { // 0 ajout, 1 modifier
            $form->setType('nom_fichier','hidden');
            if ($this->getParameter("retourformulaire") == "") {
                $form->setType('uid','upload');
            } else {
                $form->setType('uid','upload2');
            }
            $form->setType('date_creation', 'hidden');
            $form->setType('date_modification', 'hidden');
        } // fin ajout

        if ($maj==2){ //supprimer
            $form->setType('uid','filestatic');
            $form->setType('document_type','static');
        } // fin supprimer

        if ($maj==3){ //consulter
            $form->setType('uid','file');
        } // fin consulter

        if ($maj == 4) {
            foreach ($this->champs as $champ) {
                $form->setType($champ, 'hidden');
            }
            // Détermine si c'est une image ou un pdf qui doit être affiché
            $form->setType('live_preview', 'previsualiser');
        }

    }

    function setLayout(&$form, $maj){
        // si le paramètre 'param_communes' est défini et valide
        if (in_array($maj, array( 0, 1, ))) { // 0 ajout, 1 modifier
                $class = 'text-info ui-state-highlight ui-state-info';
                $message = __("Documents ajoutés manuellement par l’instructeur ou importés depuis une autre source. Ils complètent le dossier en cours et sont notifiables.");
                $this->f->display_panel_information(
                    $class,
                    $message
                );
        }
        $form->setFieldset('document_instruction_importe', 'D', __('Document d\'instruction importé'));
        $form->setBloc('document_instruction_importe', 'D', "", "sousform-document_instruction_importe-action-".$maj);
        $form->setBloc('uid_dossier_final', 'F');
        $form->setFieldset('uid_dossier_final', 'F', '');
    }

    function setLib(&$form, $maj) {
        parent::setLib($form, $maj);

        $form->setLib("uid", __("fichier"));
        $form->setLib('date_creation', __("Date de création"));
        $form->setLib('date_modification', __("Date de dernière modification"));
        $form->setLib("live_preview", "");
        $form->setLib("description_type", __("Description"));
        $form->setLib("document_type", __("Type du document"));
    }

    function setSelect(&$form, $maj, &$dnu1 = null, $dnu2 = null) {
        parent::setSelect($form, $maj);
        // Dans le cas d'un dossier d'instruction, filtrage des pièces selon le type de dossier
        $sql_document_type = $this->get_var_sql_forminc__sql("document_type");
        $this->init_select(
            $form,
            $this->f->db,
            $maj,
            null,
            "document_type",
            $sql_document_type,
            $this->get_var_sql_forminc__sql("document_type_by_id"),
            false
        );

        if ($this->is_in_context_of_foreign_key("dossier", $this->getParameter("retourformulaire")) === true) {
            //Tableau des contraintes
            $params = array(
                "constraint" => array(
                    "extension" => ".gif;.jpg;.jpeg;.png;.pdf;.doc;.docx;.odt;.xls;.xlsx;.ods;.tiff;.bitmap"
                ),
            );
            
            $form->setSelect("uid", $params);
        }

        if ($maj == 4) {
            $file = $this->f->storage->get($this->getVal('uid'));
            $base64 = base64_encode($file['file_content']);
            $form->setSelect('live_preview', array(
                'base64' => $base64,
                'mimetype' => $file['metadata']['mimetype'],
                'label' => $this->getVal('description_type'),
                'href' => sprintf(
                    '../app/index.php?module=form&snippet=file&obj=document_instruction_importe&champ=uid&id=%1$s',
                    $this->getVal($this->clePrimaire)
                )
            ));
        }
    }

    /**
     * Méthode de traitement des données retournées par le formulaire
     */
    function setvalF($val = array()) {
        parent::setvalF($val);

        if ($val["date_creation"] == "") {
            $this->valF["date_creation"] = date("Y-m-d");
        }
        $this->valF["date_modification"] = date("Y-m-d");
    
        if ($val["uid_thumbnail"] == "") {
            $this->valF["uid_thumbnail"] = "";
        }

        // TODO le nom de fichier sera généré dans les triggerajouter et modifier,
        // mais le temps de trouver comment faire pour que le champ soit pas obligatoire,
        // on enregistre au moins ce champ
        $this->valF["nom_fichier"] = "to-be-replaced";
    }

    /** @inheritDoc */
    function triggerajouter($id, &$dnu1 = null, $val = array(), $dnu2 = null) {
        $res = parent::triggerajouter($id, $dnu1, $val, $dnu2);

        $this->traitement_normaliser_nom_fichier();
        
        return $res;
    }

    /** @inheritDoc */
    function triggermodifier($id, &$dnu1 = null, $val = array(), $dnu2 = null) {
        $res = parent::triggermodifier($id, $dnu1, $val, $dnu2);

        $this->traitement_normaliser_nom_fichier();

        // On force la synchronisation des métadonnées pour que le
        // nom du fichier dans les metadatas correspond bien à celui enregistré
        $file_data = $this->f->storage->get($this->valF['uid']);
        if (isset($file_data['metadata'])) {
            $metadata = $file_data['metadata']; /** @var array $metadata - phpdoc pour corriger le mauvais type de retour */
            if ($metadata['filename'] !== $this->valF['nom_fichier']) {
                $metadata['filename'] = $this->valF['nom_fichier'];
                $is_correct = $this->f->storage->update_metadata($this->valF['uid'], $metadata);
                if ($is_correct === OP_FAILURE) {
                    $this->addToLog(
                        sprintf(__("Erreur lors de la mise à jour du document %s."), $this->valF['uid']), 
                        DEBUG_MODE
                    );
                }
            }
        }

        return $res;
    }

    /**
     * @override Pour forcer la redirection vers la page d'affichage des documents d'instruction
     * 
     * @inheritDoc
     */
    function get_back_link($view = "formulaire") {
        // Récupération du mode de l'action
        $crud = $this->get_action_crud();
        
        // @override : on renvoie vers la liste de tous les documents d'instruction 
        // plutôt que vers une liste des documents d'instruction importés
        if (
            $crud === 'read' // Consultation, le retour est toujours vers la liste globale
            || ($crud === 'create' && !($this->getParameter('validation') > 0 && $this->correct)) // Un formulaire de création retourne vers la liste globale, sauf s'il est validé
            || ($crud === 'delete' && $this->getParameter('validation') > 0) // Une suppression validée renvoie vers la liste globale
        ) {
            $href = sprintf(OM_ROUTE_SOUSFORM."&obj=%s&action=%s&idx=%s&retourformulaire=%s&idxformulaire=%s&retour=form",
                "document_numerise",
                310, 
                $this->getParameter('idxformulaire'),
                'dossier_instruction',
                $this->getParameter('idxformulaire'),
            );

            if ($this->getParameter('message_id')) {
                $href .= '&message_id='.$this->getParameter('message_id');
            }

            return $href;
        }

        return parent::get_back_link($view);
    }

    /**
     * Récupère et renvoie au format json les informations nécessaire
     * permettant d'afficher une image.
     */
    public function view_image_data() {
        $this->checkAccessibility();
        $this->f->disableLog();
        $img = $this->f->storage->get($this->getVal('uid_thumbnail'));
        if (is_array($img) &&
            array_key_exists('file_content', $img) &&
            array_key_exists('metadata', $img)
        ) {
            $min = sprintf(
                'data:%s;base64,%s',
                $img['metadata']['mimetype'],
                chunk_split(base64_encode($img['file_content']))
            );
            printf($min);
        }
    }

    protected function traitement_normaliser_nom_fichier() {
        $est_fichier_modifie = str_starts_with($this->valF['uid'], 'tmp|');
        
        if ($est_fichier_modifie) {
            // Récupère l'extension sur le fichier temporaire
            [, $temporary_uid] = explode("|", $this->valF['uid']);
            $original_filename = $this->f->storage->getFilename_temporary($temporary_uid);
        } else {
            $original_filename = $this->getVal('nom_fichier');
        }

        $extension = pathinfo($original_filename, PATHINFO_EXTENSION);
            
        // Normalisation du nom de fichier
        if ($this->f->is_option_enabled(OPTION_NORMALISE_NOM_DOC)) {                
            $nom_fichier_normalise = $this->normalise_nom_document_instruction_importe(
                $this->valF['dossier'],
                $this->valF['date_creation'],
                $this->valF[$this->clePrimaire],
                $this->valF['document_type'],
            );
            
            $this->valF['nom_fichier'] = "{$nom_fichier_normalise}.{$extension}";
        } else {
            // Traitement par défaut si l'option n'est pas activée
            $this->valF['nom_fichier'] = $this->generate_filename(
                $this->valF["date_creation"], 
                $this->valF['document_type'], 
                $extension, 
                $this->valF['dossier'],
            );
        }
    }

    /**
     * TODO regrouper avec la génération de filename avec l'option option_normaliser_nommage_document_numerise 
     * fonction $this->traitement_normalise_nom_document_instruction_importe()
     * 
     * Génère le nom du fichier.
     *
     * @param  string  $p_date                  Date
     * @param  string  $document_type_id        Identifiant du type de document
     * @param  string  $extension               Extension
     * @param  string  $p_dossier               Numéro du dossier
     * @return string                           Nom du fichier
     */
    protected function generate_filename(string $p_date, string $document_type_id, string $extension, string $p_dossier) {
        // Change le format de la date
        $date = date("Ymd");
        if ($p_date !== null && $p_date !== '') {
            $date = date("Ymd", strtotime($p_date));
        }

        // Récupération du code du type
        $document_type = $this->get_inst_common('document_type', $document_type_id);
        $code_dnt = $document_type->getVal('code');

        // Compose le nom du fichier date + code type document numérisé + extension
        $filename = "{$date}{$code_dnt}.{$extension}";

        // Vérification des doublons
        $counter = 1;
        while ($this->filename_exists_for_dossier_instruction_importe($filename, $p_dossier) === true) {
            $filename = "{$date}{$code_dnt}-{$counter}.{$extension}";
            $counter++;
        }

        return $filename;
    }

    /**
     * 
     * TODO mettre jour la PHP doc en même qu'on refactor ça et la méthode generate_filename
     * Normalise le nom donné au document en lui donnant un nom de cette forme :
     *  - IDDI_DATE_TYPEPIECE_IDPIECE_LIBTYPEPIECE
     * Avec
     *  - IDDI : libellé du dossier d'instruction
     *  - DATE : date de création du document au format YYYYMMDD
     *  - TYPEPIECE : soit la nomenclature du CERFA (si existante), soit le code du type de pièce
     *  - IDPIECE : identifiant numérique de la pièce (document)
     *  - LIBTYPEPIECE : libellé du type de pièce ou de la description pour les "autres à préciser"
     *    limité à 50 caractères, avec ses majuscules et dont les espaces ont été remplacé par des '-'.
     *
     * @param string id_di : identifiant du dossier d'instruction
     * @param string date_creation : date de création du document numérisé
     * @param string code_type_document : identifiant du type de document numerisé
     * @param int id_document : identifiant du document numérisé
     * @param string lib_type_document : libellé du type de document numérisé
     * @param string (optional) description du type de document numérisé
     */
    protected function normalise_nom_document_instruction_importe(
        string $id_di,
        string $date_creation,
        string $id_document,
        string $id_document_type,
    ): string {
        // Les différentes parties du nom du document sont traitées pour avoir le format voulu puis
        // stocker dans un tableau. Cela permet de constituer le nom en concatenant les différentes
        // parties via un implode ayant '_' pour glue.
        $parties_nom = array(
            'iddi' => '',
            'date' => '',
            'typepiece' => '',
            'idpiece' => '',
            'libtypepiece' => '',
        );

        // Récupération du IDDI : nom du dossier
        $parties_nom['iddi'] = $id_di;

        // Récupération du DATE : date de création du document au format YYYYMMDD
        // Il y a plusieurs format possible (BDD -> AAAA-MM-DD, Interface -> DD/MM/AAAA).
        // La date est donc transformée en timestamp avant d'être re-modifié au format voulu
        // ce qui fonctionne quelque soit le format d'entrée de la date.
        $parties_nom['date'] = date('Ymd', strtotime($date_creation));

        // Récupération du TYPEPIECE : code cerfa si existant (et non vide) ou code du type de document sinon
        $document_type = $this->get_inst_common('document_type', $id_document_type);

        $parties_nom['typepiece'] = $document_type->getVal('code');

        // Récupération du IDPIECE : identifiant du document
        $parties_nom['idpiece'] = $id_document;

        // Récupération du LIBTYPEPIECE : si la pièce à le type "autre à préciser" et que sa description n'est pas
        // vide prend la description, sinon prend le libellé du type de pièce.
        // Limite le nombre de caractère du nom à 50 caractère puis remplace tous les espaces par des tirets (-).
        $lib_type_piece = $document_type->getVal('libelle');
        $lib_type_piece = $this->normalize_filename(mb_substr($lib_type_piece, 0, 50));

        $parties_nom['libtypepiece'] = $lib_type_piece;

        // Constitution du nom du fichier
        return implode('_', $parties_nom);
    }

    /**
     * Permet de vérifier si le nom du document d'instruction importé
     * est déjà utilisé dans la BDD pour le dossier d'instruction courant.
     * 
     * @param  string $filename Le nom du fichier dont on veut vérifier l'existence.
     * @return bool             true si le fichier existe, sinon false.
     */
    private function filename_exists_for_dossier_instruction_importe($filename, $p_dossier = null): bool {
        // Identifiant du dossier d'instruction
        $idx_dossier = $p_dossier;
        if ($p_dossier === null
            || $p_dossier === '') {
            //
            $idx_dossier = $this->valF['dossier'];
        }
        // Requête
        $qres = $this->f->get_one_result_from_db_query(
            sprintf(
                'SELECT
                    count(document_instruction_importe)
                FROM
                    %1$sdocument_instruction_importe
                WHERE
                    dossier = \'%2$s\'
                    AND nom_fichier = \'%3$s\'',
                DB_PREFIXE,
                $this->f->db->escapeSimple($idx_dossier),
                $this->f->db->escapeSimple($filename)
            ),
            array(
                "origin" => __METHOD__,
            )
        );
        // Si le nom de fichier existe une ou plusieurs fois
        if ($qres["result"] >= 1) {
            return true;
        }
        return false;
    }

     /**
     * Rend une chaine de caractère compatible avec le nommage des fichiers sous Windows
     * - Ôte les accents
     * - Ne laisse que des caractères alphanumériques à la string
     * 
     * @param string $input chaîne de caractère à remplacer, sans extension
     */
    public function normalize_filename(string $input): string {
        // Remplacer les caractères accentués par leur équivalent non accentué
        $input = iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $input);
        
        // Remplacer tous les caractères non alphanumériques par "-"
        $input = preg_replace('/[^a-zA-Z0-9]+/u', '-', $input);
    
        // Supprimer les tirets en début et fin de chaîne
        $input = trim($input, '-');

        return $input;
    }
}// fin classe
