<?php
/**
 * Ce script définit la classe 'nature_emplacement'.
 *
 * @package opencimetiere
 * @version SVN : $Id$
 */

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

/**
 * Définition de la classe 'nature_emplacement' (om_dbform).
 */
class nature_emplacement extends nature_emplacement_gen {

    /**
     * Vérifie avant mise à jour qu'aucun changement de configuration ne rend
     * inaccessibles des données existantes.
     *
     * Règle : un paramètre ne peut passer de "plus permissif" à "plus restrictif"
     * que si aucune donnée existante ne serait masquée ou bloquée.
     * Si le nouveau paramétrage est identique ou plus permissif → modification libre.
     *
     * Paramètres contrôlés :
     *  - sf_* (9 sous-formulaires) : bloqué si des enregistrements existent dans
     *    la table liée pour les emplacements de cette nature
     *  - inhumations / reductions : bloqué si des opérations du type concerné existent
     *  - defunt_natures : bloqué si des défunts des types exclus existent
     *
     * @param mixed $id
     * @param mixed $dnu1
     * @param array $val
     * @param mixed $dnu2
     * @return void|false
     */
    function triggermodifier($id, &$dnu1 = null, $val = array(), $dnu2 = null) {

        $nature_id = intval($this->getVal('nature_emplacement'));

        // ----------------------------------------------------------------
        // Sous-formulaires sf_*
        // Si un sf passe de TRUE → FALSE et que des données existent dans
        // la table liée pour les emplacements de cette nature → blocage.
        // ----------------------------------------------------------------
        $sf_mapping = array(
            'sf_defunt'          => array('table' => 'defunt',           'label' => 'défunts'),
            'sf_autorisation'    => array('table' => 'autorisation',     'label' => 'contacts / autorisations'),
            'sf_reprise_abandon' => array('table' => 'reprise_abandon',  'label' => 'reprises sur abandon'),
            'sf_genealogie'      => array('table' => 'genealogie',       'label' => 'généalogies'),
            'sf_contrat'         => array('table' => 'contrat',          'label' => 'contrats'),
            'sf_courrier'        => array('table' => 'courrier',         'label' => 'courriers'),
            'sf_operation_trt'   => array('table' => 'operation',        'label' => 'opérations'),
            'sf_travaux'         => array('table' => 'travaux',          'label' => 'travaux'),
            'sf_dossier'         => array('table' => 'dossier',          'label' => 'dossiers'),
        );

        foreach ($sf_mapping as $sf_col => $info) {
            // Déclenchement uniquement si TRUE → FALSE
            if ($this->getVal($sf_col) !== 't' || $this->valF[$sf_col] !== false) {
                continue;
            }
            $qres = $this->f->get_all_results_from_db_query(
                sprintf(
                    "SELECT COUNT(*) AS nb
                     FROM %1\$s%2\$s
                     WHERE emplacement IN (
                         SELECT emplacement FROM %1\$semplacement WHERE nature = %3\$d
                     )",
                    DB_PREFIXE,
                    $info['table'],
                    $nature_id
                ),
                array('origin' => __METHOD__)
            );
            if ($qres['code'] === 'OK'
                && !empty($qres['result'])
                && intval($qres['result'][0]['nb']) > 0) {
                $this->addToMessage(sprintf(
                    __("Impossible de désactiver l'onglet \"%s\" : %d enregistrement(s) existent déjà pour les emplacements de cette nature."),
                    $info['label'],
                    intval($qres['result'][0]['nb'])
                ));
                $this->correct = false;
            }
        }

        // ----------------------------------------------------------------
        // inhumations
        // Si inhumations passe de TRUE → FALSE et que des opérations
        // d'inhumation existent pour cette nature → blocage.
        // ----------------------------------------------------------------
        if ($this->getVal('inhumations') === 't' && $this->valF['inhumations'] === false) {
            $qres = $this->f->get_all_results_from_db_query(
                sprintf(
                    "SELECT COUNT(*) AS nb
                     FROM %1\$soperation
                     INNER JOIN %1\$semplacement
                         ON operation.emplacement = emplacement.emplacement
                     WHERE emplacement.nature = %2\$d
                     AND operation.categorie = 'inhumation'",
                    DB_PREFIXE,
                    $nature_id
                ),
                array('origin' => __METHOD__)
            );
            if ($qres['code'] === 'OK'
                && !empty($qres['result'])
                && intval($qres['result'][0]['nb']) > 0) {
                $this->addToMessage(sprintf(
                    __("Impossible de désactiver les inhumations : %d opération(s) d'inhumation existent déjà pour les emplacements de cette nature."),
                    intval($qres['result'][0]['nb'])
                ));
                $this->correct = false;
            }
        }

        // ----------------------------------------------------------------
        // reductions
        // Si reductions passe de TRUE → FALSE et que des opérations
        // de réduction existent pour cette nature → blocage.
        // ----------------------------------------------------------------
        if ($this->getVal('reductions') === 't' && $this->valF['reductions'] === false) {
            $qres = $this->f->get_all_results_from_db_query(
                sprintf(
                    "SELECT COUNT(*) AS nb
                     FROM %1\$soperation
                     INNER JOIN %1\$semplacement
                         ON operation.emplacement = emplacement.emplacement
                     WHERE emplacement.nature = %2\$d
                     AND operation.categorie = 'reduction'",
                    DB_PREFIXE,
                    $nature_id
                ),
                array('origin' => __METHOD__)
            );
            if ($qres['code'] === 'OK'
                && !empty($qres['result'])
                && intval($qres['result'][0]['nb']) > 0) {
                $this->addToMessage(sprintf(
                    __("Impossible de désactiver les réductions : %d opération(s) de réduction existent déjà pour les emplacements de cette nature."),
                    intval($qres['result'][0]['nb'])
                ));
                $this->correct = false;
            }
        }

        // ----------------------------------------------------------------
        // defunt_natures
        // Si le nouveau paramétrage exclut des types de défunts qui étaient
        // autorisés et que des défunts de ces types existent → blocage.
        // ----------------------------------------------------------------
        $old_types = $this->parse_defunt_natures($this->getVal('defunt_natures'));
        $new_types = $this->parse_defunt_natures($this->valF['defunt_natures']);
        $excluded_types = $this->get_excluded_defunt_types($old_types, $new_types);

        if (!empty($excluded_types)) {
            // Les codes de types sont des valeurs internes contrôlées (alphanum + _)
            $pg_array = "ARRAY['"
                . implode("','", array_map('addslashes', $excluded_types))
                . "']";
            $qres = $this->f->get_all_results_from_db_query(
                sprintf(
                    "SELECT COUNT(*) AS nb
                     FROM %1\$sdefunt
                     INNER JOIN %1\$semplacement
                         ON defunt.emplacement = emplacement.emplacement
                     WHERE emplacement.nature = %2\$d
                     AND defunt.defunt_nature = ANY(%3\$s)",
                    DB_PREFIXE,
                    $nature_id,
                    $pg_array
                ),
                array('origin' => __METHOD__)
            );
            if ($qres['code'] === 'OK'
                && !empty($qres['result'])
                && intval($qres['result'][0]['nb']) > 0) {
                $this->addToMessage(sprintf(
                    __("Impossible de restreindre les types de défunts autorisés : %d défunt(s) de type(s) \"%s\" existent déjà pour les emplacements de cette nature."),
                    intval($qres['result'][0]['nb']),
                    implode('", "', $excluded_types)
                ));
                $this->correct = false;
            }
        }

        if ($this->correct === false) {
            return false;
        }
    }

    /**
     * Parse une valeur defunt_natures depuis le format tableau PostgreSQL.
     *
     * @param string|null $value  Ex : "{urne}", "{cercueil,zinc}", "", NULL
     * @return array|null  NULL = tous les types autorisés, array = ensemble restreint
     */
    private function parse_defunt_natures($value) {
        if ($value === null || $value === '') {
            return null;
        }
        $raw = trim($value, '{}');
        if ($raw === '') {
            return null;
        }
        return array_map('trim', explode(',', $raw));
    }

    /**
     * Calcule les types de défunts qui passeraient de "autorisé" à "exclu"
     * entre l'ancien et le nouveau paramétrage.
     *
     * @param array|null $old_types  NULL = tous autorisés
     * @param array|null $new_types  NULL = tous autorisés
     * @return array  Types nouvellement exclus (peut être vide)
     */
    private function get_excluded_defunt_types($old_types, $new_types) {
        // Nouveau paramétrage aussi permissif ou plus → aucune exclusion
        if ($new_types === null) {
            return array();
        }
        // Ancien paramétrage : NULL = tous les types étaient autorisés
        // On calcule les exclus par rapport à la liste complète connue
        if ($old_types === null) {
            $all_known_types = array(
                'cercueil', 'cendre', 'zinc', 'urne', 'boite',
                'cercueil_simp', 'cercueil_herm', 'cercueil_partage',
                'reliquaire', 'reliquaire_partage',
                'urne_simple', 'urne_partage', 'non_renseigne',
            );
            return array_values(array_diff($all_known_types, $new_types));
        }
        // Ancien et nouveau définis : types supprimés du set
        return array_values(array_diff($old_types, $new_types));
    }
}
