<?php
/**
 * Ce script contient la définition de la classe *openresultat*.
 *
 * @package openresultat
 * @version SVN : $Id$
 */

/**
 *
 */
if (file_exists("../dyn/locales.inc.php") === true) {
    require_once "../dyn/locales.inc.php";
}

/**
 * Définition de la constante représentant le chemin d'accès au framework
 */
define("PATH_OPENMAIRIE", getcwd()."/../core/");

/**
 * TCPDF specific config
 */
define("K_TCPDF_EXTERNAL_CONFIG", true);
define("K_TCPDF_CALLS_IN_HTML", true);

/**
 * Dépendances PHP du framework
 * On modifie la valeur de la directive de configuration include_path en
 * fonction pour y ajouter les chemins vers les librairies dont le framework
 * dépend.
 */
set_include_path(
    get_include_path().PATH_SEPARATOR.implode(
        PATH_SEPARATOR,
        array(
            getcwd()."/../php/pear",
            getcwd()."/../php/db",
            getcwd()."/../php/fpdf",
            getcwd()."/../php/phpmailer",
            getcwd()."/../php/tcpdf",
        )
    )
);

/**
 *
 */
if (file_exists("../dyn/debug.inc.php") === true) {
    require_once "../dyn/debug.inc.php";
}

/**
 *
 */
require_once PATH_OPENMAIRIE."om_application.class.php";

/**
 * Surcharges du framework à réintégrer
 */
require_once "../obj/om_application_override.class.php";

/**
 * Définition de la classe *openresultat* (om_application).
 */
class openresultat extends om_application_override {

    /**
     * Gestion du nom de l'application.
     *
     * @var mixed Configuration niveau application.
     */
    protected $_application_name = "openRésultat";

    /**
     * Titre HTML.
     *
     * @var mixed Configuration niveau application.
     */
    protected $html_head_title = ":: openMairie :: openRésultat";
    
    protected $_session_name = "openresultat";

    /**
     * Gestion du mode de gestion des permissions.
     *
     * @var mixed Configuration niveau framework.
     */
    protected $config__permission_by_hierarchical_profile = false;

    /**
     *
     * @return void
     */
    function setDefaultValues() {
        $this->addHTMLHeadCss(
            array(
                "../lib/om-theme/jquery-ui-theme/jquery-ui.custom.css",
                "../lib/om-theme/om.css",
            ),
            21
        );
        $this->addHTMLHeadJs(
            array(
                "../app/lib/dual-list-box/dual-list-box.min.js",
            ),
            21
        );
    }

    /**
     * Surcharge - getParameter().
     *
     * Force les paramètres suivants aux valeurs suivantes :
     * - is_settings_view_enabled = true
     *
     * @return mixed
     */
    function getParameter($param = null) {
        // openRésultat est fait pour fonctionner avec la view 'settings'
        // pour gérer le menu 'Administration & Paramétrage'. On force donc le
        // paramètre.
        if ($param == "is_settings_view_enabled") {
            return true;
        }
        return parent::getParameter($param);
    }

    /**
     * Renvoie, pour une chaines de caractères 't' ou 'f',
     * le booleen correspondant.
     *
     * @param string $value : 't' ou 'f'
     * @return boolean 't'=> true et 'f' => false
     */
    static function boolean_string_to_boolean($boolean_string) {
        return $boolean_string === 't';
    }

    /**
     * Ajoute la requête sql au log de l'objet puis
     * vérifie si il y a une erreur de base de données.
     * Si c'est la cas affiche un message d'erreur, envoie les
     * informations de l'erreur au log et renvoie true.
     * Sinon renvoie true.
     *
     * @param string $sql requête sql
     * @param $res resultat de la requête
     * @param string $errorMsg message d'erreur à afficher
     *
     * @return boolean
     */
    public function is_database_error($sql, $res, $errorMsg) {
        $this->addToLog(__METHOD__."(): db->query(\"".$sql."\");", VERBOSE_MODE);
        if ($this->isDatabaseError($res, true)) {
            $this->addToLog(__METHOD__." database error:".$res->getDebugInfo().";", DEBUG_MODE);
            $this->addToMessage($errorMsg);
            return true;
        }
        return false;
    }

    /**
     * Effectue une requête sql simple et renvoie les résultats sous la forme d'un tableau
     * Les requêtes ont la forme :
     * SELECT
     *      $select
     * FROM
     *      $from
     * WHERE
     *      $where = $value
     *
     * @param string $select : attribut recherché
     * @param string $from : table dans laquelle l'élément doit être récupéré
     * @param string $where : nom de l'attribut de la condition
     * @param $value : valeur de l'attribut de la condition
     *
     * @return array tableau contenant les résultats de la requête
     */
    public function simple_query($select, $from, $where, $value) {
        $resultats = array();
        $sql = sprintf(
            "SELECT
                %s
            FROM
                ".DB_PREFIXE."%s
            WHERE
                %s = '%s'
            ORDER BY
                %s",
            $this->db->escapeSimple($select),
            $this->db->escapeSimple($from),
            $this->db->escapeSimple($where),
            $this->db->escapeSimple($value),
            $this->db->escapeSimple($select)
        );
        $res = $this->db->query($sql);
        if ($this->is_database_error($sql, $res, 'Erreur de récupération des '.$select)) {
            return $resultats;
        }
        while ($row = $res->fetchRow(DB_FETCHMODE_ASSOC)) {
            $resultats[] = $row[$select];
        }
        return $resultats;
    }

    /**
     * Ajouter un nouvel element dans la table voulu de la base de données
     *
     * @param string $nomTable nom de la table dans laquelle on souhaite ajouter
     * un element
     * @param array $valAttribut tableau contenant la valeur des attributs
     * @return boolean indique si l'ajout à fonctionné
     */
    public function ajouter_element_BD($nomTable, $valAttribut = array()) {
        $success = false;
        if (! empty($nomTable) && ! empty($valAttribut)) {
            $objet = $this->get_inst__om_dbform(array(
                'obj' => $nomTable,
                'idx' => ']'
            ));
            $success = $objet->ajouter($valAttribut);
        }
        return $success;
    }

    /**
     * Modifie l'element voulu dans la table donné.
     * L'élement est identifié par son id et la table par son nom
     *
     * @param string $nomTable nom de la table dans laquelle on souhaite modifier
     * un element
     * @param integer $id identifiant unique de l'élement à modifier
     * @param array $valAttribut tableau contenant la valeur des attributs
     * @return boolean indique si l'ajout à fonctionné
     */
    public function modifier_element_BD_by_id($nomTable, $id, $valAttribut = array()) {
        if (! empty($nomTable) && ! empty($id) && ! empty($valAttribut)) {
            $modification = $this->db->autoExecute(
                DB_PREFIXE.$nomTable,
                $valAttribut,
                DB_AUTOQUERY_UPDATE,
                $nomTable.' = '.$id
            );
            $this->addToLog(__METHOD__ . "() : db->autoExecute(" . $modification . ")", VERBOSE_MODE);
            if ($this->isDatabaseError($modification, true)) {
                $this->addToMessage('Erreur lors de la modification');
                $this->db->rollback();
                return false;
            }
            $this->db->commit();
            return true;
        }
        return false;
    }

    /**
     * Supprime l'objet de la BD.
     * Pour cela la méthode remplit un tableau avec les valeurs de l'objet
     * identique au tableau issu du formulaire de l'objet (valF). Ainsi
     * la méthode supprimer peut être utilisée pour supprimer l'objet.
     *
     * @return boolean indique si la suppression à fonctionné
     */
    public function supprimer_element_BD($objet) {
        $suppression = array();
        // Préparation du tableau des valeurs pour la suppression
        foreach ($objet->champs as $id => $champs) {
            // Si des champs on été rajouté au formulaire mais qu'il n'existe
            // pas dans la BD, ils ne sont pas pris en compte dans le tableau
            // de suppression. Evite des erreurs de BD lors de la suppression
            if (isset($objet->val[$id])) {
                $suppression[$champs] = $objet->val[$id];
            }
        }

        // En cas de problème annule la suppression sinon elle est effectuée
        if (! $objet->supprimer($suppression)) {
            $this->db->rollback();
            return false;
        }

        $this->db->commit();
        return true;
    }

    /**
     * Récupére un élément d'une table donné à l'aide de son id
     *
     * @param string nom de la table dans laquel est l'élement
     * @param integer id identifiant de l'élément
     *
     * @return objet élement voulu
     */
    public function get_element_by_id($nomTable, $id) {
        $element = $this->get_inst__om_dbform(array(
            'obj' => $nomTable,
            'idx' => $id
        ));
        return $element;
    }

    /**
     * Renvoie l'extension de l'image dont les metadatas sont
     * passé en paramétre.
     *
     * @param array metadata
     * @return mixed boolean : false si l'extension n'a pas pu être récupéré,
     * sinon string : l'extension
     */
    public function get_extension($metadata) {
        //Les metadatas permettent de récupérer l'extension de l'image et son contenu.
        //Le type est donné sous la forme : ex: image/png. Pour récupérer l'extension
        //il faut donc couper la chaîne en 2 en utilisant le / comme délimiteur et
        //prendre la deuxième partie
        $extension = explode('/', $metadata['mimetype']);
        //Sans l'extension le nom du fichier ne peut pas être écris correctement et
        //une erreur doit donc être retournée
        if (empty($extension) || ! isset($extension[1])) {
            return false;
        }
        return $extension[1];
    }

    /**
     * Copie le contenu du fichier issu du filestorage à l'endroit voulu.
     * Le contenu du fichier est récupéré en utilisant son uid.
     *
     * @param string uid identifiant du fichier dans le filestorage
     * @param string chemin vers l'emplacement où le fichier doit être copié
     * @param string nom de la copie
     *
     * @return boolean indique si la copie a été faite ou non
     */
    public function copier_fichier_du_filestorage($uid, $emplacement, $nomFichier) {
        $succes = false;
        if (! empty($uid) && ! empty($emplacement)) {
            $infoImage = $this->storage->get($uid);
            //Ecriture du fichier de l'image dans le repertoire web/election_id.
            $extension = $this->get_extension($infoImage['metadata']);
            //Le fichier est écris dans un répertoire plan de l'élection et a comme nom
            //l'identifiant du plan
            //Ex : ../web/res/1/plan/1.jpg
            $path = $emplacement.'/'.$nomFichier.'.'.$extension;
            $succes = $this->write_file($path, $infoImage['file_content']);
        }
        return $succes;
    }

    /**
     * Pour une valeur donnée vérifie si il s'agit d'un entier positif,
     * que sa taille est inférieur au max des valeurs numériques admises
     * par php et qu'elle est supérieure à 0.
     *
     * @param $donneeATester
     *
     * @return boolean
     */
    public function validateur_entier_positif($donneeATester) {
        // vérification du type de la donnée
        // chaîne numérique d'un entier
        if (! is_string($donneeATester) || ! ctype_digit($donneeATester)) {
            return false;
        }

        // vérification de la taille
        // doit être inférieur au max des valeurs numérique admise par php
        if (intval($donneeATester) == PHP_INT_MAX) {
            return false;
        }

        // vérification du format
        // doit être supérieur à 0
        if (intval($donneeATester) == 0) {
            return false;
        }
        return true;
    }

    /**
     * ecriture d'un fichier avec le contenu voulu et à l'endroit spécifié.
     * Si le repertoire du fichier n'existe pas il est crée, cependant la
     * méthode ne fonctionne pas si le(s) répertoire(s) du repertoire n'existe
     * pas.
     * Ex : si on a un repertoire document :
     *   -> write_file(document/monfichier.inc, $content) : ok
     *   -> write_file(document/mondossier/monfichier.inc, $content) : ok
     *   -> write_file(document/mondossier/sousdossier/monfichier.inc, $content) : pas ok
     *
     * @param $path emplacement où le fichier est créé
     * @param $content contenu du fichier
     */
    public function write_file($path, $content) {
        $error = false;
        $parent_folder = dirname($path);
        if (!file_exists($parent_folder)) {
            $ret = mkdir($parent_folder);
            if ($ret == false) {
                $error = true;
            }
        }
        $inf = fopen($path, "w");
        if ($inf == false) {
            $error = true;
        } else {
            $ret = fwrite($inf, $content);
            if ($ret == false) {
                $error = true;
            } else {
                $ret = fclose($inf);
                if ($ret == false) {
                    $error = true;
                }
            }
        }
        if ($error==true) {
            $this->msg= "<b>"._("erreur d'ecriture")." ".$path."</b>";
            $this->layout->display_message('error', $this->msg);
            return false;
        }
        return true;
    }

    /**
     * Supprime de manière récusrsive un dossier et tous les éléments qu'il contiens
     *
     * @param directory $dir dossier à supprimer
     *
     * @return boolean indique si le traitement a reussi
     */
    function rrmdir($dir) {
        $ElementToDelete = scandir($dir);
        $current = array_shift($ElementToDelete);
        // POur chaque element du dossier verifie si il s'agit d'un
        // dossier ou d'un fichier. Si c'est un dossier, la méthode
        // rrmdir() est utilisée pour le supprimer ainsi que son contenu.
        // Si c'est un fichier, il est supprimé.
        while (! empty($current)) {
            if (( $current != '.' ) && ( $current != '..' )) {
                if (is_dir($dir.'/'.$current)) {
                    // Supprime le dossier et son contenu
                    $supprimer = $this->rrmdir($dir.'/'.$current);
                    if (! $supprimer) {
                        return false;
                    }
                } else {
                    // supprime le fichier
                    $supprimer = unlink($dir.'/'.$current);
                    if (! $supprimer) {
                        return false;
                    }
                }
            }
            $current = array_shift($ElementToDelete);
        }
        $supprimer = rmdir($dir);
        return $supprimer;
    }

    /**
     * Copie un fichier dans le filestorage.
     * Si l'uid est déjà attribué le fichier est mis à jour avec
     * les informations donnés.
     * Sinon, un nouvel emplacement est crée dans le filestorage
     *
     * @param string $content contenu du fichier ou url vers le fichier
     * @param array $metadata metadata du fichier
     * @param string $mode mode de récupération du fichier, soit depuis le
     * fichier 'from_content', soit en envoyant directement le contenu du fichier
     */
    public function copier_fichier($metadata, $content) {
        $uid = '';
        if (! empty($metadata) && ! empty($content)) {
            $uid = $this->storage->create(
                $content,
                $metadata
            );
        }
        if ($uid == OP_FAILURE) {
            $this->addToMessage(_("L'élément n'a pas été correctement mis à jour."));
            return false;
        }
        $this->addToMessage(_("L'élément a été correctement mis à jour."));
        return $uid;
    }

    /**
     * Récupére le contexte et l'identifiant de l'objet à partir des paramétres
     * de l'url dans le cas où on se trouve dans un sous-formulaire de l'élection :
     *   -> contexte : retourformulaire
     *   -> identifiant : idxformulaire
     * Si on se trouve dans le contexte d'une élection, l'instance de cette
     * election est récupérée. Ensuite, récupére et renvoie l'étape du workflow
     * de l'élection
     *
     * @return mixed false : hors contexte election
     * string : étape du workflow
     */
    protected function get_workflow_election() {
        $contexte = $this->get_submitted_get_value('retourformulaire');
        $idx = $this->get_submitted_get_value('idxformulaire');

        if (empty($contexte) || $contexte != 'election' || empty($idx)) {
            return false;
        }
        $election = $this->get_element_by_id('election', $idx);
        $workflow = $election->getVal('workflow');
        return $workflow;
    }

    /**
     * Récupére l'objet et son identifiant à partir de l'url. Vérifie si il s'agit d'une élection
     * et si son identifiant est défini.
     *
     * Récupère l'instance de l'élection et les valeurs des options :
     *  - delegation_saisie
     *  - delegation_participation
     * Récupère également l'étape du workflow de l'élection.
     * Renvoie les résultats sous la forme d'un tableau
     *
     * @return mixed false : si ce n'est pas une élection ou que son id n'est pas
     * défini
     * array : valeurs des options de délégation de saisie
     */
    protected function get_options_delegation_election() {
        $obj = $this->get_submitted_get_value('obj');
        $idx = $this->get_submitted_get_value('idx');

        if (empty($obj) || $obj != 'election' || empty($idx)) {
            return false;
        }
        $election = $this->get_element_by_id('election', $idx);
        $delegationSaisie = $election->getVal('delegation_saisie');
        $delegationPart = $election->getVal('delegation_participation');

        $options = array(
            'delegation_saisie' => $this->boolean_string_to_boolean($delegationSaisie),
            'delegation_participation' => $this->boolean_string_to_boolean($delegationPart),
            'workflow' => $election->getVal('workflow')
        );
        return $options;
    }


    /**
     * Indique si l'utilisateur est autorisé à saisir des résultats pour une élection et
     * une unité donnée.
     *
     * L'utilisateur est autorisé si :
     *  - l'option de délégation de saisie n'est pas active sur l'élection
     *  - l'utilisateur a une autorisation pour la saisie de cette unité
     *
     * @param integer $election : identifiant de l'élection
     * @param integer $unité : identifiant de l'unité
     *
     * @return booleen true : autorisé, false : pas autorisé
     */
    public function est_autorise($idElection, $unite) {
        // Récupération de l'instance de l'élection pour savoir si la délégation de saisie est
        // activée.
        $autorise = false;
        if (! empty($idElection) && ! empty($unite)) {
            $autorise = true;
            $election = $this->get_element_by_id('election', $idElection);
            $delegationActive = $this->boolean_string_to_boolean($election->getVal('delegation_saisie'));
            if ($delegationActive) {
                // La délégation de saisie étant active seul les utilisateurs ayant une autorisation
                // sont autorisé.
                $autorise = false;
                $userLogin = $this->user_infos['login'];
                if (! empty($userLogin)) {
                    // Requete permettant de récupérer la délégation en fonction du login de l'acteur
                    // de l'unité de saisie et de l'élection
                    // Si aucun résultat n'est trouvé par la requête l'utilisateur n'a pas
                    // l'autorisation de saisir les résultats
                    $sql = sprintf(
                        'SELECT
                            delegation
                        FROM
                            %sdelegation LEFT JOIN %sacteur ON delegation.acteur = acteur.acteur
                        WHERE
                            acteur.login LIKE \'%s\'
                            AND unite = %d
                            AND election = %d',
                        DB_PREFIXE,
                        DB_PREFIXE,
                        $this->db->escapeSimple($userLogin),
                        $unite,
                        $idElection
                    );
                    $res = $this->db->getOne($sql);
                    $this->addToLog(__METHOD__."(): db->getOne(\"".$sql."\");", VERBOSE_MODE);
                    if (! $this->isDatabaseError($res, true)) {
                        $autorise = ! empty($res) ? true : false;
                    }
                }
            }
        }
        return $autorise;
    }

    /**
     * Méthode permettant de vérifier si une saisie ne risque pas d'entrer
     * en conflit avec une autre.
     * Cette méthode récupère l'heure d'ouverture du formulaire, son heure de
     * cloture et l'heure du dernier enregistrement dans la BD.
     * Si le dernier enregistrement a été réalisé entre l'ouverture et la fermeture
     * du formulaire alors il y a un conflit de saisie.
     *
     * /!\ Pour fonctionner cette méthode doit être appelé juste après la validation
     * du formulaire
     *
     * @return boolean true : conflit, false : pas de conflit
     */
    public function conflit_saisie($objet, $ouvertureForm) {
        // Récupération de la date de modif à l'aide d'une requête sql pour s'assurer qu'elle est
        // à jour
        $derniereModif = $this->recupere_date_derniere_modif(
            $objet->table,
            $objet->getVal($objet->clePrimaire)
        );

        // l'heure de validation est récupérée au dernier moment pour limiter les erreurs
        $validationForm = microtime(true);

        return $ouvertureForm < $derniereModif && $derniereModif < $validationForm;
    }

    /**
     * Effectue une requête sql pour récupèrer la date de modification d'un
     * element d'une table donné à l'aide de son identifiant
     *
     * @param string nom de la table
     * @param integer identifiant de l'élément dont on cherche la date de modification
     *
     * @return mixed false en cas d'erreur de BD | date de modification au format :
     */
    protected function recupere_date_derniere_modif($nomTable, $idObjet) {
        $sql = sprintf(
            'SELECT
                date_derniere_modif
            FROM
                %s%s
            WHERE
                %s = %d',
            DB_PREFIXE,
            $this->db->escapeSimple($nomTable),
            $this->db->escapeSimple($nomTable),
            $idObjet
        );
        $date = $this->db->getOne($sql);
        if ($this->is_database_error(
            $sql,
            $date,
            'Erreur lors de la récupération de la date de modification'
        )) {
            return false;
        }
        return $date;
    }

    /**
     * Requête sql servant à la récupération d'une unité à l'aide de son
     * id.
     * Le libellé de l'unité sera affiché sous la forme : code unité - unité
     *
     * @return string Valeur de la variable récupérée ou chaîne vide
     */
    function get_sql_unite_by_id() {
        return "SELECT
                    unite.unite,
                    CONCAT_WS(' - ', unite.code_unite, unite.libelle) as libelle
                FROM
                    ".DB_PREFIXE."unite
                WHERE
                    unite = <idx>";
    }

    /**
     * Requête sql servant à la récupération d'une liste unité filtré selon
     * les paramètres fournis.
     * Le libellé de l'unité sera affiché sous la forme : code unité - unité.
     * Les unités sont triées par code puis par libellé.
     *
     * Cette méthode permet d'avoir une méthode unique pour tous les affichages
     * des champs select servant à sélectionné une unité.
     *
     * @return string Valeur de la variable récupérée ou chaîne vide
     */
    function get_sql_unite_with_parameters($typeUnite = null, $perimetre = null, $isValid = true) {
        // Les paramètres de la clause 'where' sont stockés dans un tableau pour pouvoir
        // utiliser un implode et ne pas avoir à gérer l'affichage du 'where' et des 'AND'
        // lors de la préparation de la clause where
        $where = [];
        // Sql servant à ne récupérer que les unités valide
        if ($isValid === true) {
            $where[] =
                '-- Récupère uniquement les unités valides
                ((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
                )))';
        }
        // Sql servant à filtrer les unités selon si ce sont des périmètres ou pas
        if (! empty($perimetre)) {
            $where[] = 'unite.perimetre IS '.$perimetre;
        }
        // Sql servant à filtrer les unités selon leur type
        if (! empty($typeUnite)) {
            $where[] = 'unite.type_unite = '.$typeUnite;
        }

        // Prépare la requête et la renvoie
        return sprintf(
            'SELECT
                unite.unite,
                CONCAT_WS(\' - \', unite.code_unite, unite.libelle) as libelle
            FROM
                %1$sunite
            %2$s
            ORDER BY
                code_unite::integer ASC,
                libelle ASC',
            DB_PREFIXE,
            ! empty($where) ? 'WHERE '.implode("\nAND ", $where) : ''
        );
    }

    protected function set_config__menu() {
        parent::set_config__menu();
        $parent_menu = $this->config__menu;
        // {{{ Rubrique APPLICATION
        //
        $rubrik = array(
            "title" => _("application"),
            "class" => "application",
            "right" => "menu_application",
        );
        //
        $links = array();
        //
        // --->
        //
        $links[] = array(
            "href" => OM_ROUTE_DASHBOARD,
            "class" => "dashboard",
            "title" => __("Tableau de bord"),
            "open" => array(
                "index.php|[module=dashboard]",
                "index.php|[module=map][mode=tab_sig][obj=carte_globale]",
            ),
        );
        $links[] = array(
            "title" => "<hr/>",
        );

        $links[] = array(
            "href" => OM_ROUTE_TAB."&obj=election",
            "class" => "election",
            "title" => _("élection"),
            "right" => array("election", "election_tab", ),
            "open" => array(
                "index.php|election[module=tab]",
                "index.php|election[module=form]",
            ),
        );

        $links[] = array(
            "href" => OM_ROUTE_TAB."&obj=election_resultat",
            "class" => "election_resultat",
            "title" => _("détail des résultats"),
            "right" => array("election_resultat", "election_resultat_tab", ),
            "open" => array(
                "index.php|election_resultat[module=tab]",
                "index.php|election_resultat[module=form]",
            ),
        );

        $links[] = array(
            "href" => OM_ROUTE_TAB."&obj=participation_unite",
            "class" => "participation_unite",
            "title" => _("détail des participations"),
            "right" => array("participation_unite", "participation_unite_tab", ),
            "open" => array(
                "index.php|participation_unite[module=tab]",
                "index.php|participation_unite[module=form]",
            ),
        );
        
        $rubrik['links'] = $links;
        //
        $menu[] = $rubrik;
        // }}}

        // {{{ Rubrique PARAMETRAGE
        //
        $rubrik = array(
            "title" => _("parametrage metier"),
            "class" => "parametrage",
            "right" => "menu_parametrage",
            "parameters" => array("is_settings_view_enabled" => false, ),
        );
        //
        $links = array();

        $links[] = array(
            "class" => "category",
            "title" => __("élection"),
            "right" => array(
                "unite", "unite_tab", "type_unite", "type_unite_tab",
                "candidat", "candidat_tab", "parti_politique", "parti_politique_tab",
                "type_election", "type_election_tab", "tranche", "tranche_tab",
                "acteur", "acteur_tab",
            ),
        );

        //
        $links[] = array(
            "href" => OM_ROUTE_TAB."&obj=unite",
            "class" => "unite",
            "title" => _("unité"),
            "description" => __("Paramétrage des unités de saisie et des périmètres. Une élection se déroule sur un périmètre (département, canton, commune, ...) qui se compose d'unités de saisie (bureau de vote, commune, ...)."),
            "right" => array("unite", "unite_tab", ),
            "open" => array(
                "index.php|unite[module=tab]",
                "index.php|unite[module=form]",
            ),
        );

        $links[] = array(
            "href" => OM_ROUTE_TAB."&obj=type_unite",
            "class" => "type_unite",
            "title" => _("type d'unité"),
            "description" => __("Paramétrage des types d'unités permettant de catégoriser et de hierarchiser les unités de saisie."),
            "right" => array("type_unite", "type_unite_tab", ),
            "open" => array(
                "index.php|type_unite[module=tab]",
                "index.php|type_unite[module=form]",
            ),
        );

        $links[] = array(
            "href" => OM_ROUTE_TAB."&obj=candidat",
            "class" => "candidat",
            "title" => _("candidat"),
            "description" => _("Paramétrage des candidats disponibles lors de la configuration d'une élection."),
            "right" => array("candidat", "candidat_tab", ),
            "open" => array(
                "index.php|candidat[module=tab]",
                "index.php|candidat[module=form]",
            ),
        );

        $links[] = array(
            "href" => OM_ROUTE_TAB."&obj=parti_politique",
            "class" => "parti_politique",
            "title" => _("parti politique"),
            "description" => _("Paramétrage des partis politiques disponibles lors de la configuration d'une élection."),
            "right" => array("parti_politique", "parti_politique_tab", ),
            "open" => array(
                "index.php|parti_politique[module=tab]",
                "index.php|parti_politique[module=form]",
            ),
        );

        $links[] = array(
            "href" => OM_ROUTE_TAB."&obj=type_election",
            "class" => "type_election",
            "title" => _("type d'élection"),
            "description" => _("Paramétrage des types d'élection (Présidentielle, Municipales, ...) disponibles lors de la création d'une élection."),
            "right" => array("type_election", "type_election_tab", ),
            "open" => array(
                "index.php|type_election[module=tab]",
                "index.php|type_election[module=form]",
            ),
        );

        $links[] = array(
            "href" => OM_ROUTE_TAB."&obj=tranche",
            "class" => "tranche",
            "title" => _("tranche"),
            "description" => _("Paramétrage des tranches horaires de participation disponibles lors de la création d'une élection."),
            "right" => array("tranche", "tranche_tab", ),
            "open" => array(
                "index.php|tranche[module=tab]",
                "index.php|tranche[module=form]",
            ),
        );

        $links[] = array(
            "href" => OM_ROUTE_TAB."&obj=acteur",
            "class" => "acteur",
            "title" => _("acteur"),
            "description" => __("Paramétrage des acteurs disponibles pour la configurationde des délégations. Un acteur sert pour la pérennité de la configuration (pas d'utilisation d'om_utilisateur)."),
            "right" => array("acteur", "acteur_tab", ),
            "open" => array(
                "index.php|acteur[module=tab]",
                "index.php|acteur[module=form]",
            ),
        );

        // Categorie dédiée aux affichages (web et animations)
        $links[] = array(
            "class" => "category",
            "title" => __("Affichage"),
            "right" => array(
                "animation", "animation_tab", "web", "web_tab",
                "plan", "plan_tab",
            ),
        );

        $links[] = array(
            "href" => OM_ROUTE_TAB."&obj=web",
            "class" => "web",
            "title" => _("web"),
            "description" => __("Paramétrage du portail web."),
            "right" => array("web", "web_tab", ),
            "open" => array(
                "index.php|web[module=tab]",
                "index.php|web[module=form]",
            ),
        );

        $links[] = array(
            "href" => OM_ROUTE_TAB."&obj=plan",
            "class" => "plan",
            "title" => _("plan"),
            "description" => __("Paramétrage des plans permettant d'illustrer l'arrivée des resultats dans le portail Web."),
            "right" => array("plan", "plan_tab", ),
            "open" => array(
                "index.php|plan[module=tab]",
                "index.php|plan[module=form]",
            ),
        );

        $links[] = array(
            "href" => OM_ROUTE_TAB."&obj=animation",
            "class" => "animation",
            "title" => _("animation"),
            "description" => __("Paramétrage des modèles d'animations pouvant être utilisés comme bases lors de la configuration de l'élection."),
            "right" => array("animation", "animation_tab", ),
            "open" => array(
                "index.php|animation[module=tab]",
                "index.php|animation[module=form]",
            ),
        );

        //
        $links[] = array(
            "class" => "category",
            "title" => __("découpage administratif"),
            "right" => array(
                "canton", "canton_tab",
                "circonscription", "circonscription_tab", "commune", "commune_tab",
                "departement", "departement_tab",
            ),
        );

        $links[] = array(
            "href" => OM_ROUTE_TAB."&obj=canton",
            "class" => "canton",
            "title" => _("canton"),
            "description" => __("Paramétrage des cantons (circonscription d'élection des conseillers départementaux, membres du conseil départemental). Rattach à l'unité de type bureau de vote, le paramétrage permet principalement de rensiegner le code préfecture pour l'export sinsi que le libellé pour les éditions."),
            "right" => array("canton", "canton_tab", ),
            "open" => array(
                "index.php|canton[module=tab]",
                "index.php|canton[module=form]",
            ),
        );

        $links[] = array(
            "href" => OM_ROUTE_TAB."&obj=circonscription",
            "class" => "circonscription",
            "title" => _("circonscription"),
            "description" => __("Paramétrage des circonscriptions (circonscription législatives d'élection des députés de la chambre basse du Parlement français, l'Assemblée nationale). Rattachée à l'unité de type bureau de vote, le paramétrage permet principalement de rensiegner le code préfecture pour l'export sinsi que le libellé pour les éditions."),
            "right" => array("circonscription", "circonscription_tab", ),
            "open" => array(
                "index.php|circonscription[module=tab]",
                "index.php|circonscription[module=form]",
            ),
        );

        $links[] = array(
            "href" => OM_ROUTE_TAB."&obj=commune",
            "class" => "commune",
            "title" => _("commune"),
            "description" => __("Paramétrage des communes. Rattachée à l'unité de type bureau de vote, le paramétrage permet principalement de rensiegner le code préfecture pour l'export sinsi que le libellé pour les éditions."),
            "right" => array("commune", "commune_tab", ),
            "open" => array(
                "index.php|commune[module=tab]",
                "index.php|commune[module=form]",
            ),
        );

        $links[] = array(
            "href" => OM_ROUTE_TAB."&obj=departement",
            "class" => "departement",
            "title" => _("département"),
            "description" => __("Paramétrage des départements. Rattaché à l'unité de type bureau de vote, le paramétrage permet principalement de rensiegner le code préfecture pour l'export sinsi que le libellé pour les éditions."),
            "right" => array("departement", "departement_tab", ),
            "open" => array(
                "index.php|departement[module=tab]",
                "index.php|departement[module=form]",
            ),
        );

        $rubrik['links'] = $links;
        //
        $menu[] = $rubrik;
        // }}}

        $this->config__menu = array_merge(
            $menu,
            $parent_menu
        );
    }

    /**
     * Permet de définir la configuration des liens du footer.
     *
     * @return void
     */
    protected function set_config__footer() {
        $footer = array();
        // Documentation du site
        $footer[] = array(
            "title" => __("Documentation"),
            "description" => __("Accéder à l'espace documentation de l'application"),
            "href" => "https://docs.openmairie.org/index.php?project=openresultat&version=2.1&format=html&path=manuel_utilisateur",
            "target" => "_blank",
            "class" => "footer-documentation",
        );

        // Forum openMairie
        $footer[] = array(
            "title" => __("Forum"),
            "description" => __("Espace d'échange ouvert du projet openMairie"),
            "href" => "https://communaute.openmairie.org/c/openresultat",
            "target" => "_blank",
            "class" => "footer-forum",
        );

        // Portail openMairie
        $footer[] = array(
            "title" => __("openMairie.org"),
            "description" => __("Site officiel du projet openMairie"),
            "href" => "http://www.openmairie.org/catalogue/openresultat",
            "target" => "_blank",
            "class" => "footer-openmairie",
        );
        //
        $this->config__footer = $footer;
    }
}
