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

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

class election_unite extends election_unite_gen {

    /**
     * Liste des candidats de l'élection
     * 
     * @var array
     */
    protected $candidats;

    /**
     * Liste des champs permettant de configurer le bureau.
     * Si seul ces champs sont saisis, l'unité même si elle est publiée
     * ne sera pas considéré comme envoyée.
     *
     * @var array
     */
    protected $champsConfig = array(
        'inscrit',
        'emargement',
        'procuration',
        'election_unite',
        'election',
        'unite',
        'envoi_aff',
        'envoi_web',
        'saisie',
        'validation',
        'ouverture',
        'date_derniere_modif'
    );

    /**
     * @return array liste de candidat
     */
    protected function get_candidats(){
        return ! empty($this->candidats) ? $this->candidats : array();
    }

    /**
     * Constructeur.
     *
     * @param string $id Identifiant de l'objet.
     * @param null &$dnu1 @deprecated  Ne pas utiliser.
     * @param null $dnu2 @deprecated  Ne pas utiliser.
     */
    function __construct($id, &$dnu1 = null, $dnu2 = null) {
        $this->constructeur($id);
        if ($id != "]") {
            // Récupération de la liste des candidats et creation d'un champs pour
            // chaque candidat
            $idElection = $this->getVal("election");
            $election = $this->f->get_element_by_id('election', $idElection);
            $candidats = $election->get_candidats_election($idElection);
            foreach ($candidats as $candidat) {
                $this->champs[] = 'candidat'.$candidat->getVal('ordre');
                // Initialisation pour éviter des erreurs lorsque l'on souhaite accéder
                // aux informations des champs liés aux candidat. Évite notamment des notices
                // PHP lors de la récupération des champs de fusion
                $this->type[] = 'int4';
                $this->longueurMax[] = 4;
                $this->flags[] = '';
            }
            $this->candidats = $candidats;

            // Ajout du champ permettant de récupérer l'heure d'ouverture du formulaire
            $this->champs[] = 'ouverture';
            // Idem que pour les champs candidats
                $this->type[] = 'float8';
                $this->longueurMax[] = 8;
                $this->flags[] = '';
        }
    }

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

        // la suppression ne doit pas être possible
        $this->class_actions[2] = '';
        // la modification (equivalent à la saisie) n'est possible que durant les
        // étapes de simulation et de saisie
        $this->class_actions[1]['portlet']['libelle'] = 'Saisir les résultats';
        $this->class_actions[1]['condition'][0] = 'is_saisie_or_simulation';
        $this->class_actions[1]['condition'][1] = 'is_not_perimetre';
        $this->class_actions[1]['condition'][2] = 'est_autorise';
        $this->class_actions[1]['condition'][3] = 'saisie_en_cours';
        // ACTION - 04 - affichage
        //
        $this->class_actions[4] = array(
            "identifier" => "affichage",
            "portlet" => array(
                "type" => "action-direct-with-confirmation",
                "libelle" => _("envoi à l'animation"),
                "order" => 40,
                "class" => "arrow-right-16",
            ),
            "view" => "formulaire",
            "method" => "action_affichage",
            "permission_suffix" => "publication_res_aff",
            'condition' => array(
                'is_finalisation_saisie_or_simulation',
                'est_publiable'
            )
        );

        // ACTION - 05 - depublier_aff
        //
        $this->class_actions[5] = array(
            "identifier" => "depublier_aff",
            "portlet" => array(
                "type" => "action-direct-with-confirmation",
                "libelle" => _("supprimer de l'animation"),
                "order" => 50,
                "class" => "delete-16",
            ),
            "view" => "formulaire",
            "method" => "action_desaffichage",
            "permission_suffix" => "publication_res_aff",
            'condition' => array(
                'is_finalisation_saisie_or_simulation',
                'est_envoye_aff'
            )
        );
    
        // ACTION - 06 - web
        //
        $this->class_actions[6] = array(
            "identifier" => "web",
            "portlet" => array(
                "type" => "action-direct-with-confirmation",
                "libelle" => _("envoi au portail web"),
                "order" => 60,
                "class" => "arrow-right-16",
            ),
            "view" => "formulaire",
            "method" => "action_web",
            "permission_suffix" => "publication_res_web",
            'condition' => array(
                'is_finalisation_saisie_or_simulation',
                'est_publiable'
            )
        );

        // ACTION - 07 - depublier_web
        //
        $this->class_actions[7] = array(
            "identifier" => "depublier_web",
            "portlet" => array(
                "type" => "action-direct-with-confirmation",
                "libelle" => _("supprimer du portail web"),
                "order" => 70,
                "class" => "delete-16",
            ),
            "view" => "formulaire",
            "method" => "action_annuler_web",
            "permission_suffix" => "publication_res_web",
            'condition' => array(
                'is_finalisation_saisie_or_simulation',
                'est_envoye_web'
            )
        );

        // ACTION - 08 - demande de validation
        //
        $this->class_actions[8] = array(
            "identifier" => "demander_validation",
            "portlet" => array(
                "type" => "action-direct-with-confirmation",
                "libelle" => _("Demande de validation"),
                "order" => 80,
                "class" => "arrow-right-16",
            ),
            "view" => "formulaire",
            "method" => "demande_validation",
            "permission_suffix" => "demander_validation",
            'condition' => array(
                'est_autorise',
                'saisie_en_cours',
                'is_finalisation_saisie_or_simulation'
            )
        );

        // ACTION - 09 - validation
        //
        $this->class_actions[9] = array(
            "identifier" => "valider",
            "portlet" => array(
                "type" => "action-direct-with-confirmation",
                "libelle" => _("Valider"),
                "order" => 90,
                "class" => "arrow-right-16",
            ),
            "view" => "formulaire",
            "method" => "validation",
            "permission_suffix" => "valider",
            'condition' => array(
                'est_autorise',
                'en_attente_de_validation',
                'is_finalisation_saisie_or_simulation'
            )
        );

        // ACTION - 10 - reprendre_la_saisie
        //
        $this->class_actions[10] = array(
            "identifier" => "reprendre_saisie",
            "portlet" => array(
                "type" => "action-direct-with-confirmation",
                "libelle" => _("Reprendre la saisie"),
                "order" => 100,
                "class" => "arrow-right-16",
            ),
            "view" => "formulaire",
            "method" => "reprendre_la_saisie",
            "permission_suffix" => "reprendre_saisie",
            'condition' => array(
                'est_autorise',
                'validee_ou_en_attente_de_validation',
                'is_finalisation_saisie_or_simulation'
            )
        );

        // Récupération de l'instance de l'élection afin de récupérer la liste
        // des centaines et affichage d'une action par centaine
        $idElection = $this->f->get_submitted_get_value('idxformulaire');
        $election = $this->f->get_element_by_id('election', $idElection);
        $centaines = $election->get_centaines_election();
        for ($index = 0; $index < count($centaines); $index++) {
            // Récupération de l'id et du libelle de la centaine pour le
            // paramétrage de l'action
            $idCentaine = $centaines[$index]->getVal('election');
            $libelle = $centaines[$index]->getVal('libelle');
            // ACTION - XXX - saisie des résultats de la centaine
            // Il y a 6 actions avant donc les index commence à 7
            $this->class_actions[11 + $index] = array(
                "identifier" => "centaine_".$idCentaine,
                "portlet" => array(
                    "type" => "action-self",
                    "libelle" => _("saisir résultat : ".$libelle),
                    "order" => 110 + $index,
                    "class" => "edit-16",
                ),
                "view" => "view_centaine",
                "permission_suffix" => "saisir_centaine",
                'condition' => array(
                    'is_saisie_or_simulation',
                    'is_not_perimetre',
                    'est_autorise'
                )
            );
        }
    }

    protected function get_centaine_action() {
        $indexAction = $this->f->get_submitted_get_value('action');
        $idCentaine = 0;
        if ($indexAction >= 7) {
            $identifiant = $this->class_actions[$indexAction]['identifier'];
            $id = str_replace('centaine_', '', $identifiant);
            $idCentaine = intval($id);
        }
        return intval($idCentaine);
    }

    /**
     * VIEW - view_centaine.
     *
     * @return void
     */
    function view_centaine() {
        $this->checkAccessibility();
        $this->retoursousformulaire();
        $idCentaine = $this->get_centaine_action();
        $sql = sprintf(
            'SELECT
                election_unite.election_unite
            FROM
                %1$selection_unite
            WHERE
                election_unite.election=%2$s
                AND election_unite.unite=%3$s',
            DB_PREFIXE,
            $idCentaine,
            $this->getVal("unite")
        );
        $election_unite_centaine_id = $this->f->db->getone($sql);
        $this->f->is_database_error(
            $sql,
            $election_unite_centaine_id,
            'Erreur lors de la récupération de l\'unité liée à la centaine'
        );

        // Objet à charger
        $obj = "election_unite_centaine";
        // Construction de l'url de sousformulaire à appeler
        $url = sprintf(
            '%s&obj=%s&idx=%s&action=1&retourformulaire=election&idxformulaire=%s&retour=form',
            OM_ROUTE_SOUSFORM,
            $obj,
            $election_unite_centaine_id,
            $idCentaine
        );

        // Affichage du container permettant le raffraichissement du contenu
        // dans le cas des action-direct.
        printf(
            '<div id="sousform-href" data-href="%s">
            </div>',
            $url
        );
        // Affichage du container permettant de charger le retour de la requête
        // ajax récupérant le sous formulaire.
        printf(
            '<div id="sousform-%s">
            </div>
            <script>
            ajaxIt(\'%s\', \'%s\');
            </script>',
            $obj,
            $obj,
            $url
        );
    }

    /**
     *
     * @return string
     */
    function get_var_sql_forminc__sql_unite() {
        return "SELECT
                    unite.unite,
                    concat(unite.code_unite, ' ', unite.libelle) as lib
                FROM
                    ".DB_PREFIXE."unite
                ORDER BY
                    unite.ordre ASC";
    }

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

    /**
     * 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);

        // Pour les actions appelée en POST en Ajax, il est nécessaire de
        // qualifier le type de chaque champs (Si le champ n'est pas défini un
        // PHP Notice:  Undefined index dans core/om_formulaire.class.php est
        // levé). On sélectionne donc les actions de portlet de type
        // action-direct ou assimilé et les actions spécifiques avec le même
        // comportement.
        if ($this->get_action_param($maj, "portlet_type") == "action-direct"
            || $this->get_action_param($maj, "portlet_type") == "action-direct-with-confirmation") {
            //
            foreach ($this->champs as $key => $value) {
                $form->setType($value, 'hidden');
            }
            $form->setType($this->clePrimaire, "hiddenstatic");
        }
        // Les champs résultats des candidats ne sont visibles qu'en modification
        $candidats = $this->get_candidats();
        foreach ($candidats as $candidat) {
            $ordre = $candidat->getVal('ordre');
            $form->setType('candidat'.$ordre, "hidden");
            $form->setTaille('candidat'.$ordre, 11);
            $form->setMax('candidat'.$ordre, 11);

            if ($maj == 1) {
                $form->setType('candidat'.$ordre, "text");
            }
        }
        
        // L'unité et l'élection ne sont pas modifiable
        $form->setType('unite', "selecthiddenstatic");
        $form->setType('election', "selecthiddenstatic");
        $form->setType('saisie', "hidden");
        $form->setType('validation', "hidden");
        $form->setType('date_derniere_modif', "hidden");

        // Le champ permettant de récupérer l'heure d'ouverture du formulaire
        // doit toujours être caché
        $form->setType('ouverture', 'hidden');
        
        
        if ($maj==1) {
            $form->setType('envoi_web', "checkboxdisabled");
            $form->setType('envoi_aff', "checkboxdisabled");
            if (! $this->publication_auto_activee()) {
                $form->setType('envoi_web', "checkbox");
                $form->setType('envoi_aff', "checkbox");
            }
            if ($this->calcul_auto_activee()) {
                $form->setType('exprime', "hidden");
            }
        }
    }

    /**
     * SETTER FORM - setOnchange.
     * 
     * @param formulaire $form Instance formulaire.
     * @param integer $maj Identifant numérique de l'action.
     * 
     * @return void
     */
    function setOnchange(&$form, $maj) {
        parent::setOnchange($form, $maj);
        if ($maj==1) {
            $candidats = $this->get_candidats();
            foreach ($candidats as $candidat) {
                $form->setOnchange('candidat'.$candidat->getVal('ordre'), 'VerifNum(this)');
            }
        }
    }

    /**
     * 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) {
        // Nécessaire pour remplir les résultats des candidats car ils ne sont
        // pas issu de la table election_unite. Il faut donc les résupérer et
        // les remplir
        if (($validation==0 && $maj==1) || ($maj != 1)) {
            $candidats = $this->get_candidats();
            foreach ($candidats as $candidat) {
                $ordre = $candidat->getVal('ordre');
                $resultat = $this->get_resultat_candidat_unite(
                    $candidat->getVal('election_candidat'),
                    $this->getVal('election_unite')
                );
                $form->setVal('candidat'.$ordre, $resultat, $validation);
            }
        }
        if ($maj == 1) {
            // Si la publication automatique est activé les attributs d'envoi et d'affichage sont
            // cochés
            if ($this->publication_auto_activee()) {
                $form->setVal('envoi_aff', true);
                $form->setVal('envoi_web', true);
            }
        }

        // Récupère le temps à l'ouverture du formulaire d'ajout, de modification et de suppression
        if ($validation == 0) {
            $form->setVal('ouverture', microtime(true));
        }
    }

    /**
     * SETTER FORM - setLib
     *
     * @param formulaire $form Instance formulaire.
     * @param integer $maj Identifant numérique de l'action.
     *
     * @return void
     */
    function setLib(&$form, $maj) {
        parent::setLib($form, $maj);
        $form->setLib('election_unite', 'id');
        $form->setLib('envoi_aff', 'envoyer à l\'affichage');
        $form->setLib('envoi_web', 'envoyer à la page web');
        $form->setLib('ouverture', 'ouverture');
        
        // libelle des candidats
        $candidats = $this->get_candidats();
        foreach ($candidats as $candidatElec) {
            $ordre = $candidatElec->getVal('ordre');
            $candidat = $this->f->get_element_by_id('candidat', $candidatElec->getVal('candidat'));
            $form->setLib('candidat'.$ordre, $candidat->getVal('libelle'));
        }
    }

    /**
     * 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() {
        // ré-ordonne les champs pour pouvoir les afficher correctement dans setLayout
        return array(
            "election_unite",
            "election",
            "unite",
            "envoi_aff",
            "envoi_web",
            "inscrit",
            "emargement",
            "procuration",
            "votant",
            "blanc",
            "nul",
            "exprime",
            "saisie",
            "validation",
            "date_derniere_modif"
        );
    }

    /**
     * SETTER FORM - setLayout
     *
     * @param formulaire $form Instance formulaire.
     * @param integer $maj Identifant numérique de l'action.
     * 
     * @return void
     */
    function setLayout(&$form, $maj) {
        if ($maj==3) {
            // Fieldset Election contiens dans l'ordre : election_unite, election, libellé
            $form->setBloc('election_unite', 'D', "", "col_3"); // debut du bloc
                $form->setFieldset('election_unite', 'D', _('Election'), "collapsible");
                $form->setFieldset('unite', 'F', '');
            $form->setBloc('unite', 'F', ''); // fin fieldset election
            // Fieldset resultat de l'unité contiens dans l'ordre : inscrit, votant, blanc,
            // nul, exprime
            $form->setBloc('inscrit', 'D', "", "col_3"); // debut du bloc
                $form->setFieldset('inscrit', 'D', _('resultat de l\'unite'), "collapsible");
                $form->setFieldset('exprime', 'F', '');
            $form->setBloc('exprime', 'F', ''); // fin resultat de l'unite
            // Fieldset envoi contiens dans l'ordre : envoi_aff et envoi_web
            $form->setBloc('envoi_aff', 'D', "", "col_3"); // debut du bloc
                $form->setFieldset('envoi_aff', 'D', _('envoi'), "collapsible");
                $form->setFieldset('envoi_web', 'F', '');
            $form->setBloc('envoi_web', 'F', ''); // fin fieldset envoi
        }
        if ($maj == 1) {
            // Fieldset Election contiens dans l'ordre : election_unite, election, libellé
            $form->setBloc('election_unite', 'D', "", ""); // debut du bloc
                $form->setFieldset('election_unite', 'D', _('Election'), "collapsible");
                $form->setFieldset('unite', 'F', '');
            $form->setBloc('unite', 'F', ''); // fin fieldset election
            // Fieldset Publication contiens dans l'ordre : envoi_aff et envoi_web
            $form->setBloc('envoi_aff', 'D', "", ""); // debut du bloc
                $form->setFieldset('envoi_aff', 'D', _('Publication'), "collapsible");
                $form->setFieldset('envoi_web', 'F', '');
            $form->setBloc('envoi_web', 'F', ''); // fin fieldset envoi
            // Fieldset Résultats contiens dans l'ordre : inscrit, votant, blanc,
            // nul, exprime et les champs de chaque candidat
            $lastChamp = $this->champs[count($this->champs) - 1];
            $form->setBloc('inscrit', 'D', "", ""); // debut du bloc
                $form->setFieldset('inscrit', 'D', _('Résultats'), "collapsible");
                $form->setFieldset($lastChamp, 'F', '');
            $form->setBloc($lastChamp, 'F', ''); // fin resultat de l'unite
        }
    }

    /**
     * Vérifie si la saisie est en attente ou si elle a été effectué en testant
     * si un des champs de "résultat" (ceux qui ne sont pas des champs de config)
     * a été saisi.
     *
     * @param array $val tableau des valeurs issus du formulaire
     * @return boolean indique si l'unité est saisie ou pas
     */
    protected function is_saisie($val) {
        $isSaisie = false;
        foreach ($val as $champ => $valeur) {
            if (! in_array($champ, $this->champsConfig)) {
                if (! empty($valeur)) {
                    $isSaisie = true;
                    break;
                }
            }
        }
        return $isSaisie;
    }

    /**
     * Vérifie la validité des valeurs en mode CREATE & UPDATE.
     *
     * - Vérifie qu'il n'y a pas de conflit lors de la saisie'
     * 
     * @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, $dnu1, $dnu2);
        // En cas de conflit de saisie return false et empêche la modification
        if (array_key_exists('ouverture', $val)) {
            if ($this->f->conflit_saisie($this, $val['ouverture'])) {
                $this->addToMessage('Attention: votre modification est en conflit avec la modification précédente!');
                $this->correct = false;
                return;
            }
        }
    }

    /**
     * TRIGGER - triggermodifier
     *
     * - Met à jour les résultats des candidats
     * - Calcul et met a jour le nombre de vote exprime (somme des résultats des candidats)
     * - Verifie si les resultats saisis sont correct
     *
     * @param string $id
     * @param null &$dnu1 @deprecated  Ne pas utiliser.
     * @param array $val Tableau des valeurs brutes.
     * @param null $dnu2 @deprecated  Ne pas utiliser.
     *
     * @return boolean false en cas d'erreur
     */
    function triggermodifier($id, &$dnu1 = null, $val = array(), $dnu2 = null) {
        // calcul automatique des votes exprimés si l'option est activée. Le calcul est réalisé
        // en faisant : exprime = votant - (blanc + nul)
        if ($this->calcul_auto_activee()) {
            $blanc = is_numeric($val['blanc']) ? $val['blanc'] : 0;
            $nul = is_numeric($val['nul']) ? $val['nul'] : 0;
            $votant = is_numeric($val['votant']) ? $val['votant'] : 0;
            $exprime = $votant - ($blanc + $nul);
            $this->valF['exprime'] = $exprime;
            $val['exprime'] = $exprime;
        }

        // /!\ : Le calcul des votes exprimés doit être fait avant. En cas de
        //       remise à zéro des résultats, si le calcul auto est fait après,
        //       le nombre de vote exprime est différent de 0 et l'unité est
        //       considérée comme saisie
        $isSaisie = $this->is_saisie($val);

        // Maj des résultats des candidats
        $succesMaj = $this->maj_resultat_candidat($val);

        if (! $succesMaj) {
            $this->addToMessage('Erreur : les résultats des candidats n\'ont pas été correctement enregistré');
            return false;
        }

        // Vérifie la validité de la saisie et maj de l'état de la saisie
        $correcte = $this->verifier_saisie($val);
        if ($isSaisie) {
            $this->valF['saisie'] = $correcte ? 'correcte' : 'en defaut';
        } else {
            $this->valF['saisie'] = 'en attente';
        }

        $succesAff = $succesWeb = true;
        // Publication automatique si :
        //      * la publication automatique est activée
        //      * les résultats sont publiables soit parce qu'ils n'ont pas besoin d'être validé
        //        soit car la validation est obligatoire et qu'ils ont été validé
        //      * les résultats sont corrects ou alors l'option de validation même en cas d'erreur
        //        est active
        if ($this->est_publiable() &&
            (! $isSaisie ||
                ($isSaisie && $correcte) ||
                $this->publication_erreur_activee())
        ) {
            // En cas de publication automatique les attributs d'envoi prenne pour valeur
            // par défaut 'vrai'.
            // Si la publication est manuel ces attributs seront vrai si l'utilisateur active
            // l'envoi en cochant la case ou en utilisant l'action
            // Dans tous les cas ces attributs permettent de savoir si les résultats doivent
            // être publiés ou pas
            $envoiAff = $val['envoi_aff'] == 'Oui' ? true : false;
            $envoiWeb = $val['envoi_web'] == 'Oui' ? true : false;
            // Met à jour la valeur de la saisie du formulaire pour envoi à l'affichage
            $val['saisie'] = $this->valF['saisie'];

            if ($envoiAff) {
                $succesAff = $this->affichage($val);
            } elseif ($envoiAff != $this->f->boolean_string_to_boolean($this->getVal('envoi_aff'))) {
                // Dépublie uniquement si les résultats ont déjà été publié
                $succesAff = $this->desaffichage($val);
            }
            if ($envoiWeb) {
                $succesWeb = $this->web($val);
            } elseif ($envoiWeb != $this->f->boolean_string_to_boolean($this->getVal('envoi_web'))) {
                // Dépublie uniquement si les résultats ont déjà été publié
                $succesWeb = $this->annuler_web($val);
            }
        } else {
            // Dans le cas, ou la publication auto est activée, évite d'avoir les
            // l'unité considérée comme envoyé alors que ses résultats n'ont
            // pas été transmis
            if (! $this->f->boolean_string_to_boolean($this->getVal('envoi_aff'))) {
                $this->valF['envoi_aff'] = false;
            }
            if (! $this->f->boolean_string_to_boolean($this->getVal('envoi_web'))) {
                $this->valF['envoi_web'] = false;
            }
        }

        $this->correct = $succesMaj && $succesAff && $succesWeb;
        // Mise à jour de la date de dernière modification
        $this->valF['date_derniere_modif'] = microtime(true);
    }

    /**
     * TRIGGER - triggermodifierapres
     *
     * Met à jour les résultats des périmètres qui contiennent l'unité qui viens
     * d'être modifiée
     *
     * @param string $id
     * @param null &$dnu1 @deprecated  Ne pas utiliser.
     * @param array $val Tableau des valeurs brutes.
     * @param null $dnu2 @deprecated  Ne pas utiliser.
     *
     * @param integer $id identifiant de l'objet
     *
     * @return void
     */
    function triggermodifierapres($id, &$dnu1 = null, $val = array(), $dnu2 = null) {
        $correct = $this->maj_resultats_perimetres();
        return $correct;
    }

    /**
     * Met à jour le résultats des périmètres contenant l'unité
     *
     * Récupére la liste des périmètre contenant l'unité. Pour chaque périmètres
     * calcul son résultat à partir des résultat des unités qu'il contiens.
     * Le résultat est ensuite enregistré dans la base de données.
     * Récupère la liste des candidats de l'élection. Calcule le nombre de voix
     * obtenus pour chaque candidat à partir du nombre de voix enregistré pour
     * dans chaque unité appartenant au périmètre. Met à jour le résultat des
     * candidat dans la BD.
     *
     * @return boolean indique si la maj à réussi
     */
    public function maj_resultats_perimetres() {
        // Récupèration de la liste des périmètres contenant l'unité
        // et mise à jour des résultats de chacun de ces périmètres
        $perimetres = $this->get_perimetres_election_unite(
            $this->getVal('unite'),
            $this->getVal('election')
        );
        $candidats = $this->get_candidats();

        $succes = true;
        foreach ($perimetres as $perimetre) {
            // Récupération du nom du périmètre pour les messages
            $unite = $this->f->get_element_by_id('unite', $perimetre->getVal('unite'));
            $libUnite = $unite->getVal('libelle');

            // Calcul et maj des résultats des candidats pour le périmètre
            // Pour cela forme un tableau contenant les résultats de val et qui
            // est organisé comme le tableau des valeurs du formulaire
            // Ainsi la méthode de mise à jour des résultats des candidats peut être
            // utilisée
            $val = array();
            foreach ($candidats as $candidat) {
                $idCandidat = $candidat->getVal('election_candidat');
                $ordre = $candidat->getVal('ordre');
                $resultatCandidat = $this->calcul_resultat_candidat_perimetre($perimetre, $idCandidat);
                $val['candidat'.$ordre] = $resultatCandidat != false ? $resultatCandidat : 0;
            }
            $majResCandidats = $perimetre->maj_resultat_candidat($val);

            // Calcul et maj des résultats du perimetre
            $resultats = $this->calculate_perimetre_results($perimetre);

            // Préparation du tableau des valeurs pour la publication et la vérification de
            // la saisie
            foreach ($perimetre->champs as $key => $champs) {
                if (isset($perimetre->val[$key])) {
                    $val[$champs] = $perimetre->val[$key];
                }
                if (array_key_exists($champs, $resultats)) {
                    $val[$champs] = $resultats[$champs];
                }
            }
            $resultats['envoi_aff'] = $this->f->boolean_string_to_boolean($perimetre->getVal('envoi_aff'));
            $resultats['envoi_web'] = $this->f->boolean_string_to_boolean($perimetre->getVal('envoi_web'));

            // Test de la validité de la saisie et maj des attributs selon le résultat
            // Si les envois ont déjà été réalisé ou que la saisie est valide alors
            // les attributs d'envoi sont vrai sinon ils sont faux
            $isSaisie = $this->is_saisie($val);
            $valide = $perimetre->verifier_saisie($val);
            if (! $isSaisie) {
                $resultats['saisie'] = 'en attente';
            } elseif ($valide) {
                $resultats['saisie'] = 'correcte';
            } else {
                $resultats['saisie'] = 'en defaut';
            }

            $resultats['date_derniere_modif'] = microtime(true);
            
            // Mise à jour des attributs de publication et saisie selon les options choisies
            // et l'état de la saisie
            if ($this->publication_auto_activee() &&
                ($valide || $this->publication_erreur_activee()) &&
                $this->est_publiable()
            ) {
                $resultats['envoi_aff'] = true;
                $resultats['envoi_web'] = true;
            }

            $majResultats = $this->f->modifier_element_BD_by_id(
                'election_unite',
                $perimetre->getVal('election_unite'),
                $resultats
            );

            // Publication des résultats uniquement si les résultats ont été correctement enregistré
            if ($majResultats && $majResCandidats) {
                $this->addToMessage($libUnite.' : Les résultats ont été mis à jour');
                // Publication animation
                if (($valide || $this->publication_erreur_activee()) &&
                    $this->est_publiable()
                ) {
                    if ($resultats['envoi_aff']) {
                        $succesAff = $perimetre->affichage($val);
                        $message = $libUnite.' : les résultats ont été envoyé à l\'animation';
                        if (! $succesAff) {
                            $message = $libUnite.' : Erreur les résultats n\'ont pas été envoyé à l\'animation';
                            $succes = false;
                        }
                        $this->addToMessage($message);
                    }

                    // Publication web
                    if ($resultats['envoi_web']) {
                        $succesWeb = $perimetre->web($val);
                        $message = $libUnite.' : les résultats ont été envoyé au portail web';
                        if (! $succesWeb) {
                            $message = $libUnite.' : Erreur les résultats n\'ont pas été envoyé au portail web';
                            $succes = false;
                        }
                        $this->addToMessage($message);
                    }
                }
            } else {
                $this->addToMessage('Erreur : les résultats n\'ont pas été mis à jour pour : '.$libUnite);
                $succes = false;
                break;
            }
        }
        return $succes;
    }


    /**
     * Verifie si une unité de l'élection est un bureau de vote
     *
     * @return boolean
     */
    public function is_bureau() {
        // Récupére l'instance de l'unité ce qui permet d'accéder à son type
        // Renvoie la valeur de l'attribut 'bureau_vote' du type
        $unite = $this->f->get_element_by_id('unite', $this->getVal('unite'));
        $type = $this->f->get_element_by_id('type_unite', $unite->getVal('type_unite'));
        $isBureau = $this->f->boolean_string_to_boolean($type->getVal('bureau_vote'));
        return $isBureau;
    }

    /**
     * Indique si l'étape en cours est celle de la saisie ou
     * de la simulation
     *
     * @return boolean
     */
    protected function is_saisie_or_simulation() {
        $election = $this->f->get_element_by_id('election', $this->getVal('election'));
        return $election->is_etape_saisie() || $election->is_etape_simulation() ;
    }

    /**
     * Indique si l'étape en cours est celle de la saisie, de la finalisation ou
     * de la simulation
     *
     * @return boolean
     */
    protected function is_finalisation_saisie_or_simulation() {
        $election = $this->f->get_element_by_id('election', $this->getVal('election'));
        return $election->is_etape_saisie() ||
            $election->is_etape_finalisation() ||
            $election->is_etape_simulation();
    }

    /**
     * Indique si l'unité n'est pas un périmètre
     *
     * @return booleen true : pas perimetre, false : perimetre
     */
    protected function is_not_perimetre() {
        //instance de l'unité permettant d'accéder à l'attribut is_perimetre
        $unite = $this->f->get_inst__om_dbform(array(
            'obj' => 'unite',
            'idx' => $this->getVal('unite')
        ));
        return ! $this->f->boolean_string_to_boolean($unite->getVal('perimetre'));
    }

    /**
     * Indique si l'utilisateur à le droit de saisir les résultats de cette
     * unité de l'élection.
     *
     * @return booleen true : autorisé, false : pas autorisé
     */
    protected function est_autorise() {
        return $this->f->est_autorise($this->getVal('election'), $this->getVal('unite'));
    }

    // ===========================================
    // Methodes d'envoi des fichiers à l'affichage
    // ===========================================

    /**
     * Cette méthode permet de préparer l'envoi à l'affichage dans le cas
     * ou l'affichage est réalisé par une action.
     * Met à jour l'attribut d'envoi à l'affichage si nécessaire puis
     * prépare le tableau des valeurs à envoyer à l'affichage.
     * Pour finir fait appel à la méthode affichage() pour envoyer les
     * résultats à l'affichage.
     *
     * @return boolean
     */
    protected function action_affichage() {
        // Dans le contexte de l'action, la valeur 'envoi_aff' doit être modifié
        // dans la BD.
        if ($this->getVal("envoi_aff") === 'f') {
            $modif = array(
                "envoi_aff" => true
            );

            $this->f->modifier_element_BD_by_id(
                'election_unite',
                $this->getVal("election_unite"),
                $modif
            );
        }
        
        // Préparation du tableau des valeurs similaire à celui issu
        // du formulaire
        $val = array();
        foreach ($this->champs as $key => $champs) {
            if (isset($this->val[$key])) {
                $val[$champs] = $this->val[$key];
            }
        }
        $val['envoi_aff'] = true;

        return $this->affichage($val);
    }

    /**
     * Effectue l'envoi à l'animation des résultats de l'unité.
     * Ecris / met à jour 2 fichiers :
     *  -> le fichier contenant les résultats de l'unité : bres/bX.json
     *  -> le fichier contenant les infos des unités et notamment leur
     *  état (arrivée ou pas) : unites.json
     *
     * @return boolean indique si l'envoi des fichiers à réussi
     */
    protected function affichage($val) {
        // Creation du repertoire de l'élection. Permet d'éviter les problèmes d'écriture
        // de fichier pour l'envoi à l'affichage. En effet, si plusieurs repertoire doivent
        // être crées le fichier n'arrive pas à s'écrire. C'est par exemple le cas pour les
        // résultats qui sont dans le repertoire bres du repertoire de l'élection.
        if (! file_exists('../aff/res/'.$val['election'])) {
            if (! mkdir('../aff/res/'.$val['election'])) {
                $this->addToMessage('repertoire aff de l\'élection non crée');
            }
        }
        $affRes = $this->ecris_fichier_resultats_unite_affichage($val);
        $affInfo = $this->ecris_fichier_info_unite_affichage($val);


        $succes = $affRes && $affInfo;
        $message = $succes ? 'envoi affichage effectué' : 'envoie affichage non effectué';
        $this->addToMessage($message);
        return $succes;
    }

    /**
     * Prépare la dépublication des résultats de l'animation lorsqu'elle
     * est faite via une action
     * Met à jour l'attribut d'envoi à l'affichage et prépare le tableau
     * des valeurs identique à celui issu du formulaire.
     *
     * @return boolean indique si l'annulation des résultats à réussi
     */
    public function action_desaffichage() {
        if ($this->getVal("envoi_aff") === 't') {
            $modif = array(
                "envoi_aff" => false
            );

            $this->f->modifier_element_BD_by_id(
                'election_unite',
                $this->getVal("election_unite"),
                $modif
            );
        }

        // Préparation d'un tableau des valeurs identique à celui issus
        // du formulaire
        $val = array();
        foreach ($this->champs as $key => $champs) {
            if (isset($this->val[$key])) {
                $val[$champs] = $this->val[$key];
            }
        }
        $val['envoi_aff'] = false;

        $succes = $this->desaffichage($val);
        return $succes;
    }

    /**
     * Supprime le fichier contenant les résultats de l'unité puis met à
     * jour la liste des unités arrivées/non arrivées.
     *
     * @param array tableau des valeurs issus du formulaire
     * @return boolean
     */
    public function desaffichage($val) {
        $succes = true;
        $message = 'Aucun fichier à supprimer';

        // Suppression du fichier contenant les résultats, si il existe
        $uniteId = $val['unite'];
        $electionId = $val['election'];
        if (file_exists("../aff/res/".$electionId."/bres/b".$uniteId.".json")) {
            $succes = unlink('../aff/res/'.$electionId.'/bres/b'.$uniteId.'.json');
            $message = $succes ? '../aff/res/'.$electionId.'/bres/b'.$uniteId.'.json supprimé' :
            '../aff/res/'.$electionId.'/bres/b'.$uniteId.'.json non supprimé';
        }
        $this->addToMessage($message);

        // Mis à jour de l'état de l'unité dans le fichier des infos des unités
        $succes = $this->ecris_fichier_info_unite_affichage($val);
        $message = $succes ? 'Les resultats ont été mis à jour' :
            'Les résultats n\'ont pas été mis à jour';
        $this->addToMessage($message);
        return $succes;
    }

    /**
     * Permet de mettre à jour les fichiers du dossier "aff/res/".$election :
     * /bres/b."codeunite".inc, election.inc, last.inc, unites.inc, resultats.inc
     *
     *    $unite_libelle = "1 - Mairie";
     *    $inscrit = "100";
     *    $votant = "80";
     *    $exprime = "60";
     *    $blanc = "10";
     *    $nul = "10";
     *    $type = "bureau de vote"
     *    $candidat [1] = array(
     *          'nom' => "Gilbert MATHIEU",
     *          'prenom' => "Liste pour le renouveau",
     *          'voix' => "50",
     *          'tx' => "83.33%"
     *          );
     *
     * @param array tableau des valeurs de l'unité
     * @return boolean
     */
    protected function ecris_fichier_resultats_unite_affichage($val) {
        $succes = false;

        $unite_libelle = $this->get_unite_libelle($val['unite']);
        // Composition du tableau qui envoyé en json dans le repertoire de
        // l'affichage
        $resultats = array(
            'libelle' => $unite_libelle,
            'inscrit' => $val['inscrit'],
            'votant' => $val['votant'],
            'exprime' => $val['exprime'],
            'blanc' => $val['blanc'],
            'nul' => $val['nul'],
            'candidats' => array()
        );

        // Récupération des résultats de chaque candidats dans un tableau
        // qui sera ensuite associé à l'index 'candidats' du tableau des résultats
        $candidats = $this->get_candidats();
        foreach ($candidats as $candidatElec) {
            $idElectionCandidat = $candidatElec->getVal('election_candidat');
            $idCandidat = $candidatElec->getVal('candidat');
            // Récupération de l'instance du candidat pour accéder à son libellé
            $candidat = $this->f->get_element_by_id('candidat', $idCandidat);
            // Récupération du nombre de voix obtenu dans cette unité par le candidat
            $resultat = $this->get_resultat_candidat_unite(
                $idElectionCandidat,
                $val['election_unite']
            );
            // Calcul du pourcentage de voix obtenu par le candidat
            $resultat = ! empty($resultat) ? $resultat : 0;
            $taux = $val['exprime'] != 0 ?
                number_format(round($resultat * 100 / $val['exprime'], 2), 2).'%'
                : '0%';

                $resultats['candidats'][$candidatElec->getVal('ordre')] = array(
                    'nom' => $candidat->getVal('libelle'),
                    'prenom' => $candidat->getVal('libelle_liste'),
                    'voix' => $resultat,
                    'tx' => $taux
                );
        }

        // Ecriture du fichier contenant le json du résultats dans le repertoire de l'élection
        $resultats = json_encode($resultats);
        $succes = $this->f->write_file(
            '../aff/res/'.$val['election'].'/bres/b'.$val['unite'].'.json',
            $resultats
        );

        $message = $succes ?
            '../aff/res/'.$val['election'].'/bres/b'.$val['unite'].'.json envoyé'
            : 'Les résultats de l\'unité non pas été envoyé';
        $this->addToMessage($message);
        return $succes;
    }

    /**
     * Ecris un fichier contenant les informations d'une unité de la manière suivante :
     * $unite [1] = array ('code' => "1",'etat' => "1", 'lib' => "Mairie");
     *
     * @param array tableau des valeurs de l'unité
     * @return boolean
     */
    public function ecris_fichier_info_unite_affichage($val) {
        $electionId = $val['election'];
        $election = $this->f->get_element_by_id('election', $electionId);
        $unitesElection = $election->get_unites_election($electionId);

        // Tableau contenant pour chaque unité son numéro d'ordre, si elle est envoyé ou pas
        // son type, son libelle et si c'est la dernière envoyée
        $contenu = array();
        foreach ($unitesElection as $uniteElection) {
            $unite = $this->f->get_element_by_id('unite', $uniteElection->getVal('unite'));
            // Si l'unité ayant servi à faire l'envoi est la même que celle dont on est en
            // train de récupérer les valeurs alors c'est que c'est la dernière envoyée
            $envoi = $this->f->boolean_string_to_boolean($uniteElection->getVal('envoi_aff'));
            $saisie =  $uniteElection->getVal('saisie') == 'en attente' ? false : true;
            $isLast = false;
            if ($val['unite'] == $unite->getVal('unite')) {
                $envoi = $val['envoi_aff'] === 'Oui' ||
                        $val['envoi_aff'] === 't' ||
                        $val['envoi_aff'] === true ?
                    true : false;
                $isLast = $envoi;
                $saisie = $val['saisie'] == 'en attente' ? false : true;
            }

            $arrive = $envoi && $saisie;

            $contenu[$unite->getVal('unite')] = array(
                    'ordre' => $unite->getVal('ordre'),
                    'envoie' => $arrive,
                    'type' => $unite->getVal('type_unite'),
                    'lib' => $unite->getVal('code_unite').' '.$unite->getVal('libelle'),
                    'is_last' => $isLast
            );
        }
        // Passage du tableau en format json et écriture du fichier json dans le repertoire
        // de l'élection
        $contenu = json_encode($contenu);
        $envoi = $this->f->write_file("../aff/res/".$electionId."/unites.json", $contenu);

        $message = $envoi ? '../aff/res/'.$electionId.'/unites.json envoyé'
            : '../aff/res/'.$electionId.'/unites.json non envoyé';
        $this->addToMessage($message);
        return $envoi;
    }

    // ===============================================
    // methodes d'envoi des fichiers au répertoire web
    // ===============================================

    /**
     * Cette méthode permet de préparer l'envoi au portail web dans le cas
     * ou l'affichage est réalisé par une action.
     * Met à jour l'attribut d'envoi à la page web si nécessaire puis
     * prépare le tableau des valeurs à envoyer à la page web.
     * Pour finir fait appel à la méthode web() pour envoyer les
     * résultats au répertoire web.
     *
     * @param array tableau des valeurs de l'unité
     * @return boolean
     */
    protected function action_web() {
        // Dans le contexte de l'action, la valeur 'envoi_aff' doit être modifié
        // dans la BD.
        if ($this->getVal("envoi_web") === 'f') {
            $modif = array(
                "envoi_web" => true
            );

            $this->f->modifier_element_BD_by_id(
                'election_unite',
                $this->getVal("election_unite"),
                $modif
            );
        }

        // Préparation d'un tableau des valeurs identique à celui issus
        // du formulaire
        $val = array();
        foreach ($this->champs as $key => $champs) {
            if (isset($this->val[$key])) {
                $val[$champs] = $this->val[$key];
            }
        }
        $val['envoi_web'] = true;

        return $this->web($val);
    }

    /**
     * Fait appel aux méthodes permettant d'écrire les fichiers contenant
     * les informations nécessaire au portail web.
     * Ecris / met à jour 4 fichiers :
     *  -> le fichier des résultats de l'unité : bX.html
     *  -> le fichier contenant les infos des unités et notamment leur état
     *  (arrivé ou pas) : unite.inc
     *  -> le fichier contenant le résultat global de l'élection : collectivite.inc
     *  -> le fichier contenant les infos de l'élection et notamment le
     *  nombre d'unité : election.inc
     *
     * @param array tableau des valeurs issus du formulaire
     * @return boolean indique si l'envoi des fichiers à réussi
     */
    protected function web($val) {
        $webRes = $this->ecris_fichier_resultat_unite_web($val);
        $webUnite = $this->ecris_fichier_info_unite_web($val);
        $webGlobal = $this->ecris_fichier_resultats_globaux_web($val);
        $webElec = $this->ecris_fichier_info_election_web($val);
    
        $succes = $webRes && $webUnite && $webGlobal && $webElec;
        $message = $succes ? 'envoi web effectué' : 'Erreur lors de l\'envoi web';
        $this->addToMessage($message);
        return $succes;
    }

    /**
     * Prépare la dépublication des résultats de la page web lorsqu'elle
     * est faite via une action
     * Met à jour l'attribut d'envoi à la page web et prépare le tableau
     * des valeurs identique à celui issu du formulaire.
     *
     * @return boolean indique si l'annulation des résultats à réussi
     */
    public function action_annuler_web() {
        if ($this->getVal("envoi_web") === 't') {
            $modif = array(
                "envoi_web" => false
            );

            $this->f->modifier_element_BD_by_id(
                'election_unite',
                $this->getVal("election_unite"),
                $modif
            );
        }

        // Préparation d'un tableau des valeurs identique à celui issus
        // du formulaire
        $val = array();
        foreach ($this->champs as $key => $champs) {
            if (isset($this->val[$key])) {
                $val[$champs] = $this->val[$key];
            }
        }
        $val['envoi_web'] = '';

        $succes = $this->annuler_web($val);
        return $succes;
    }

    /**
     * Supprime le fichier contenant les résultats de l'unité, du repertoire web,
     * met à jour l'état de l'unité et le nombre d'unités envoyés dans les fichiers
     * contenant les infos sur les unités et l'élection.
     * Pour finir, met à jour le fichier contenant le résultat global de l'élection
     *
     * @param array tableau des valeurs issus du formulaire
     * @return boolean indique si la suppression a correctement été effectuée
     */
    public function annuler_web($val) {
        $succes = true;
        
        $idElection = $val['election'];
        $election = $this->f->get_element_by_id('election', $idElection);
        $unite = $this->f->get_element_by_id('unite', $val['unite']);
        $ordre = $unite->getVal('ordre');

        // Suppression du fichier contenant les résultats de l'unité
        $message = 'Aucun fichier à supprimer';
        $path = $election->get_election_web_path();
        if (file_exists($path.'/b'.$ordre.'.html')) {
            $succes = unlink($path.'/b'.$ordre.'.html');
            $message = $succes ? $path.'/b'.$ordre.'.html supprimé' :
                $path.'/b'.$ordre.'.html non supprimé' ;
        }
        $this->addToMessage($message);

        // Maj des fichiers du repertoire web
        $webUnite = $this->ecris_fichier_info_unite_web($val);
        $webGlobal = $this->ecris_fichier_resultats_globaux_web($val);
        $webElec = $this->ecris_fichier_info_election_web($val);
        $succes = $webUnite && $webGlobal && $webElec;
        $message = $succes ? 'Les fichiers du répertoire web ont été mis à jour' :
            'Erreur lors de la mise à jour des fichiers du répertoire web';
            $this->addToMessage($message);
        return $succes;
    }

    /**
     * Permet de mettre à jour les fichiers  du dossier : "web/res/".$election."/bres/"
     * b."codeunite".html , election.inc,  unite.inc, collectivite.inc
     *
     * @param array tableau des valeurs de l'unité
     * @return boolean
    */
    protected function ecris_fichier_resultat_unite_web($val) {
        $electionId = $val['election'];
        // Récupération de la liste des candidats de l'élection
        $election = $this->f->get_element_by_id('election', $electionId);
        $candidats = $election->get_candidats_election($electionId);
        
        // Préparation de toutes les informations à afficher
        $unite = $this->f->get_element_by_id('unite', $val['unite']);
        $ordre = $unite->getVal('ordre');
        $code = $unite->getVal('code_unite');
        $inscrit = ! empty($val['inscrit']) ? $val['inscrit']: 0;
        $votant = ! empty($val['votant'])? $val['votant'] : 0;
        $blanc = ! empty($val['blanc'])? $val['blanc'] : 0;
        $nul = ! empty($val['nul'])? $val['nul'] : 0;
        $exprime = ! empty($val['exprime'])? $val['exprime'] : 0;

        // Remplit pour chaque candidat la ligne du tableau contenant son nom et prénom
        // son nombre de voix et son pourcentage de voix par rapport au vote exprime
        $htmlResCandidats = '';
        foreach ($candidats as $candidatElec) {
            // Récupération de l'instance du candidat pour obtenir son nom et prenom (libelle)
            $candidat = $this->f->get_element_by_id('candidat', $candidatElec->getVal('candidat'));
            $nom = $candidat->getVal('libelle').' '.$candidat->getVal('libelle_liste');

            $resultat = $this->get_resultat_candidat_unite(
                $candidatElec->getVal('election_candidat'),
                $val['election_unite']
            );
            $resultat = ! empty($resultat) ? $resultat : 0;
            $taux = $exprime != 0 ?
                number_format(round($resultat * 100 / $exprime, 2), 2).'%' : '0%';

            $htmlResCandidats .= sprintf(
                "<tr>
<td valign=middle align=left>
%s
</td><td valign=middle align=right>
%d
</td><td valign=middle align=right>
%s
</td></tr>",
                $nom,
                $resultat,
                $taux
            );
        }

        // Code html du fichier web des résultats de l'unité
        $htmlResultat = sprintf(
            "<font SIZE=4 color=#E61313>
<b>
%s
</b>
</font>
<br>
Inscrits: %d
<br>
Votants: %d
<br>
Blancs: %d
<br>
Nuls: %d
<br>
Exprim&eacute;s: %d
<br>
<table border=1  width=290 cellpadding=2 cellspacing=0 bordercolor=#395683 style='font-size:10pt;font-weight: bold;color: #000066'>
<tr>
<td valign=middle align=left bgcolor=#C7DCFC>
Candidats
</td>
<td valign=middle align=right bgcolor=#C7DCFC>
Voix
</td>
<td valign=middle align=right bgcolor=#C7DCFC>
%%
</td>
</tr>
%s
</table>",
            $code.' '.$unite->getVal('libelle'),
            $inscrit,
            $votant,
            $blanc,
            $nul,
            $exprime,
            $htmlResCandidats
        );

        $path = $election->get_election_web_path();
        $succes = $this->f->write_file($path.'/b'.$ordre.'.html', $htmlResultat);
        $message = $succes ? $path.'/b'.$ordre.'.html envoyé' :
            $path.'/b'.$ordre.'.html non envoyé';
        $this->addToMessage($message);
        
        return $succes;
    }

    /**
     * Ecris un fichier contenant les informations d'une unité de la manière suivante :
     * $unite [1] = array ('code' => "1",'etat' => "0", 'obj' => "", 'positionx' => "",'positiony' => "");
     *
     * @param array tableau des valeurs de l'unité
     * @return boolean
     */
    public function ecris_fichier_info_unite_web($val) {
        $electionId = $val['election'];
        $election = $this->f->get_element_by_id('election', $electionId);
        $unitesElection = $election->get_unites_election($electionId);

        $contenu = '';
        foreach ($unitesElection as $uniteElection) {
            $unite = $this->f->get_element_by_id('unite', $uniteElection->getVal('unite'));
            // Seul les bureaux de vote sont envoyés à la page web
            $isBureau = $uniteElection->is_bureau();
            if ($isBureau) {
                // 0 : unite non envoyé à la page web, 1 : unité envoyé
                // Si c'est l'unité que l'on viens d'envoyer elle doit valoir 1 même si son attribut
                // n'est pas encore mis à jour
                $saisie = $uniteElection->getVal('saisie') == 'en attente' ? false : true;
                $publie = $this->f->boolean_string_to_boolean($uniteElection->getVal('envoi_web')) ? 1 : 0;
                if ($uniteElection->getVal('election_unite') == $val['election_unite']) {
                    $publie = $val['envoi_web'] === 'Oui' ||
                            $val['envoi_web'] === 't' ||
                            $val['envoi_web'] === true ?
                            true : false;
                    $saisie = $val['saisie'] == 'en attente' ? false : true;
                }
                $envoi = $saisie && $publie ? 1 : 0;
                $contenu .= sprintf(
                    "<?php
                    \$unite[%d] = array(
                    'ordre' => '%s',
                    'etat' => '%s',
                    'obj' => '',
                   'libelle' => \"%s\"
                    );?>",
                    $unite->getVal('unite'),
                    $unite->getVal('ordre'),
                    $envoi,
                    $unite->getVal('code_unite').' '.$unite->getVal('libelle')
                );
            }
        }
        $path = $election->get_election_web_path();
        $succes = $this->f->write_file($path.'/unite.inc', $contenu);
        $message = $succes ? $path.'/unite.inc envoyé' :
            $path.'/unite.inc non envoyé';
        $this->addToMessage($message);
        return $succes;
    }

    /**
     * Ecris un fichier contenant les informations suivantes :
     * nombre total d'inscrit, de votants, de blancs, de nuls et de votes exprimés
     * ainsi que les candidats et leur informations (photo, code, nom, prenom, parti, voix, tx)
     * Ex :
     * $inscrits = "38209";
     * $votants = "1000";
     * $blancs = "10";
     * $nuls = "0";
     * $exprimes = "1000";
     * $candidats [1] = array (
     *                 'photo' => "1.jpg",
     *                 'code' => "1",
     *                 'nom' => "Pierre CHENEL",
     *                 'prenom' => "Arles bleu marine",
     *                 'parti' => "",
     *                 'voix' => "300",
     *                 'tx' => "30.00%");
     *
     * @param array tableau des valeurs de l'unité
     * @return boolean
     */
    public function ecris_fichier_resultats_globaux_web($val) {
        $idElection = $val['election'];
        $election = $this->f->get_element_by_id('election', $idElection);
        $unitesElec = $election->get_unites_election($idElection);
        $candidats = $this->get_candidats();

        // Calcul du total de l'élection pour les unités arrivées et étant des bureaux
        // Calcul egalement du total obtenu par chaque candidat
        $resultatsACalculer = array(
            'inscrit',
            'votant',
            'nul',
            'blanc',
            'exprime'
        );
        foreach ($resultatsACalculer as $res) {
            ${$res} = 0;
        }

        $resultatCandidats = array();
        foreach ($candidats as $candidat) {
            $resultatCandidats[$candidat->getVal('ordre')] = 0;
        }

        foreach ($unitesElec as $uniteElec) {
            $isBureau = $uniteElec->is_bureau();
            // Gère le cas de l'unité en cours de modification
            $isArrive = $uniteElec->getVal('election_unite') == $val['election_unite'] ?
                $val['envoi_web'] : $this->f->boolean_string_to_boolean($uniteElec->getVal('envoi_web'));
            if ($isBureau && $isArrive) {
                foreach ($resultatsACalculer as $champs) {
                    // Si l'unité est celle qui viens d'être envoyé, les valeurs utilisées sont
                    // celle contenu dans val. Permet d'avoir les résultats à jour même si ils
                    // ne sont pas encore enregistré dans la BD, ce qui est le cas lorsque la
                    // méthode est appellé dans un trigger
                    $res = $uniteElec->getVal('election_unite') == $val['election_unite'] ?
                        $val[$champs] : $uniteElec->getVal($champs);
                    ${$champs} += ! empty($res) ? $res : 0;
                }
                foreach ($candidats as $candidat) {
                    $resultat = $this->get_resultat_candidat_unite(
                        $candidat->getVal('election_candidat'),
                        $uniteElec->getVal('election_unite')
                    );
                    $resultatCandidats[$candidat->getVal('ordre')] += ! empty($resultat) ? $resultat : 0;
                }
            }
        }

        // Ecriture du tableau des résultats des candidats
        $tableauResCandidat = '';
        $indexCandidat = 0;
        foreach ($candidats as $candidatElec) {
            $indexCandidat++;
            $candidat = $this->f->get_element_by_id('candidat', $candidatElec->getVal('candidat'));
            $resultat = $resultatCandidats[$candidatElec->getVal('ordre')];
            $taux = ! empty($exprime) && $exprime != 0 ?
                number_format(($resultat / $exprime) * 100, 2).'%'
                : '0%';

            $tableauResCandidat .= sprintf(
                "\$candidats[%d] = array(
                    'photo' => '',
                    'code' => '%d',
                    'nom' => \"%s\",
                    'prenom' => \"%s\",
                    'parti' => '',
                    'voix' => '%d',
                    'tx' => '%s'
                );",
                $indexCandidat,
                $candidatElec->getVal('ordre'),
                $candidat->getVal('libelle'),
                $candidat->getVal('libelle_liste'),
                $resultat,
                $taux
            );
        }

        // Ecriture du contenu du fichier contenant les résultats de l'élection
        $contenu = sprintf(
            '<?php
            $inscrits = %d;
            $votants = %d;
            $blancs = %d;
            $nuls = %d;
            $exprimes = %d;
            %s
            ?>',
            $inscrit,
            $votant,
            $blanc,
            $nul,
            $exprime,
            $tableauResCandidat
        );

        $path = $election->get_election_web_path();
        $succes = $this->f->write_file($path.'/collectivite.inc', $contenu);
        $message = $succes ? $path.'/collectivite.inc envoyé' :
            $path.'/collectivite.inc non envoyé';
        $this->addToMessage($message);
        return $succes;
    }

    /**
     * Ecris un fichier contenant les informations sur l'affichage web de l'election : 
     * Ex :
     * $election_libelle = "Municipales 2014 2eme tour";
     * $election_date = "2014-03-30";
     * $nbcandidat = "3";
     * $unite_arr = "1";
     * $unite_tot = "35";
     *
     * @param array tableau des valeurs de l'unité
     * @return boolean
     */
    public function ecris_fichier_info_election_web($val) {
        $idElection = $val['election'];
        $election = $this->f->get_element_by_id('election', $idElection);
        $unites = $election->get_unites_election($idElection);
        // Récupération de la liste des candidats pour connaître leur nombre
        $candidats = $election->get_candidats_election($idElection);

        // Calcul du nombre d'unités arrivées et du nombre d'unités totale
        $nbUnitesArrivees = 0;
        $nbUnites = 0;

        foreach ($unites as $uniteElec) {
            $unite = $this->f->get_element_by_id('unite', $uniteElec->getVal('unite'));
            $type = $this->f->get_element_by_id('type_unite', $unite->getVal('type_unite'));
            $isBureau = $this->f->boolean_string_to_boolean($type->getVal('bureau_vote'));
            if ($isBureau) {
                $nbUnites++;
                // Si l'unité est celle qui viens d'être envoyé on utilise le tableau des
                // valeur fourni en paramétre. Cela permet d'avoir les bons résultats
                // même si l'unité n'a pas encore été modifié. C'est le cas lorsqu'elle
                // est appellée via un trigger
                $publie = $this->f->boolean_string_to_boolean($uniteElec->getVal('envoi_web'));
                $saisie = $uniteElec->getVal('saisie') == 'en attente' ? false : true;
                if ($uniteElec->getVal('election_unite') == $val['election_unite']) {
                    $publie = $val['envoi_web'] === true || $val['envoi_web'] === 'Oui'
                        || $val['envoi_web'] === 't' ? true : false;
                    $saisie = $val['saisie'] == 'en attente' ? false : true;
                }
                if ($publie && $saisie) {
                    $nbUnitesArrivees++;
                }
            }
        }

        // Ecriture du contenu du fichier
        $contenu = sprintf(
            '<?php
            $election_libelle = "%s";
            $election_date = "%s";
            $nbcandidat = "%d";
            $unite_arr = "%d";
            $unite_tot = "%d";
            ?>',
            $this->get_election_libelle($idElection),
            $this->get_election_date($idElection),
            count($candidats),
            $nbUnitesArrivees,
            $nbUnites
        );

        $path = $election->get_election_web_path();
        $succes = $this->f->write_file($path."/election.inc", $contenu);
        $message = $succes ? $path.'/election.inc envoyé' :
            $path.'/election.inc non envoyé';
        $this->addToMessage($message);
        return $succes;
    }

    // ==================================================================
    // methodes communes de recuperation de donnees pour affichage et web
    // ==================================================================

    /**
     * Récupére le libellé et l'ordre d'une unité à l'aide son id
     * puis créer un nouveau libellé de type : n°ordre - libellé
     * ex : 1 - ARLES
     *
     * @param $idUnite identifiant de l'unité dont on veut le libellé
     * @return $newLibelle nouveau libellé
     */
    protected function get_unite_libelle($idUnite) {
        // Récupère l'instance de l'unité à l'aide de son id
        $unite = $this->f->get_inst__om_dbform(array(
            "obj" => "unite",
            "idx" => $idUnite
        ));
        // Récupération de son libellé
        $libelle = $unite->getVal("libelle");
        // Récupération de son numero d'ordre
        $code = $unite->getVal("code_unite");
        // Construction de son libellé d'affichage avec son ordre et son libellé
        $newLibelle=$code." ".$libelle;
        $this->msg .=_("unité")." ".$newLibelle."</br>";
        return $newLibelle;
    }

    /**
     * Récupère le libellé d'une élection
     *
     * @param $idElection identifiant de l'élection
     * @return $libelle libellé de l'élection
     */
    protected function get_election_libelle($idElection) {
        // Récupère l'instance de l'élection à l'aide de son id
        $election = $this->f->get_inst__om_dbform(array(
            "obj" => "election",
            "idx" => $idElection
        ));
        // Récupération du libellé de l'élection
        $libelle = $election->getVal("libelle");
        return $libelle;
    }

    /**
     * Récupère la date d'une élection
     *
     * @param $idElection identifiant de l'élection
     * @return $date date de l'élection
     */
    protected function get_election_date($idElection) {
        // Récupère l'instance de l'élection à l'aide de son id
        $election = $this->f->get_inst__om_dbform(array(
            "obj" => "election",
            "idx" => $idElection
        ));
        // Récupération de la date de l'élection
        $date = $election->getVal("date");
        return $date;
    }

    /**
     * Recupere dans la base de données l'identifiant de toutes les
     * unités liées à l'élection et qui sont des périmètres.
     * Retourne un tableau contenant la liste des identifiants de ces unités.
     *
     * Si la requête echoue un message d'erreur est affiché et une liste
     * vide est retournée.
     *
     * @param integer $idElection identifiant de l'élection
     *
     * @return array $perimetresList liste des périmètres
     */
    public function get_election_perimetres($idElection) {
        //Requête sql donnant la liste des unités de l'élection étant des
        //périmètres
        $sql = "SELECT
                    election_unite
                FROM
                    ".DB_PREFIXE."election_unite
                    INNER JOIN ".DB_PREFIXE."unite ON election_unite.unite = unite.unite
                WHERE
                    election = %d
                    AND perimetre = 'true'";
        $sql = sprintf(
            $sql,
            $this->f->db->escapeSimple($idElection)
        );
        $res = $this->f->db->query($sql);
        //Si la requête renvoie une erreur le message d'erreur est affiché
        //et un tableau vide est retourné
        $perimetresList = array();
        if ($this->f->is_database_error($sql, $res, 'Erreur lors de la récupération des périmètres')) {
            return $perimetresList;
        }

        //Pour chaque résultat obtenu récupèration de l'instance et
        //ajout de l'instance dans le tableau des périmètres
        while ($row = $res->fetchRow(DB_FETCHMODE_ASSOC)) {
            $perimetre = $this->f->get_inst__om_dbform(array(
                'obj' => 'election_unite',
                'idx' => $row['election_unite']
            ));
            $perimetresList[] = $perimetre;
        }
        return $perimetresList;
    }

    /**
     * Récupére et renvoie le nombre de voie enregistré pour le candidat
     * dans l'unité donnée
     *
     * @param integer $idCandidat identifiant du candidat pour l'élection
     * @param integer $idUnite identifiant de l'unité de l'élection dont on souhaite
     * les résultats
     * @return integer resultat du candidat
     */
    public function get_resultat_candidat_unite($idCandidat, $idUnite) {
        // Récupération du nombre de voix obtenu par le candidat pour l'unité
        $sql = sprintf(
            'SELECT
                resultat
            FROM
                %selection_resultat
            WHERE
                election_unite = %d AND
                election_candidat = %d',
            DB_PREFIXE,
            $idUnite,
            $idCandidat
        );
        $resultat = $this->db->getOne($sql);
        if ($this->f->is_database_error($sql, $resultat, 'Erreur de récupération des résultats')) {
            $resultat = 0;
        }
        return $resultat;
    }

    /**
     * Somme le nombre de vote de chaque candidat et renvoie le résultat
     *
     * @param array $val tableau des valeurs issues du formulaire
     * @return integer nombre de vote exprimé
     */
    protected function calcul_vote_exprime($val) {
        $candidats = $this->get_candidats();
        $exprime = 0;
        foreach ($candidats as $candidat) {
            $ordre = $candidat->getVal('ordre');
            $exprime = array_key_exists('candidat'.$ordre, $val) && is_numeric($val['candidat'.$ordre]) ?
                $exprime + $val['candidat'.$ordre] : $exprime;
        }
        return $exprime;
    }

    /**
     * Calcul les résultats du périmètre passé en paramétre.
     * Les résultats calculés sont :
     *  - le total d'inscrits
     *  - le total de votants,
     *  - le total de vote blanc
     *  - le total de vote nul
     *  - le total d'émargement
     *  - le total de procuration
     *  - le total de votes exprimés
     *  - le nombre de voix obtenues pour chaque candidat
     *
     * Ces résultats sont récupérés à l'aaide d'une requête faisant la somme des
     * résultats des unités contenues par le périmètre.
     *
     * @param election_unite $perimetre perimetre dont on va calculer les résultats
     *
     * @return mixed boolean false si le calcul des résultats de l'unité ou des candidats
     * à échoué, renvoie un array contenant le résultat total et le total de chaque
     * candidats sinon
     */
    public function calculate_perimetre_results($perimetre) {
        $resPerimetre = array();
        // Requete servant à récupérer le résultat d'une unité en sommant
        // les résultats de ses unités enfant
        // Exemple : A contiens B et C alors le total de A est égale au résultat
        // de B + C
        $sql = "
            SELECT
                SUM(inscrit) AS inscrit,
                SUM(votant) AS votant,
                SUM(blanc) AS blanc,
                SUM(nul) AS nul,
                SUM(emargement) AS emargement,
                SUM(procuration) AS procuration,
                SUM(exprime) AS exprime
            FROM
                ".DB_PREFIXE."lien_unite
                LEFT JOIN ".DB_PREFIXE."election_unite
                    ON lien_unite.unite_enfant = election_unite.unite
            WHERE
                unite_parent = '%d'
                AND election = '%d'";

        $sql = sprintf(
            $sql,
            $this->f->db->escapeSimple($perimetre->getVal('unite')),
            $this->f->db->escapeSimple($perimetre->getVal('election'))
        );
        $res = $this->f->db->query($sql);
        if ($this->f->is_database_error(
            $sql,
            $res,
            'Erreur lors du calcul des resultats du perimetre'
        )) {
            return false;
        }
        // Il s'agit d'une somme, il n'y a donc qu'une seule ligne de résultats, il
        //n'est donc pas nécessaire d'utiliser une boucle pour les récupérer.
        $row = $res->fetchRow(DB_FETCHMODE_ASSOC);
        // Liste des résultats récupérés. Remplissage d'un tableau avec ces résultats.
        // Pour chaque élement de cette liste (inscrit, votant, etc.)
        // le tableau prend pour clé l'élement et pour valeur le résultat associé
        // issu de la requête. Si il n'y a pas de résultat associé la valeur 0 est
        // attribué par défaut
        $resultats = array(
            'inscrit',
            'votant',
            'blanc',
            'nul',
            'exprime',
            'emargement',
            'procuration'
        );
        foreach ($resultats as $resultat) {
            $resPerimetre[$resultat] = ! empty($row[$resultat]) ? $row[$resultat] : 0;
        }

        return $resPerimetre;
    }

    /**
     * Calcul le nombre de voix obtenu par un candidat pour un périmètre donnée.
     *
     * Ces résultats sont récupérés à l'aide d'une requête faisant la somme des
     * résultats obtenus par le candidats dans les unités contenues par le périmètre.
     *
     * @param perimetre $perimetre perimetre dont on va calculer les résultats
     *
     * @return mixed boolean false si le calcul des résultats du candidat
     * à échoué, renvoie le nombre de voix obtenu par le candidat sinon
     */
    protected function calcul_resultat_candidat_perimetre($perimetre, $idCandidat) {
        $sql = sprintf(
            'SELECT
                SUM(resultat) AS resultat
            FROM
                %slien_unite
                LEFT JOIN %selection_unite
                    ON lien_unite.unite_enfant = election_unite.unite
                LEFT JOIN %selection_resultat
                    ON election_unite.election_unite = election_resultat.election_unite
            WHERE
                unite_parent = %d
                AND election = %d
                AND election_candidat = %d',
            DB_PREFIXE,
            DB_PREFIXE,
            DB_PREFIXE,
            $perimetre->getVal('unite'),
            $perimetre->getVal('election'),
            $idCandidat
        );
        $resultat = $this->f->db->getOne($sql);
        if ($this->f->is_database_error(
            $sql,
            $resultat,
            'Erreur lors de la récupération des résultats des candidats'
        )) {
            return false;
        }
        return $resultat;
    }

    /**
     * Donne la liste de tous les périmètres liés à l'élection et contenant l'unité
     * voulue. En cas d'erreur lors de la récupération des périmètres un tableau vide
     * est renvoyé.
     *
     * @param integer $uniteId identifiant de l'unité dont on cherche les périmètres
     * @return array liste des périmètres
     */
    public function get_perimetres_election_unite($uniteId, $electionId) {
        $perimetresList = array();
        $unitesIdToTest = array();
        $currentUniteId = $uniteId;

        while (! empty($currentUniteId)) {
            $sql = sprintf(
                'SELECT
                    election_unite
                FROM 
                    %slien_unite
                        INNER JOIN '.DB_PREFIXE.'election_unite
                        ON election_unite.unite = lien_unite.unite_parent
                WHERE
                    unite_enfant = %d
                    AND election = %d',
                DB_PREFIXE,
                $currentUniteId,
                $electionId
            );
            $res = $this->f->db->query($sql);
            if ($this->f->is_database_error($sql, $res, 'Erreur lors de la récupération des périmètres')) {
                return array();
            }
            //Remplis la liste des périmètres avec les résultats de la requête
            while ($row = $res->fetchRow(DB_FETCHMODE_ASSOC)) {
                $perimetre = $this->f->get_element_by_id(
                    'election_unite',
                    intval($row['election_unite'])
                );
                $perimetresList[] = $perimetre;
                $unitesIdToTest[] = $perimetre->getVal('unite');
            }
            $currentUniteId = array_shift($unitesIdToTest);
        }
        return $perimetresList;
    }

    // =========================================================================
    // action : annuler les resultats d'un unite dans la base, affichage et web
    // =========================================================================

    /**
     * Reset les résultats en mettant à 0 :
     *  - les résultats enregistrés dans la table election_unite
     *  - les resultats des candidats dans la table election_resultat
     *
     * Affiche un message indiquant si le reset à réussi ou si il y a eu une
     * erreur
     *
     * @return boolean indique si la remise à zéro à réussi
     */
    public function reset_resultat() {
        $candidats = $this->get_candidats();
        $election = $this->f->get_element_by_id('election', $this->getVal('election'));

        // Reinitialise les résultats en gardant le nombre de votant par défaut qui est
        // nul pour une élection mais égale au nombre de votant voulu pour une centaine
        $votant = ! empty($election->getVal('votant_defaut')) ? $election->getVal('votant_defaut') : null;
        $inscrit = ! empty($this->getVal('inscrit')) ? $this->getVal('inscrit') : null;
        $resultats = array(
            'inscrit' => $inscrit,
            'votant' => $votant,
            'emargement' => null,
            'procuration' => null,
            'nul' => null,
            'blanc' => null,
            'exprime' => null,
            'saisie' => 'en attente',
            'validation' => 'saisie en cours'
        );

        // Remise à 0 des résultats enregistré pour l'unité
        $succes = $this->f->modifier_element_BD_by_id(
            'election_unite',
            $this->getVal('election_unite'),
            $resultats
        );

        // Remise à 0 des résultats de chaque candidat pour l'unité
        foreach ($candidats as $candidat) {
            $sql = sprintf(
                'SELECT
                    election_resultat
                FROM
                    %selection_resultat
                WHERE
                    election_unite = %d AND
                    election_candidat = %d',
                DB_PREFIXE,
                $this->getVal('election_unite'),
                $candidat->getVal('election_candidat')
            );
            
            $idResultat = $this->db->getOne($sql);
            $majResultat = false;
            if (! $this->f->is_database_error(
                $sql,
                $idResultat,
                'Erreur lors de la récupération des résultats'
            )) {
                $majResultat = $this->f->modifier_element_BD_by_id(
                    'election_resultat',
                    $idResultat,
                    array('resultat' => null)
                );
            }
            // Si les résultats n'ont pas pu être récupéré ou maj alors le
            // traitement à échoué
            $succes = $succes && $majResultat;
        }

        $message = $succes ? 'Les résultats enregistrés ont été remis à zéro' :
            'Erreur lors de la remise à zéro des résultats';
            $this->addToMessage($message);

        $succes &= $this->maj_resultats_perimetres();
        $message = $succes ? 'Les résultats des périmètres ont été mis à jour' :
            'Erreur lors de la mise à jour des résultats des périmètres';
        $this->addToMessage($message);

        return $succes;
    }

    // =================================================================
    // affichage des resultats dans le formulaire d affichage
    // =================================================================

    /**
     * En consultation, affiche la liste des candidats et leur résultat
     * sous le formulaire
     *
     * @return void
     */
    function afterSousFormSpecificContent() {
        $maj = $this->getParameter("maj");
        if ($maj==3) {
            $this->affiche_data();
        }
    }

    /**
     * Code html du sous formulaire d'affichage de la liste des candidats
     * et de leur résultats
     *
     * @param integer $election_unite identifiant de l'unité de l'élection
     *
     * @return void
     */
    protected function affiche_data() {
        // Récupération des candidats et de leur nombre de voix
        $candidats = $this->get_candidats();
        $oddEven = 'odd';
        $htmlResultat = '';
        foreach ($candidats as $candidatElec) {
            $candidat = $this->f->get_element_by_id('candidat', $candidatElec->getVal('candidat'));
            $resultat = $this->get_resultat_candidat_unite(
                $candidatElec->getVal('election_candidat'),
                $this->getVal('election_unite')
            );

            // Préparation des lignes du tableau contenant les résultats des candidats
            $htmlResultat .= sprintf(
                '<tr class="tab-data %s">
                    <td>%d</td>
                    <td>%s</td>
                    <td style="text-align:right">%d</td>
                <tr>',
                $oddEven,
                $candidatElec->getVal('ordre'),
                $this->f->db->escapeSimple($candidat->getVal('libelle')),
                ($resultat != false ? $resultat : 0)
            );
            // Switch entre odd et even à chaque itération
            $oddEven = $oddEven === 'odd' ? 'even' : 'odd';
        }

        $exprime = ! empty($this->getVal('exprime')) ? $this->getVal('exprime') : 0;

        printf(
            '<div id="affichage_article" class="formEntete ui-corner-all">
                <fieldset class="cadre ui-corner-all ui-widget-content">
                    <legend>Liste des Candidats</legend>
                    <table class="tab-tab">
                        <tr class="ui-tabs-nav ui-accordion ui-state-default tab-title">
                            <th class="title">ordre</th>
                            <th class="title">candidat</th>
                            <th class="title">voix</th>
                        </tr>
                        %s
                        <tr class="tab-data %s">
                            <td></td>
                            <td>Total exprime</td>
                            <td style="text-align:right">%d</td>
                        </tr>
                    </table>
                </fieldset>
            </div>',
            $htmlResultat,
            $oddEven,
            $exprime
        );
    }

    /**
     * Récupére le tableau des valeurs issues du formulaire et met à jour le résultat
     * de chaque candidat dans la table election_resultat à l'aide de ces valeurs
     *
     * @param array $val tableau des valeurs issues du formulaire
     * Dans ce tableau les résultats des candidats doivent être organisé de cette manière :
     * ex : si le candidat d'ordre 3 a 100 voix
     *      => val['candidat3'] = 100
     *
     * @return boolean indique si la maj à réussi
     */
    protected function maj_resultat_candidat($val) {
        $succes = true;
        $candidats = $this->get_candidats();
        foreach ($candidats as $candidat) {
            $ordre = $candidat->getVal('ordre');
            $resultat = is_numeric($val['candidat'.$ordre]) ? $val['candidat'.$ordre] : 0;
            $modif = array(
                'resultat' => $resultat
            );
            $maj = $this->f->db->autoExecute(
                DB_PREFIXE."election_resultat",
                $modif,
                DB_AUTOQUERY_UPDATE,
                'election_unite = '.$this->getVal("election_unite").
                ' AND election_candidat = '.$candidat->getVal('election_candidat')
            );
            if ($this->f->isDatabaseError($maj, true)) {
                $succes = false;
                $this->addToLog(__METHOD__." database error:".$maj->getDebugInfo().";", DEBUG_MODE);
                $this->addToMessage('Erreur lors de l\'enregistrement des résultats des candidats');
                $this->f->db->rollback();
                break;
            }
            $this->f->db->commit();
        }
        return $succes;
    }

    /**
     * Méthode effectuant une requête pour récupérer un élément de la table
     * election_unite à l'aide des identifiants de l'unité et de l'élection
     * passé en paramètre.
     * A partir de cet id récupère l'instance d'élection_unité correspondante
     * et la renvoie.
     *
     * @param integer $idUnite identifiant de l'unité
     * @param integer $idElection identifiant de l'élection
     *
     * @return election_unite
     */
    public function get_instance_election_unite($idUnite, $idElection) {
        $sql = sprintf(
            'SELECT
                election_unite
            FROM
                %selection_unite
            WHERE
                unite = %d AND
                election = %d',
            DB_PREFIXE,
            $idUnite,
            $idElection
        );
        $res = $this->f->db->getOne($sql);
        if ($this->f->isDatabaseError($res, true)) {
            $this->addToLog(__METHOD__." database error:".$res->getDebugInfo().";", DEBUG_MODE);
            $this->addToMessage('Erreur lors de la récupération de l\'unité');
            return false;
        }
        $electionUnite = $this->f->get_element_by_id('election_unite', $res);
        return $electionUnite;
    }

    /**
     * Vérifie si la saisie est valide et si une erreur est relevé indique
     * laquelle
     *
     * @param array $val tableau des valeurs issues du formulaire
     * @return boolean
     */
    protected function verifier_saisie($val) {
        $valide = true;
        // Vérifie la validité des résultats saisis en comparant le nombre de vote exprime
        // au nombre de votants moins les votes blancs et nuls
        $votants = is_numeric($val['votant']) ? $val['votant'] : 0;
        $nuls    = is_numeric($val['nul'])    ? $val['nul']    : 0;
        $blancs  = is_numeric($val['blanc'])  ? $val['blanc']  : 0;
        $exprimes = is_numeric($val['exprime']) ? $val['exprime'] : 0;
        $inscrits = is_numeric($val['inscrit']) ? $val['inscrit'] : 0;
        $emargements = is_numeric($val['emargement']) ? $val['emargement'] : 0;
        $procuration = is_numeric($val['procuration']) ? $val['procuration'] : 0;
        
        $this->AddToMessage('Total exprimé : '.$exprimes.'<br>');
        $message = '';
        $ecart = $exprimes - ($votants - ($blancs + $nuls));
        if ($ecart != 0) {
            $valide = false;
            $message .= sprintf(
                'ATTENTION : il y a un écart de %d entre le nombre de vote exprimé : %d
                et le nombre de votant - (blanc + nuls) : %d <br>',
                $ecart,
                $exprimes,
                $votants - ($blancs + $nuls)
            );
        }

        $totalCandidats = $this->calcul_vote_exprime($val);
        $ecart = $exprimes - $totalCandidats;
        if ($ecart != 0) {
            $valide = false;
            $message .= sprintf(
                'ATTENTION : il y a un écart de %d entre le nombre de vote exprimé : %d
                et le nombre de vote obtenu par les candidats : %d <br>',
                $ecart,
                $exprimes,
                $totalCandidats
            );
        }

        if ($votants > $inscrits) {
            $valide = false;
            $message .= sprintf(
                'ATTENTION : Il y a plus de votants (%d) que d\'inscrits (%d) <br>',
                $votants,
                $inscrits
            );
        }

        if ($emargements > $inscrits) {
            $valide = false;
            $message .= sprintf(
                'ATTENTION : Il y a plus d\'émargements (%d) que d\'inscrits (%d) <br>',
                $emargements,
                $inscrits
            );
        }

        if ($procuration > $inscrits) {
            $valide = false;
            $message .= sprintf(
                'ATTENTION : Il y a plus de procurations (%d) que d\'inscrits (%d) <br>',
                $procuration,
                $inscrits
            );
        }

        if ($votants < ($nuls + $blancs)) {
            $valide = false;
            $message .= sprintf(
                'ATTENTION : Il y a plus de votes blancs (%d) et nuls (%d) que de votants (%d) <br>',
                $blancs,
                $nuls,
                $votants
            );
        }

        if (! $valide) {
            $this->AddToMessage('<span class="saisie-erronee">'.$message.'</span><br>');
        }
        return $valide;
    }

    /**
     * Donne à l'attribut de validation de l'unité de l'élection la valeur
     * 'en attente' dans la base de donnée.
     *
     * @return boolean indique si la maj à réussi
     */
    protected function demande_validation() {
        $modifie = $this->f->modifier_element_BD_by_id(
            'election_unite',
            $this->getVal('election_unite'),
            array('validation' => 'en attente')
        );
        $message = $modifie ? 'En attente de validation de la saisie' :
            'Erreur lors de la mise à jour de l\'attribut de validation';
        $this->addToMessage($message);
        return $modifie;
    }

    /**
     * Donne à l'attribut de validation de l'unité de l'élection la valeur
     * 'validee' dans la base de donnée.
     *
     * @return boolean indique si la maj à réussi
     */
    protected function validation() {
        $modifie = $this->f->modifier_element_BD_by_id(
            'election_unite',
            $this->getVal('election_unite'),
            array('validation' => 'validee')
        );
        $message = $modifie ? 'La saisie est validée' :
            'Erreur lors de la mise à jour de l\'attribut de validation';
        $this->addToMessage($message);
        
        // Publication des résultats si la publication automatique est activé
        if ($this->publication_auto_activee()) {
            $affichage = $this->action_affichage();
            $message = $affichage ? 'Les résultats ont été envoyés à l\'animation' :
                'Erreur lors de l\'envoi à l\'animation';
            $this->addToMessage($message);

            $web = $this->action_web();
            $message = $web ? 'Les résultats ont été envoyés au portail web' :
                'Erreur lors de l\'envoi au portail web';
            $this->addToMessage($message);
        }

        return $modifie;
    }

    /**
     * Donne à l'attribut de validation de l'unité de l'élection la valeur
     * 'saisie en cours' dans la base de donnée.
     *
     * @return boolean indique si la maj à réussi
     */
    protected function reprendre_la_saisie() {
        $modifie = $this->f->modifier_element_BD_by_id(
            'election_unite',
            $this->getVal('election_unite'),
            array('validation' => 'saisie en cours')
        );
        $message = $modifie ? 'Reprise de la saisie' :
            'Erreur lors de la mise à jour de l\'attribut de validation';
        $this->addToMessage($message);
        return $modifie;
    }

    /**
     * Indique si l'option de calcul automatique des votes exprimés est
     * activé
     *
     * @return boolean
     */
    protected function calcul_auto_activee() {
        $election = $this->f->get_element_by_id('election', $this->getVal('election'));
        $calculAuto = $election->getVal('calcul_auto_exprime');
        return $this->f->boolean_string_to_boolean($calculAuto);
    }

    /**
     * Indique si l'option de publication automatique des résultats est
     * activé
     *
     * @return boolean
     */
    protected function publication_auto_activee() {
        $election = $this->f->get_element_by_id('election', $this->getVal('election'));
        $publicationAuto = $election->getVal('publication_auto');
        return $this->f->boolean_string_to_boolean($publicationAuto);
    }

    /**
     * Indique si l'option de publication des résultats présentant des
     * erreurs de saisie est activé
     *
     * @return boolean
     */
    protected function publication_erreur_activee() {
        $election = $this->f->get_element_by_id('election', $this->getVal('election'));
        $publicationErreur = $election->getVal('publication_erreur');
        return $this->f->boolean_string_to_boolean($publicationErreur);
    }

    /**
     * Fait une requête pour récupérer l'identifiant de l'élection unité à partir
     * de l'identifiant de l'unité et de celui de l'élection.
     * A partir de l'identifiant récupère l'instance d'election_unite recherchée
     *
     * @param integer identifiant de l'élection
     * @param integer identifiant de l'unité
     *
     * @return mixed election_unite ou null en cas d'erreur de BD
     */
    public function get_election_unite($electionId, $uniteId) {
        $sql = sprintf(
            'SELECT
                election_unite
            FROM
                %selection_unite
            WHERE
                election = %d AND
                unite = %d',
            DB_PREFIXE,
            $electionId,
            $uniteId
        );
        $res = $this->f->db->getOne($sql);
        $this->addToLog(__METHOD__ . "() : db->autoExecute(" . $res . ")", VERBOSE_MODE);
        if ($this->f->isDatabaseError($res, true)) {
            $this->addToMessage('Erreur de récupération de l\'unité de l\'élection');
            $this->db->rollback();
            return false;
        }
        $electionUnite = $this->f->get_element_by_id('election_unite', $res);
        return $electionUnite;
    }

    /**
     * Indique si la validation est attente ou pas
     *
     * @return booleen
     */
    protected function en_attente_de_validation() {
        $enAttente = $this->getVal('validation') === 'en attente';
        return $enAttente;
    }

    /**
     * Indique si la saisie est en cours ou pas.
     *
     * @return booleen
     */
    protected function saisie_en_cours() {
        $saisieEnCours = $this->getVal('validation') === 'saisie en cours';
        return $saisieEnCours;
    }

    /**
     * Indique si la saisie a été validée ou pas.
     *
     * @return booleen
     */
    protected function validee() {
        $validee = $this->getVal('validation') === 'validee';
        return $validee;
    }

    /**
     * Indique si la saisie a été validée ou pas.
     *
     * @return booleen
     */
    protected function validee_ou_en_attente_de_validation() {
        return $this->validee() || $this->en_attente_de_validation();
    }

    /**
     * Indique si une unité rempli tous les critères demandés pour pouvoir être publiée
     */
    protected function est_publiable() {
        $election = $this->f->get_element_by_id('election', $this->getVal('election'));
        $validationObligatoire = $this->f->boolean_string_to_boolean(
            $election->getVal('validation_avant_publication')
        );
        $valide = $this->validee();
        return ! $validationObligatoire || $valide;
    }

    /**
     * Indique si les résultats ont été envoyé à l'affichage
     */
    protected function est_envoye_aff() {
        return $this->f->boolean_string_to_boolean($this->getVal('envoi_aff'));
    }

    /**
     * Indique si les résultats ont été envoyés à la page web
     */
    protected function est_envoye_web() {
        return $this->f->boolean_string_to_boolean($this->getVal('envoi_web'));
    }


    function get_results() {
        $results = array(
            "inscrit" => intval($this->getVal("inscrit")),
            "votant" => intval($this->getVal("votant")),
            "emargement" => intval($this->getVal("emargement")),
            "procuration" => intval($this->getVal("procuration")),
            "nul" => intval($this->getVal("nul")),
            "blanc" => intval($this->getVal("blanc")),
            "exprime" => intval($this->getVal("exprime")),
            "abstention" => 0,
            "pc_abstention" => 0.00,
            "pc_votant" => 0.00,
            "pc_emargement" => 0.00,
            "pc_nul" => 0.00,
            "pc_blanc" => 0.00,
            "pc_exprime" => 0.00,
        );
        if ($results["inscrit"] > 0) {
            $results["abstention"] = $results["inscrit"] - $results["votant"];
            $results["pc_abstention"] = $results["abstention"] / $results["inscrit"] * 100;
            $results["pc_votant"] = $results["votant"] / $results["inscrit"] * 100;
            $results["pc_emargement"] = $results["emargement"] / $results["inscrit"] * 100;
        }
        if ($results["votant"] > 0) {
            $results["pc_nul"] = $results["nul"] / $results["votant"] * 100;
            $results["pc_blanc"] = $results["blanc"] / $results["votant"] * 100;
            $results["pc_exprime"] = $results["exprime"] / $results["votant"] * 100;
        }
        return $results;
    }


    /**
     * Récupération des libellés des champs de fusion
     *
     * @return array $labels tableau associatif contenant les labels
     */
    function get_labels_merge_fields() {
        $labels = parent::get_labels_merge_fields();
        //
        $labels[$this->clePrimaire]["election_unite.abstention"] = __("nombre d'abstention");
        $labels[$this->clePrimaire]["election_unite.pourcentage_abstention"] = __("pourcentage d'abstention (12,10%)");
        $labels[$this->clePrimaire]["election_unite.pourcentage_votant"] = __("pourcentage de votants (12,10%)");
        $labels[$this->clePrimaire]["election_unite.pourcentage_emargement"] = __("pourcentage d'émargements (12,10%)");
        $labels[$this->clePrimaire]["election_unite.pourcentage_nul"] = __("pourcentage de nuls (12,10%)");
        $labels[$this->clePrimaire]["election_unite.pourcentage_blanc"] = __("pourcentage de blanc (12,10%)");
        $labels[$this->clePrimaire]["election_unite.pourcentage_exprime"] = __("pourcentage d'exprimés (12,10%)");
        //
        return $labels;
    }

    /**
     * Récupération des veleurs des champs de fusion
     *
     * @return array $values tableau associatif contenant les valeurs
     */
    function get_values_merge_fields() {
        $values = parent::get_values_merge_fields();
        //
        $results = $this->get_results();
        $values["election_unite.inscrit"] = $results["inscrit"];
        $values["election_unite.emargement"] = $results["emargement"];
        $values["election_unite.procuration"] = $results["procuration"];
        $values["election_unite.votant"] = $results["votant"];
        $values["election_unite.blanc"] = $results["blanc"];
        $values["election_unite.nul"] = $results["nul"];
        $values["election_unite.exprime"] = $results["exprime"];
        $values["election_unite.abstention"] = $results["abstention"];
        $values["election_unite.pourcentage_abstention"] = number_format(round($results["pc_abstention"], 2), 2, ",", " ")."%";
        $values["election_unite.pourcentage_votant"] = number_format(round($results["pc_votant"], 2), 2, ",", " ")."%";
        $values["election_unite.pourcentage_emargement"] = number_format(round($results["pc_emargement"], 2), 2, ",", " ")."%";
        $values["election_unite.pourcentage_nul"] = number_format(round($results["pc_nul"], 2), 2, ",", " ")."%";
        $values["election_unite.pourcentage_blanc"] = number_format(round($results["pc_blanc"], 2), 2, ",", " ")."%";
        $values["election_unite.pourcentage_exprime"] = number_format(round($results["pc_exprime"], 2), 2, ",", " ")."%";
        //
        $inst__election = $this->get_inst_common("election");
        $values["election_unite.etat_proclamation"] = $inst__election->get_tableau_resultat_candidat(
            $this->getVal($this->clePrimaire)
        );
        //
        return $values;
    }

    /**
     * MERGE_FIELDS - Liste des classes *and co*.
     * @var array
     */
    var $merge_fields_and_co_obj = array(
        "unite",
        "election",
    );
}
