<?php
//$Id$
//gen openMairie le 10/08/2020 10:08

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

class lien_unite extends lien_unite_gen {


    var $unique_key = array(
        array("unite_parent","unite_enfant"),
    );

    /**
     * Clause select pour la requête de sélection des données de l'enregistrement.
     *
     * @return array liste des champs dans leur ordre d'apparition
     */
    function get_var_sql_forminc__champs() {
        // affiche le parent avant l'enfant dans le formulaire
        return array(
            "lien_unite",
            "unite_parent",
            "unite_enfant"
        );
    }

    /**
     * SETTER FORM - setLib
     * 
     * @param formulaire $form Instance formulaire.
     * @param integer $maj Identifant numérique de l'action.
     * 
     * @return void
     */
    function setLib(&$form, $maj) {
        //libelle des champs pour éviter les termes techniques
        parent::setLib($form, $maj);
        $form->setLib('lien_unite', 'id');
        $form->setLib('unite_parent', 'perimetre');
        $form->setLib('unite_enfant', 'unité contenue');
    }

    /**
     * SETTER FORM - setType.
     * 
     * @param formulaire $form Instance formulaire.
     * @param integer $maj Identifant numérique de l'action.
     * 
     * @return void
     */
    function setType(&$form, $maj) {
        parent::setType($form, $maj);
        //Empêche la saisie par défaut de l'unité enfant avec l'unité selectionnée
        //dans le sous formulaire des unités
        if ($maj==0 || $maj==1) {
            $form->setType('unite_enfant', "select");
        }
        // Formulaire d'ajout simplifié
        if ($maj == 5) {
            $form->setType("lien_unite", "hidden");
            $form->setType('unite_enfant', "select_multiple");
        }
    }

    function setValsousformulaire(&$form, $maj, $validation, $idxformulaire, $retourformulaire, $typeformulaire, &$dnu1 = null, $dnu2 = null) {
        parent::setValsousformulaire($form, $maj, $validation, $idxformulaire, $retourformulaire, $typeformulaire, $dnu1, $dnu2);
        if ($validation == 0 and $maj == 5) {
            if ($this->is_in_context_of_foreign_key('unite', $this->retourformulaire))
                $form->setVal('unite_parent', $idxformulaire);
        }
    }

    /**
     * Permet de définir l’attribut “onchange” sur chaque champ.
     *
     * @param object  &$form Formumaire
     * @param integer $maj   Mode d'insertion
     */
    function setOnchange(&$form, $maj) {
        parent::setOnchange($form, $maj);

        // Suppression du 'verifNum' car il empêche la sélection de plusieurs item dans la liste
        if ($maj == 5) {
            $form->setOnchange('unite_enfant', '');
        }

        // En cas de changement du champ unite_parent, appel
        // la méthode javascript filterSelect qui utilise (via l'URL) le
        // snippet_filterselect. Le snippet renvoie ensuite un json contenant la valeur du champ.
        // Cette valeur est ensuite utilisé pour récupèrer la liste des
        // unité répondant à la contrainte de type
        $form->setOnchange(
            'unite_parent',
            "filterSelect(
                this.value,
                'unite_enfant',
                'unite_parent',
                'lien_unite'
            )"
        );
    }

    /**
     *
     * @return string Valeur de la variable récupérée ou chaîne vide
     */
    function get_var_sql_forminc__sql_unite() {
        return "SELECT 
                    unite.unite,
                concat(
                    unite.unite,
                    ' ',
                    unite.libelle,
                    ' [ ',
                    unite.ordre,
                    ' ] '
                ) 
                as 
                    lib
                FROM
                    ".DB_PREFIXE."unite
                ORDER BY
                    unite.libelle ASC";
    }

    /**
     *
     * @return string Valeur de la variable récupérée ou chaîne vide
     */
    function get_var_sql_forminc__sql_unite_by_id() {
        return "SELECT
                    unite.unite,
                concat(
                    unite.unite,
                    ' ',
                    unite.libelle,
                    ' [ ',
                    unite.ordre,
                    ' ] '
                )
                as
                    lib
                FROM
                    ".DB_PREFIXE."unite
                WHERE
                    unite = <idx>";
    }

    /**
     *
     * @return string
     */
    function get_var_sql_forminc__sql_unite_parent() {
        return "SELECT 
                unite.unite,
                unite.libelle
            FROM 
                ".DB_PREFIXE."unite
            WHERE 
                (
                    (
                        unite.om_validite_debut IS NULL 
                        AND (
                            unite.om_validite_fin IS NULL
                            OR unite.om_validite_fin > CURRENT_DATE
                        )
                    )
                    OR (
                        unite.om_validite_debut <= CURRENT_DATE
                        AND (
                            unite.om_validite_fin IS NULL
                            OR unite.om_validite_fin > CURRENT_DATE
                        )
                    )
                )
                AND perimetre = true
                ORDER BY 
                    unite.libelle ASC";
    }

    /**
     * Méthode qui effectue les requêtes de configuration des champs.
     *
     * @param object  $form Instance du formulaire.
     * @param integer $maj  Mode du formulaire.
     * @param null    $dnu1 @deprecated Ancienne ressource de base de données.
     * @param null    $dnu2 @deprecated Ancien marqueur de débogage.
     *
     * @return void
     */
    function setSelect(&$form, $maj, &$dnu1 = null, $dnu2 = null) {
        parent::setSelect($form, $maj);
        //En mode modification ou ajout
        if ($maj == 0 || $maj == 1 || $maj == 5) {
            // Initialise le select en fonction de la valeur du champs unite_parent
            $form->setSelect(
                'unite_enfant',
                $this->loadSelect_unite_enfant($form, $maj, "unite_parent")
            );
        }
    }

    /**
     * Renvoie les valeurs possible des options du select "unite_enfant".
     *
     * Ce select liste toutes les unités qui ont le type recherché
     * par l'unité parente.
     *
     * @param  object  $form  Formulaire.
     * @param  integer $maj   Mode d'insertion.
     * @param  string  $champ Champ activant le filtre.
     *
     * @return array Tableau des valeurs possible du select.
     */
    protected function loadSelect_unite_enfant(&$form, $maj, $champ) {
        // Initialisation du tableau de paramétrage du select :
        // - la clé 0 contient le tableau des valeurs,
        // - la clé 1 contient le tableau des labels,
        // - les clés des tableaux doivent faire correspondre le couple valeur/label.
        $contenu = array(
            0 => array('', ),
            1 => array(__('choisir')." ".__("unite_enfant"), ),
        );

        // Récupération de l'identifiant de l'unité parente :
        // (par ordre de priorité)
        // - si une valeur est postée : c'est le cas lors du rechargement d'un
        //   formulaire et que le select doit être peuplé par rapport aux
        //   données saisies dans le formulaire,
        // - si la valeur est passée en paramètre : c'est le cas lors d'un
        //   appel via le snippet filterselect qui effectue un
        //   $object->setParameter($linkedField, $idx); lors d'un appel ajax
        //   depuis le formulaire,
        // - si la valeur est dans l'enregistrement du lien entre unité sur lequel on se
        //   trouve : c'est le cas lors de la première ouverture du formulaire
        //   en modification par exemple.
        $idUniteParent = "";
        if ($this->f->get_submitted_post_value($champ) !== null) {
            $idUniteParent = $this->f->get_submitted_post_value($champ);
        } elseif ($this->getParameter($champ) != "") {
            $idUniteParent = $this->getParameter($champ);
        } elseif (isset($form->val[$champ])) {
            $idUniteParent = $form->val[$champ];
        }

        // Si on ne récupère pas l'unité parente alors on ne peut pas savoir
        // le type attendu, on renvoi donc un select vide
        if (empty($idUniteParent)) {
            return $contenu;
        }

        // on récupère l'instance de l'unité parent
        $uniteParent = $this->f->get_inst__om_dbform(array(
            "obj" => "unite",
            "idx" => $idUniteParent
        ));
        // on récupère le type d'unité que peut contenir le parent
        $typeVoulu = $uniteParent->getVal('type_unite_contenu');
        // Si il n'y a pas de type d'unité voulu alors renvoie une liste vide
        if (empty($typeVoulu)) {
            return $contenu;
        }

        // on récupère ainsi la liste de toutes les unités ayant ce type
        // c'est cette liste qu'on va afficher dans le select
        $sql = "SELECT 
                unite, libelle, code_unite
            FROM 
                ".DB_PREFIXE."unite
            WHERE 
                unite.type_unite = ".$typeVoulu.
            "ORDER BY
                unite.libelle ASC";

        $res = $this->f->db->query($sql);
        $this->addToLog(
            __METHOD__."(): db->query(\"".$sql."\");",
            VERBOSE_MODE
        );

        // si la requête échoue on renvoie un select vide
        if ($this->f->isDatabaseError($res, true)) {
            return $contenu;
        };

        // si la requête réussi on récupère les résultats et on les stocke dans le
        // tableau de paramétrage du select
        while ($row =& $res->fetchRow(DB_FETCHMODE_ASSOC)) {
            $contenu[0][] = $row['unite'];
            $contenu[1][] = ! empty($row['code_unite']) ?
                $row['code_unite'].' '.$row['libelle'] :
                $row['libelle'];
        }

        // on renvoie le tableau de paramètrage du select contenant la liste des unités
        // respectant la contrainte de type
        return $contenu;
    }

    /**
     * SETTER FORM - set_form_default_values
     * 
     * @param formulaire $form Instance formulaire.
     * @param integer $maj Identifant numérique de l'action.
     * @param integer $validation Marqueur de validation du formulaire.
     * 
     * @return void
     */
    function set_form_default_values(&$form, $maj, $validation) {
        if ($validation == 0 && $maj == 5) {
            $form->setVal('unite_parent', null, $validation);
            $form->setVal('lien_unite', null, $validation);
            $form->setVal('unite_enfant', '', $validation);
        }
    }

    /**
     * Definition des actions disponibles sur la classe
     *
     * @return void
     */
    function init_class_actions() {
        parent::init_class_actions();

        $this->class_actions[5] = array(
            "identifier" => "ajouter_multiple",
            "permission_suffix" => "ajouter_lien_multiple",
            "crud" => "create",
            "method" => "ajouter_multiple"
        );
    }

    /**
     * Récupère les données du formulaire et vérifie si elles sont correct.
     * Si c'est le cas vérifie si une election, des acteurs et des unités ont
     * bien été sélectionnés avant de créer les délégations correspondantes.
     *
     * @param array $val tableau contenant les valeurs issues du formulaire
     * @return boolean
     */
    protected function ajouter_multiple($val = array()) {
        $this->begin_treatment(__METHOD__);
        // Si les verifications precedentes sont correctes, on procede a
        // la modification, sinon on ne fait rien et on affiche un message
        // d'echec
        if ($this->correct) {
            if (! empty($val['unite_parent']) && ! empty($val['unite_enfant'])) {
                $parent = $val['unite_parent'];
                $enfants = explode(";", $val['unite_enfant']);
                if (is_array($enfants)) {
                    if (! $this->creer_liens_multiple($parent, $enfants)) {
                        $this->addToLog(__METHOD__."(): ERROR", DEBUG_MODE);
                        return $this->end_treatment(__METHOD__, false);
                    }
                }
            }
        } else {
            // Message d'echec (saut d'une ligne supplementaire avant le
            // message pour qu'il soit mis en evidence)
            $this->addToMessage("<br/>".__("SAISIE NON ENREGISTREE")."<br/>");
            // Return
            return $this->end_treatment(__METHOD__, false);
        }
        return $this->end_treatment(__METHOD__, true);
    }

    /**
     * Création dans la base de données de tous les liens entre les
     * unités enfants sélectionnées et l'unité parent
     *
     * @param integer $idUniteParent identifiant de l'unité parent
     * @param array $unitesEnfant  Liste des unités enfants
     *
     * @return boolean indique si le traitement à fonctionné
     */
    protected function creer_liens_multiple($idUniteParent, $unitesEnfant) {
        $succes = true;
        foreach ($unitesEnfant as $idUnite) {
            if (! empty($idUnite) &&
                ! empty($idUniteParent) &&
                ! $this->lien_existe($idUniteParent, $idUnite)
            ) {
                $lien = $this->f->get_element_by_id('lien_unite', ']');
                $data = array(
                    "lien_unite" => null,
                    "unite_parent" => $idUniteParent,
                    "unite_enfant" => $idUnite
                );
                if (! $lien->ajouter($data)) {
                    $succes = false;
                    break;
                }
                $succes = true;
                // Message informant l'utilisateur des délégation crées
                $uniteParent = $this->f->get_element_by_id('unite', $idUniteParent);
                $uniteEnfant = $this->f->get_element_by_id('unite', $idUnite);
                $message = sprintf(
                    'lien : %s -> %s',
                    $uniteParent->getVal('libelle'),
                    $uniteEnfant->getVal('libelle')
                );
                $this->addToMessage($message);
            }
        }
        $message = $succes ? 'Les liens ont été ajoutés avec succés' :
            'Erreur : la création des liens à échouée';
        $this->addToMessage($message);
        return $succes;
    }

    /**
     * Requête sql permettant de récupérer la délégation dont l'élection, l'acteur
     * et l'unité correspondent aux paramétres.
     * Si un élement est récupéré, la délégation existe.
     * Renvoie true si la délégation existe et false sinon.
     *
     * @param integer id de l'unité parent
     * @param integer id de l'unité enfant
     *
     * @return boolean
     */
    protected function lien_existe($idUniteParent, $idUniteEnfant) {
        $sql = sprintf(
            'SELECT
                lien_unite
            FROM
                %slien_unite
            WHERE
                unite_parent = %d AND
                unite_enfant = %d',
            DB_PREFIXE,
            $idUniteParent,
            $idUniteEnfant
        );
        $lien = $this->f->db->getOne($sql);
        if ($this->f->isDatabaseError($lien, true)) {
            $this->addToLog(__METHOD__." database error:".$lien->getDebugInfo().";", DEBUG_MODE);
            $this->addToMessage('Erreur lors de la récupération du lien');
        }
        return ! empty($lien);
    }

    /**
     * Vérifie la validité des valeurs en mode CREATE & UPDATE.
     *
     * @param array $val Tableau des valeurs brutes.
     * @param null &$dnu1 @deprecated  Ne pas utiliser.
     * @param null $dnu2 @deprecated  Ne pas utiliser.
     *
     * @return void
     */
    function verifier($val = array(), &$dnu1 = null, $dnu2 = null) {
        parent::verifier($val);
        $result = true;
        if (! $this->validate_unite_parent($val['unite_parent'])) {
            $this->addToMessage("Périmètre non valide");
            return false;
        };
        if (! $this->validate_unite_enfant($val['unite_enfant'])) {
            $this->addToMessage("Unité contenue non valide");
            return false;
        };
        $parents = $this->f->simple_query(
            'unite_parent',
            'lien_unite',
            'unite_enfant',
            $val['unite_enfant']
        );
        // Vérifie et averti l'utilisateur si l'unité enfant à déjà des parents
        if (! empty($parents)) {
            $unite = $this->f->get_element_by_id('unite', $val['unite_enfant']);
            $message = 'Attention : l\'unite '.$unite->getVal('libelle').' a déjà pour parent :';
            foreach ($parents as $parent) {
                $perimetre = $this->f->get_element_by_id('unite', $parent);
                $message .= '<br> - '.$perimetre->getVal('libelle');
            }
            $this->addToMessage($message);
        }

        return $result;
    }

    /**
     * Récupére la valeur issue d'un select et vérifie si elle est valide.
     * Vérifie si le type correspond bien à une chaîne numérique d'un entier
     * non négatif. Vérifie ensuite si la valeur ne dépassse pas le max admis
     * par PHP. S'assure que cette valeur est strictement positive à zéro.
     * Pour finir, une requête est faite pour valider l'existance de cette donnée
     * dans la base.
     *
     * Si une de ces vérification échoue la fonction renvoie false et un message
     * d'explication est affiché. Sinon elle renvoie true.
     *
     * @param string $donneeATester résultat du select que l'on veut tester
     * @param string $nomDuChamp nom du champ pour les message
     *
     * @return boolean
     */
    public function validateur_select_unite($donneeATester, $nomDuChamp) {
        if ($result = $this->f->validateur_entier_positif($donneeATester)) {
            // vérification de l'existence dans la base
            $sql = "SELECT 
                        unite
                    FROM 
                        ".DB_PREFIXE."unite
                    WHERE
                        unite = ".$this->f->db->escapeSimple($donneeATester);
            $uniteBase = $this->f->db->getOne($sql);
            // si la requête échoue on renvoie false
            if ($this->f->isDatabaseError($uniteBase, true)) {
                $class = "error";
                $message = __("Erreur de base de donnees. Contactez votre administrateur.");
                $this->addToMessage($class, $message);
                $result = false;
            }
            if ($result && $uniteBase === null) {
                $this->addToMessage("La valeur de ".$nomDuChamp." n'existe pas dans la base");
                $result = false;
            }
        }
        return $result;
    }

    public function validate_unite_parent($donneeATester) {
        return $this->validateur_select_unite($donneeATester, 'unite_parent');
    }

    public function validate_unite_enfant($donneeATester) {
        return $this->validateur_select_unite($donneeATester, 'unite_enfant');
    }

    /**
     *
     * @return string
     */
    function get_var_sql_forminc__sql_unite_enfant_by_id() {
        return 
            "SELECT
                unite.unite, concat(unite.code_unite, ' ', unite.libelle)
            FROM
                ".DB_PREFIXE."unite
            WHERE
                unite = <idx>";
    }
}
