<?php
/**
 * Ce script permet de définir la classe 'import_specific'.
 *
 * @package openads
 * @version SVN : $Id: import_specific.class.php 6138 2016-03-09 10:53:39Z nhaye $
 */

require_once PATH_OPENMAIRIE."om_import.class.php";

/**
 * Définition de la classe import.
 *
 * Cette classe étend le module d'import du framework. Ce module permet 
 * l'intégration de données dans l'applicatif depuis des fichiers CSV.
 */
class import_specific extends import {

    /**
     *
     */
    var $script_path = "../app/import_specific.php";

    /**
     *
     */
    var $script_extension = ".import_specific.inc.php";

    /**
     * Ligne de travail du tableau en cours de formatage
     */
    var $line;

    /**
     * Table de ligne rejetées à retiournées en csv
     */
    var $rejet = array();

    /**
     * Table de ligne rejetées à retiournées en csv
     */
    var $line_error = array();

    /**
     * Liste des DA contenant chacun une liste de DI
     */
    var $dossier_autorisation;

    /**
     * Affichage de la liste des imports disponibles.
     *
     * @return void
     */
    function display_import_list() {
        //
        echo "\n<div id=\"import-list\">\n";
        // Composition de la liste de liens vers les imports disponibles.
        // En partant de la liste des imports disponibles, on compose une liste
        // d'éléments composés d'une URL, d'un libellé, et de tous les paramètres
        // permettant l'affichage de l'élément comme un élément de liste.
        $list = array();
        foreach ($this->get_import_list() as $key => $value) {
            //
            $list[] = array(
                "href" => $this->script_path."?obj=".$key,
                "title" => $value["title"],
                "class" => "om-prev-icon import-16",
                "id" => "action-import-".$key."-importer",
            );
        }
        //
        $this->f->layout->display_list(
            array(
                "title" => _("choix de l'import"),
                "list" => $list,
            )
        );
        //
        echo "</div>\n";
    }

    /**
     * Affichage du formulaire d'import.
     *
     * @param string $obj Identifiant de l'import.
     *
     * @return void
     */
    function display_import_form($obj) {
        //
        echo "\n<div id=\"form-csv-import\" class=\"formulaire\">\n";
        $this->f->layout->display__form_container__begin(array(
            "action" => $this->script_path."?obj=".$obj,
            "method" => "post",
            "name" => "f2",
        ));
        //
        $champs = array("fic1", "separateur");
        //
        $form = $this->f->get_inst__om_formulaire(array(
            "validation" => 0,
            "maj" => 0,
            "champs" => $champs,
        ));
        //
        $form->setLib("fic1", __("Fichier CSV"));
        $form->setType("fic1", "upload2");
        $form->setTaille("fic1", 64);
        $form->setMax("fic1", 30);
        // Restriction sur le champ d'upload
        $params = array(
            "constraint" => array(
                "size_max" => 8,
                "extension" => ".csv;.txt"
            ),
        );
        $form->setSelect("fic1", $params);
        //
        $form->setLib("separateur", __("Separateur"));
        $form->setType("separateur", "select");
        $separator_list = array(
            0 => array(";", ",", ),
            1 => array("; ".__("(point-virgule)"), ", ".__("(virgule)")),
        );
        $form->setSelect("separateur", $separator_list);
        //
        $form->entete();
        $form->afficher($champs, 0, false, false);
        $form->enpied();
        //
        $this->f->layout->display__form_controls_container__begin(array(
            "controls" => "bottom",
        ));
        $this->f->layout->display__form_input_submit(array(
            "name" => "submit-csv-import",
            "value" => __("Importer"),
            "class" => "boutonFormulaire",
        ));
        // Lien retour
        $this->f->layout->display_lien_retour(array(
            "href" => $this->script_path,
        ));
        $this->f->layout->display__form_controls_container__end();
        //
        $this->f->layout->display__form_container__end();
        echo "</div>\n";
    }

    /**
     * Affichage de l'assistant d'import.
     *
     * @param string $obj Identifiant de l'import.
     *
     * @return void
     */
    function display_import_helper($obj) {
        if ($obj === "ads2007") {
            $this->display_import_helper_ads2007($obj);
        }
        elseif ($obj == 'bible') {
            $this->display_import_helper_bible($obj);
        }
        else {
            parent::display_import_helper($obj);
        }
    }

    /**
     * Affichage de l'assistant d'import.
     *
     * @param string $obj Identifiant de l'import.
     *
     * @return void
     */
    function display_import_helper_ads2007($obj) {
        // Récupération du fichier de paramétrage de l'import
        // XXX Faire un accesseur pour vérifier l'existence du fichier
        include $this->import_list[$obj]["path"];
        //
        if (!isset($fields)) {
            return;
        }
        //
        echo "<fieldset class=\"cadre ui-corner-all ui-widget-content\">\n";
        //
        echo "\t<legend class=\"ui-corner-all ui-widget-content ui-state-active\">";
        echo _("Structure du fichier CSV");
        echo "</legend>\n";
        // Lien vers le téléchargement d'un fichier CSV modèle
        echo "<div>";
        // $this->f->layout->display_link(array(
        //     "href" => $this->script_path."?obj=".$obj."&amp;action=template",
        //     "title" => _("Télécharger le fichier CSV modèle"),
        //     "class" => "om-prev-icon reqmo-16",
        //     "target" => "_blank",
        // ));
        echo "</div>";
        // Affichage des informations sur l'import
        echo "<table ";
        echo " class=\"table table-condensed table-bordered table-striped\" ";
        echo " id=\"structure_csv\">\n";
        //
        echo "<thead>\n";
        echo "<tr>";
        echo "<th>"._("Ordre")."</th>";
        echo "<th>"._("Champ")."</th>";
        echo "<th>"._("Type")."</th>";
        echo "<th>"._("Obligatoire")."</th>";
        echo "<th>"._("Defaut")."</th>";
        echo "<th>"._("Vocabulaire")."</th>";
        echo "</tr>\n";
        echo "</thead>\n";
        //
        $i = 1;
        //
        echo "<tbody>\n";
        foreach ($fields as $key => $field) {
            // Gestion du caractère obligatoire du champ
            (isset($field["require"]) && $field["require"] == true) ?
                $needed = true : $needed = false;
            echo "<tr>";
            // Ordre
            echo "<td><b>".$i."</b></td>";
            // Champ
            echo "<td>".$field["header"]."</td>";
            // Type
            echo "<td>";
            if (isset($field["type"])) {
                switch ($field["type"]) {
                    case 'blob':
                        echo "text";
                        break;
                    case 'string':
                        echo "text";
                        break;
                    default:
                        echo $field["type"];
                        break;
                }
            }
            // Taille
            if (isset($field["len"])) { 
                if (!in_array($field["type"], array("blob", "geom", ))) {
                    echo " (";
                    echo $field["len"];
                    echo ")";
                }
            }
            echo "</td>";
            // Obligatoire si not null et si aucune valeur par défaut
            echo "<td>";
            if ($needed == true && !isset($field["default"])) { 
                echo "Oui";
            }
            echo "</td>";
            // Défaut
            echo "<td>";
            if (isset($field["default"])) { 
                echo "<i>".$field["default"]."</i>";
            }
            echo "</td>";
            // Vocabulaire
            echo "<td>";
            // Clé étrangère
            if (isset($field["foreign_key"])) {
                echo _("Cle etrangere vers").
                    " : <a href=\"".OM_ROUTE_TAB."&obj=".
                    $field["foreign_key"]["table"]."\">";
                echo $field["foreign_key"]["table"].".".$field["foreign_key"]["field"];
                echo "</a>";
                if (isset($field["foreign_key"]["foreign_key_alias"]) 
                    && isset($field["foreign_key"]["foreign_key_alias"]["fields_list"])) {
                    if (count($field["foreign_key"]["foreign_key_alias"]["fields_list"]) > 1) {
                        echo "<br/>=> "._("Valeurs alternatives possibles")." : ";
                    } else {
                        echo "<br/>=> "._("Valeur alternative possible")." : ";
                    }
                    echo implode(
                            ", ",
                            $field["foreign_key"]["foreign_key_alias"]["fields_list"]
                        );
                }
            }
            // Dates et booléens
            $field_info = "";
            if (isset($field["type"])) {
                switch ($field["type"]) {
                    case 'date':
                        $field_info = _("Format")." : '"._("DD/MM/YYYY")."'";
                        break;
                    case 'bool':
                        $field_info = _("Format")." :<br/>";
                        if ($needed == false) {
                            $field_info .= "'' "._("pour état null")."<br/>";
                        }
                        $field_info .= "'t', 'true', '1', 'Oui' "._("pour oui");
                        $field_info .= "<br/>";
                        $field_info .= "'f', 'false', '0', 'Non' "._("pour non");
                        break;
                    default:
                        break;
                }
            }
            echo $field_info;
            echo "</td>";
            //
            echo "</tr>\n";
            $i++;
        }
        //
        echo "</tbody>\n";
        //
        echo "</table>\n";
        //
        echo "</fieldset>\n";
    }

    /**
     * Surcharge pour remplacer  OM_ROUTE_MODULE_IMPORT par '../app/import_specific.php?'.
     *
     * @param string $obj Identifiant de l'import.
     *
     * @return void
     */
    function display_import_helper_bible($obj) {
        // Récupération du fichier de paramétrage de l'import
        // XXX Faire un accesseur pour vérifier l'existence du fichier
        include $this->import_list[$obj]["path"];
        //
        if (isset($zone) && !isset($fields)) {
            return;
        }
        //
        echo "<fieldset class=\"cadre ui-corner-all ui-widget-content\">\n";
        //
        echo "\t<legend class=\"ui-corner-all ui-widget-content ui-state-active\">";
        echo __("Structure du fichier CSV");
        echo "</legend>\n";
        // Lien vers le téléchargement d'un fichier CSV modèle
        echo "<div>";
        $this->f->layout->display_link(array(
            "href" => "../app/import_specific.php?obj=$obj&amp;action=template",
            "title" => __("Télécharger le fichier CSV modèle"),
            "class" => "om-prev-icon reqmo-16",
            "target" => "_blank",
        ));
        echo "</div>";
        // Affichage des informations sur l'import
        echo "<table ";
        echo " class=\"table table-condensed table-bordered table-striped\" ";
        echo " id=\"structure_csv\">\n";
        //
        echo "<thead>\n";
        echo "<tr>";
        echo "<th>".__("Ordre")."</th>";
        echo "<th>".__("Champ")."</th>";
        echo "<th>".__("Type")."</th>";
        echo "<th>".__("Obligatoire")."</th>";
        echo "<th>".__("Defaut")."</th>";
        echo "<th>".__("Vocabulaire")."</th>";
        echo "</tr>\n";
        echo "</thead>\n";
        //
        $i = 1;
        //
        echo "<tbody>\n";
        foreach ($fields as $key => $field) {
            // Gestion du caractère obligatoire du champ
            (isset($field["notnull"]) && $field["notnull"] == true) ?
                $needed = true : $needed = false;
            echo "<tr>";
            // Ordre
            echo "<td><b>".$i."</b></td>";
            // Champ
            echo "<td>".$key."</td>";
            // Type
            echo "<td>";
            if (isset($field["type"])) {
                switch ($field["type"]) {
                    case 'blob':
                        echo "text";
                        break;
                    default:
                        echo $field["type"];
                        break;
                }
            }
            // Taille
            if (isset($field["len"])) {
                if (!in_array($field["type"], array("blob", "geom", ))) {
                    echo " (";
                    echo $field["len"];
                    echo ")";
                }
            }
            echo "</td>";
            // Obligatoire si not null et si aucune valeur par défaut
            echo "<td>";
            if ($needed == true && !isset($field["default"])) {
                echo "Oui";
            }
            echo "</td>";
            // Défaut
            echo "<td>";
            if (isset($field["default"])) {
                echo "<i>".$field["default"]."</i>";
            }
            echo "</td>";
            // Vocabulaire
            echo "<td>";
            // Clé étrangère
            if (isset($field["fkey"])) {
                echo __("Cle etrangere vers")." : <a href=\"".OM_ROUTE_TAB."&obj=".$field["fkey"]["foreign_table_name"]."\">";
                echo $field["fkey"]["foreign_table_name"].".".$field["fkey"]["foreign_column_name"];
                echo "</a>";
                if (isset($field["fkey"]["foreign_key_alias"])
                    && isset($field["fkey"]["foreign_key_alias"]["fields_list"])) {
                    if (count($field["fkey"]["foreign_key_alias"]["fields_list"]) > 1) {
                        echo "<br/>=> ".__("Valeurs alternatives possibles")." : ";
                    } else {
                        echo "<br/>=> ".__("Valeur alternative possible")." : ";
                    }
                    echo implode(", ", $field["fkey"]["foreign_key_alias"]["fields_list"]);
                }
            }
            // Dates et booléens
            $field_info = "";
            if (isset($field["type"])) {
                switch ($field["type"]) {
                    case 'date':
                        $field_info = __("Format")." : '".__("YYYY-MM-DD")."'";
                        break;
                    case 'bool':
                        $field_info = __("Format")." :<br/>";
                        if ($needed == false) {
                            $field_info .= "'' ".__("pour état null")."<br/>";
                        }
                        $field_info .= "'t', 'true', '1' ".__("pour oui");
                        $field_info .= "<br/>";
                        $field_info .= "'f', 'false', '0' ".__("pour non");
                        break;
                    default:
                        break;
                }
            }
            echo $field_info;
            echo "</td>";
            //
            echo "</tr>\n";
            $i++;
        }
        //
        echo "</tbody>\n";
        //
        echo "</table>\n";
        //
        echo "</fieldset>\n";
    }

    /**
     * Traitement d'import.
     *
     * @param string $obj Identifiant de l'import.
     *
     * @todo Modifier cette méthode pour la rendre générique et éventuellement
     *       utilisable depuis d'autres contextes que celui de la vue principale
     *       du module import.
     *
     * @return void
     */
    function treatment_import($obj) {
        if ($obj === "ads2007") {
            $this->treatment_import_ads2007($obj);
        } elseif ($obj === "bible") {
            $this->treatment_import_bible($obj);
        }
        else {
            parent::treatment_import($obj);
        }
    }

    /**
     * [treatment_import_bible description]
     *
     * @param [type] $obj [description]
     *
     * @return [type] [description]
     */
    private function treatment_import_bible($obj) {
        // On vérifie que le formulaire a bien été validé
        if (!isset($_POST['submit-csv-import'])) {
            //
            return false;
        }

        // On récupère les paramètres du formulaire
        $separateur=$_POST['separateur'];

        // On vérifie que le fichier a bien été posté et qu'il n'est pas vide
        if (isset($_POST['fic1']) && $_POST['fic1'] == "") {
            //
            $class = "error";
            $message = __("Vous n'avez pas selectionne de fichier a importer.");
            $this->f->displayMessage($class, $message);
            //
            return false;
        }

        // On enlève le préfixe du fichier temporaire
        $fichier_tmp = str_replace("tmp|", "", $_POST['fic1']);
        // On récupère le chemin vers le fichier
        $path = $this->f->storage->storage->temporary_storage->getPath($fichier_tmp);
        // On vérifie que le fichier peut être récupéré
        if (!file_exists($path)) {
            //
            $class = "error";
            $message = __("Le fichier n'existe pas.");
            $this->f->displayMessage($class, $message);
            //
            return false;
        }

        // Configuration par défaut du fichier de paramétrage de l'import
        //
        $table = "";
        // Clé primaire numérique automatique. Si la table dans laquelle les
        // données vont être importées possède une clé primaire numérique
        // associée à une séquence automatique, il faut positionner le nom du
        // champ de la clé primaire dans la variable $id. Attention il se peut
        // que ce paramètre se chevauche avec le critère OBLIGATOIRE. Si ce
        // champ est défini dans $zone et qu'il est obligatoire et qu'il est
        // en $id, les valeurs du fichier CSV seront ignorées.
        $id = "";
        //
        $verrou = 1; // =0 pas de mise a jour de la base / =1 mise a jour
        //
        $fic_rejet = 1; // =0 pas de fichier pour relance / =1 fichier relance traitement
        //
        $ligne1 = 1; // = 1 : 1ere ligne contient nom des champs / o sinon
        //
        $encodages = array("UTF-8", "ASCII", "Windows-1252", "ISO-8859-15", "ISO-8859-1");

        // Récupération du fichier de paramétrage de l'import
        // XXX Faire un accesseur pour vérifier l'existence du fichier
        include $this->import_list[$obj]["path"];

        // On ouvre le fichier en lecture
        $fichier = fopen($path, "r");

        // Initialisation des variables
        $cpt = array(
            "total" => 0,
            "rejet" => 0,
            "insert" => 0,
            "firstline" => 0,
            "empty" => 0,
        );
        $rejet = "";

        // Boucle sur chaque ligne du fichier
        $lines = array();
        while (!feof($fichier)) {
            // Incrementation du compteur de lignes
            $cpt['total']++;
            // Logger
            $this->f->addToLog(__METHOD__."(): LINE ".$cpt['total'], EXTRA_VERBOSE_MODE);
            // On définit si on se trouve sur la ligne titre
            $firstline = ($cpt['total'] == 1 && $ligne1 == 1 ? true : false);
            // On définit le marqueur correct à true
            $correct = true;
            //
            $valF = array();
            $msg = "";

            // Récupération de la ligne suivante dans le fichier
            $contenu = fgetcsv($fichier, 4096, $separateur);

            //
            $this->f->addToLog(__METHOD__."(): LINE ".$cpt['total']." - contenu = ".print_r($contenu, true), EXTRA_VERBOSE_MODE);
            // Si la ligne a plus d'un champ et que le premier champ n'est pas vide
            if (is_array($contenu) === true && count($contenu) > 1 && $contenu[0] != "") { // enregistrement vide (RC à la fin)
                //
                if ($firstline == true) {
                    //
                    $cpt['firstline']++;
                    // Logger
                    $this->f->addToLog(__METHOD__."(): LINE ".$cpt['total']." - firstline", EXTRA_VERBOSE_MODE);
                } else {
                    // NG
                    if (isset($fields)) {
                        // On boucle sur chaque champ défini dans le fichier
                        // de configuration de l'import pour récupérer la
                        // valeur à importer dans la base pour ce champ
                        foreach ($fields as $key => $field) {
                            //
                            $key_num = array_search($key, array_keys($fields));
                            //
                            if (!isset($contenu[$key_num])) {
                                $valF[$key] = -1;
                                // On rejette l'enregistrement
                                $correct = false;
                                // Raison du rejet à ajouter dans le fichier rejet
                                $msg = __("nombre de colonnes incohérent")." : la colonne ".$key_num." n'existe pas";
                                // Logger
                                $this->f->addToLog(__METHOD__."(): REJET => ".$msg, EXTRA_VERBOSE_MODE);
                            } else {
                                // Suppression des espaces superflus
                                $valF[$key] = trim($contenu[$key_num]);
                                // Traitement de l'encodage
                                $valF[$key] = iconv(mb_detect_encoding($valF[$key], $encodages), "UTF-8", $valF[$key]);
                                // la chaine de texte 'null' représente la valeur null
                                if (strtolower($valF[$key]) === "null") {
                                    $valF[$key] = null;
                                }
                            }

                            // Logger
                            $this->f->addToLog(__METHOD__."(): LINE ".$cpt['total']." - champ '".$key."' = '".$valF[$key]."'", EXTRA_VERBOSE_MODE);

                            // ----------------------------------------------------
                            // Gestion des valeurs par défaut lors de la
                            // transmission d'une valeur vide ou nulle
                            // ----------------------------------------------------
                            // Si le paramétrage est défini correctement et que la
                            // valeur transmise est vide ou nulle
                            if (isset($field["type"]) && isset($field["notnull"])
                                && $valF[$key] !== '0'
                                && (empty($valF[$key]) || is_null($valF[$key]))) {
                                // Si une valeur par défaut est proposée dans la paramétrage
                                if (isset($field["default"])) {
                                    // On affecte la valeur par défaut
                                    $valF[$key] = $field["default"];
                                // Si le champ est de type entier et qu'il n'est pas
                                // obligatoire
                                } elseif ($field["type"] == "int"
                                          && $field["notnull"] == false) {
                                    // On affecte null afin de ne pas initialiser
                                    // un champs entier avec une chaine vide ce qui
                                    // provoquerait une erreur de base de données
                                    $valF[$key] = null;

                                // Si le champ est de type date et qu'il n'est pas
                                // obligatoire
                                } elseif ($field["type"] == "date"
                                          && $field["notnull"] == false) {
                                    // On affecte null afin de ne pas initialiser
                                    // un champs date avec une chaine vide ce qui
                                    // provoquerait une erreur de base de données
                                    $valF[$key] = null;

                                // Si le champ est de type booléen et qu'il n'est pas
                                // obligatoire
                                } elseif ($field["type"] == "bool"
                                          && $field["notnull"] == false) {
                                    // XXX Vérifier pourquoi la valeur null
                                    // provoque une erreur de base de données
                                    $valF[$key] = null;

                                // Si le champ est de type string et qu'il n'est pas
                                // obligatoire et que ce champ est une clé étrangère
                                } elseif ($field["type"] == "string"
                                          && $field["notnull"] == false
                                          && isset($field["fkey"])) {
                                    // On affecte null car une chaine vide serait
                                    // considérait comme une clé primaire de l'autre
                                    // table ce qui provoquerait une erreur de base
                                    //  de données
                                    $valF[$key] = null;

                                // Si le champ est de type geom et qu'il n'est pas
                                // obligatoire
                                } elseif ($field["type"] == "geom"
                                          && $field["notnull"] == false) {
                                    // On enlève le champ de l'enregistrement
                                    unset($valF[$key]);
                                }
                            }

                            // ----------------------------------------------------
                            // Vérification du caractère obligatoire d'un champ
                            // ----------------------------------------------------
                            if (isset($field["notnull"]) && $field["notnull"] == true
                                && (empty($valF[$key]) || is_null($valF[$key])) && $valF[$key] != '0') {
                                // On rejette l'enregistrement
                                $correct = false;
                                // Raison du rejet à ajouter dans le fichier rejet
                                $msg = __("champ obligatoire vide")." : ".$key." = ".$valF[$key];
                                // Logger
                                $this->f->addToLog(__METHOD__."(): REJET => ".$msg, EXTRA_VERBOSE_MODE);
                            }

                            // ----------------------------------------------------
                            // Vérification de la taille des string
                            // ----------------------------------------------------
                            if (isset($field["type"]) && $field["type"] == "string"
                                && mb_strlen($valF[$key]) > $field["len"]) {
                                // On rejette l'enregistrement
                                $correct = false;
                                // Raison du rejet à ajouter dans le fichier rejet
                                $msg = __("valeur trop longue pour le champ")." : ".$key."(".$field["len"].") = ".$valF[$key]." (".mb_strlen($valF[$key]).")";
                                // Logger
                                $this->f->addToLog(__METHOD__."(): REJET => ".$msg, EXTRA_VERBOSE_MODE);
                            }

                            // ----------------------------------------------------
                            // Gestion du critère EXIST
                            // ----------------------------------------------------
                            // Ce critère permet de vérifier si la valeur fournie
                            // existe bien dans la table liée (clé étrangère).
                            // Exemple du paramétrage de ce critère :
                            //   $exist = array(
                            //     "champ1" => 1, // Ce champ est lié et doit exister
                            //     "champ2" => 0, // Ce champ n'est pas lié
                            //   );
                            // Par défaut si le critère n'est pas paramétré, on
                            // considère que le champ n'est pas lié.
                            // Comportement : si la valeur du champ en question
                            // dans le fichier CSV est vide alors on rejette
                            // l'enregistrement
                            // ----------------------------------------------------
                            if (isset($field["fkey"]) && !empty($valF[$key])) {
                                // Logger
                                $this->f->addToLog(__METHOD__."(): LINE ".$cpt['total']." - champ '".$key."' - EXIST", EXTRA_VERBOSE_MODE);
                                // Si le champ recherché est sensé être de type entier et est n'est pas numeric
                                if (isset($field["type"]) && $field["type"] = "int"
                                    && !is_numeric($valF[$key])
                                    && isset($field["fkey"]["foreign_key_alias"])) {
                                    $sql = str_replace("<SEARCH>", $valF[$key], $field["fkey"]["foreign_key_alias"]["query"]);
                                    $res = $this->f->db->getOne($sql);
                                    if (!is_null($res) && !$this->f->isDatabaseError($res, true)) {
                                        $valF[$key] = $res;
                                    } else {
                                        // On rejette l'enregistrement
                                        $correct = false;
                                        // Raison du rejet à ajouter dans le fichier rejet
                                        $msg = __("cle secondaire inexistante")." : ".$key." = ".$valF[$key]." / ";
                                        // Logger
                                        $this->f->addToLog(__METHOD__."(): REJET => ".$msg, EXTRA_VERBOSE_MODE);
                                    }
                                } else {
                                    //
                                    $sql = $field["fkey"]["sql_exist"].$valF[$key];
                                    if (strrpos($field["fkey"]["sql_exist"], "'") === strlen($field["fkey"]["sql_exist"])-strlen("'")) {
                                        $sql .= "'";
                                    }
                                    //
                                    $res = $this->f->db->getOne($sql);
                                    // Logger
                                    $this->f->addToLog(__METHOD__."(): db->getone(\"".$sql."\");", VERBOSE_MODE);
                                    // Si le résultat de la requête ne renvoi aucune valeur ou
                                    // une erreur de base de données alors on rejette l'enregistrement
                                    if (is_null($res) || $this->f->isDatabaseError($res, true)) {
                                        // On rejette l'enregistrement
                                        $correct = false;
                                        // Raison du rejet à ajouter dans le fichier rejet
                                        $msg = __("cle secondaire inexistante")." : ".$key." = ".$valF[$key]." / ";
                                        // Logger
                                        $this->f->addToLog(__METHOD__."(): REJET => ".$msg, EXTRA_VERBOSE_MODE);
                                    }
                                }
                            }
                        }
                    // OG
                    } elseif (isset($zone)) {
                        // On boucle sur chaque champ définit dans le fichier
                        // de configuration de l'import pour récupérer la
                        // valeur à importer dans la base pour ce champ
                        foreach (array_keys($zone) as $champ) {
                            // Logger
                            $this->f->addToLog(__METHOD__."(): LINE ".$cpt['total']." - champ '".$champ."'", EXTRA_VERBOSE_MODE);

                            // ----------------------------------------------------
                            // Gestion du critère DEFAUT
                            // ----------------------------------------------------
                            if ($zone[$champ] == "") { // valeur par defaut
                                //
                                $valF[$champ] = ""; // eviter le not null value
                                //
                                if (!isset($defaut[$champ])) {
                                    $defaut[$champ] = "";
                                }
                                $valF[$champ] = $defaut[$champ];
                            } else {
                                if (isset($contenu[$zone[$champ]])) {
                                    $valF[$champ] = $contenu[$zone[$champ]];
                                } else {
                                    // On rejette l'enregistrement
                                    $correct = false;
                                    // Raison du rejet à ajouter dans le fichier rejet
                                    $msg = __("nombre de colonnes incohérent")." : la colonne ".$champ." n'existe pas dans le fichier";
                                    // Logger
                                    $this->f->addToLog(__METHOD__."(): REJET => ".$msg, EXTRA_VERBOSE_MODE);
                                }
                            }

                            // ----------------------------------------------------
                            // Gestion du critère OBLIGATOIRE
                            // ----------------------------------------------------
                            // Ce critère permet de vérifier, avant de faire une
                            // requête d'insertion, que la valeur fournie est
                            // correcte. Exemple du paramétrage de ce critère :
                            //   $obligatoire = array(
                            //     "champ1" => 1, // Ce champ est obligatoire
                            //     "champ2" => 0, // Ce champ n'est pas obligatoire
                            //   );
                            // Par défaut si le critère n'est pas paramétré, on
                            // considère que le champ n'est pas obligatoire.
                            // Comportement : si la valeur du champ en question
                            // dans le fichier CSV est vide ou null alors on
                            // rejette l'enregistrement.
                            // ----------------------------------------------------
                            if (isset($obligatoire[$champ])
                                && $obligatoire[$champ] == 1
                                && (empty($valF[$champ]) || is_null($valF[$champ]))) {
                                // On rejette l'enregistrement
                                $correct = false;
                                // Raison du rejet à ajouter dans le fichier rejet
                                $msg = __("champ obligatoire vide")." : ".$champ." = ".$valF[$champ];
                                // Logger
                                $this->f->addToLog(__METHOD__."(): REJET => ".$msg, EXTRA_VERBOSE_MODE);
                            } elseif (!isset($obligatoire[$champ])) {
                                // Par défaut on indique que le champ n'est pas obligatoire
                                $obligatoire[$champ] = 0;
                            }

                            // ----------------------------------------------------
                            // Gestion du critère EXIST
                            // ----------------------------------------------------
                            // Ce critère permet de vérifier si la valeur fournie
                            // existe bien dans la table liée (clé étrangère).
                            // Exemple du paramétrage de ce critère :
                            //   $exist = array(
                            //     "champ1" => 1, // Ce champ est lié et doit exister
                            //     "champ2" => 0, // Ce champ n'est pas lié
                            //   );
                            // Par défaut si le critère n'est pas paramétré, on
                            // considère que le champ n'est pas lié.
                            // Comportement : si la valeur du champ en question
                            // dans le fichier CSV est vide alors on rejette
                            // l'enregistrement
                            // ----------------------------------------------------
                            if (isset($exist[$champ])
                                && $exist[$champ] == 1
                                && !empty($valF[$champ])) {
                                // Logger
                                $this->f->addToLog(__METHOD__."(): LINE ".$cpt['total']." - champ '".$champ."' - EXIST", EXTRA_VERBOSE_MODE);
                                //
                                $sql = $sql_exist[$champ].$valF[$champ];
                                if (strrpos($sql_exist[$champ], "'") === strlen($sql_exist[$champ])-strlen("'")) {
                                    $sql .= "'";
                                }
                                //
                                $res = $this->f->db->getOne($sql);
                                // Logger
                                $this->f->addToLog(__METHOD__."(): db->getone(\"".$sql."\");", VERBOSE_MODE);
                                // Si le résultat de la requête ne renvoi aucune valeur ou
                                // une erreur de base de données alors on rejette l'enregistrement
                                if (is_null($res) || $this->f->isDatabaseError($res, true)) {
                                    // On rejette l'enregistrement
                                    $correct = false;
                                    // Raison du rejet à ajouter dans le fichier rejet
                                    $msg = __("cle secondaire inexistante")." : ".$champ." = ".$valF[$champ];
                                    // Logger
                                    $this->f->addToLog(__METHOD__."(): REJET => ".$msg, EXTRA_VERBOSE_MODE);
                                }
                            } elseif (!isset($exist[$champ])) {
                                // Par défaut on indique que le champ n'est pas lié
                                $exist[$champ] = 0;
                            }
                        }
                    }

                    if ($correct == true) {
                        $lines[$cpt['total']] = $valF;
                        $cpt["insert"]++;
                    }
                }
                // Si il y a une erreur sur la ligne alors on constitue un fichier
                // de rejet que l'utilisateur corrigera
                if ($correct == false || $firstline == true) {
                    // On recompose la ligne avec les separateurs
                    $ligne = "";
                    foreach ($fields as $key => $field) {
                        $key_num = array_search($key, array_keys($fields));
                        if (!isset($contenu[$key_num])) {
                            $ligne .= $separateur;
                        } elseif ($field["type"] == "string" or $field["type"] == "blob") {
                            $ligne .= '"'.$contenu[$key_num].'"'.$separateur;
                        } else {
                            $ligne .= $contenu[$key_num].$separateur;
                        }
                    }
                    // On ajoute une colonne erreur sur la premiere ligne
                    if ($firstline == true) {
                        $ligne .= "rejet";
                    } else {
                        $cpt["rejet"]++;
                        $ligne .= '"'.$msg.'"';
                    }
                    // Ajout du caractere de fin de ligne
                    $rejet .= $ligne."\n";
                } else {
                    // Cas de l'import spécifique des bibles, toutes les lignes même
                    // correctes doivent être récupérées dans le fichier de rejet
                    $ligne = "";
                    foreach ($fields as $key => $field) {
                        $key_num = array_search($key, array_keys($fields));
                        if (!isset($contenu[$key_num])) {
                            $ligne .= $separateur;
                        } elseif ($field["type"] == "string" or $field["type"] == "blob") {
                            $ligne .= '"'.$contenu[$key_num].'"'.$separateur;
                        } else {
                            $ligne .= $contenu[$key_num].$separateur;
                        }
                    }
                    $msg = __("Il n'y a pas d'erreur sur cette ligne");
                    $ligne .= '"'.$msg.'"';
                    $rejet .= $ligne."\n";
                }
            } else {
                $cpt["empty"]++;
            }
        }

        // Fermeture du fichier
        fclose($fichier);

        /**
         * Affichage du message de résultat de l'import
         */
        // Composition du message résultat
        $message = __("Resultat de l'import")."<br/>";
        $message .= $cpt["total"]." ".__("ligne(s) dans le fichier dont :")."<br/>";
        $message .= " - ".$cpt["firstline"]." ".__("ligne(s) d'entete")."<br/>";
        $message .= " - ".$cpt["insert"]." ".__("ligne(s) correcte(s)")."<br/>";
        $message .= " - ".$cpt["rejet"]." ".__("ligne(s) rejetee(s)")."<br/>";
        $message .= " - ".$cpt["empty"]." ".__("ligne(s) vide(s)")."<br/>";
        //
        if ($fic_rejet == 1 && $cpt["rejet"] != 0) {
            //
            $class = "error";
            // Composition du fichier de rejet
            $rejet = substr($rejet, 0, strlen($rejet) - 1);
            $metadata = array(
                "filename" => "import_".$obj."_".date("Ymd_Gis")."_rejet.csv",
                "size" => strlen($rejet),
                "mimetype" => "application/vnd.ms-excel",
            );
            $uid = $this->f->storage->create_temporary($rejet, $metadata);
            // Enclenchement de la tamporisation de sortie
            ob_start();
            //
            $this->f->layout->display_link(array(
                "href" => OM_ROUTE_FORM."&snippet=file&amp;uid=".$uid."&amp;mode=temporary",
                "title" => __("Télécharger le fichier CSV rejet"),
                "class" => "om-prev-icon reqmo-16",
                "target" => "_blank",
            ));
            // Affecte le contenu courant du tampon de sortie au message puis l'efface
            $message .= ob_get_clean();
        } else {
            //
            $class = "ok";
        }
        //
        $this->f->displayMessage($class, $message);

        // L'import ne s'applique que s'il n'y a aucun rejet
        if ($cpt["rejet"] === 0) {
            // Désactivation l'auto-commit
            $this->f->db->autoCommit(false);
            // Suppression de toutes les bibles existantes
            $query = sprintf('
                DELETE
                FROM %1$s%2$s
                ',
                DB_PREFIXE,
                $obj
            );
            $res = $this->f->db->query($query);
            $this->addToLog(__METHOD__."(): db->query(\"".$query."\");", VERBOSE_MODE);
            if ($this->f->isDatabaseError($res, true)) {
                $this->f->db->rollback();
                $error_msg = sprintf(
                    "%s %s",
                    __("La suppression de toutes les bibles a échouée."),
                    __("Veuillez contacter votre administrateur.")
                );
                $this->f->displayMessage('error', $error_msg);
                $this->f->addToLog(__METHOD__."(): ".$error_msg, DEBUG_MODE);
                return false;
            }

            // Ajout de toutes les lignes du fichier
            $error_add  = false;
            foreach ($lines as $key => $line) {
                $codes = explode("},", $line['codes']);
                foreach ($codes as $code) {
                    $error_check_ids  = false;
                    $code = str_replace(array("{", "}"), "", $code);
                    $ids = array_map('trim', explode(",", $code));
                    $bible = $this->f->get_inst__om_dbform(array(
                        "obj" => $obj,
                        "idx" => "]",
                    ));
                    // Valeurs de la bible
                    $valF = array();
                    foreach($bible->champs as $champ) {
                        $valF[$champ] = '';
                    }
                    $valF['libelle'] = $line['libelle'];
                    $valF['contenu'] = $line['contenu'];
                    $valF['evenement'] = $ids[0];
                    $valF['complement'] = $ids[1];
                    $valF['automatique'] = $ids[2];
                    $valF['dossier_autorisation_type'] = $ids[3];
                    $valF['om_collectivite'] = $ids[4];
                    $check_evenement = $this->check_id_exists('evenement', $valF['evenement']);
                    if ($check_evenement === false) {
                        $error_check_ids = true;
                        $error_msg = sprintf(__("L'événement dont l'identifiant est %s n'existe pas."), $valF['evenement']);
                        $this->f->displayMessage('error', $error_msg);
                        $this->f->addToLog(__METHOD__."(): ".$error_msg, DEBUG_MODE);
                    }
                    $check_dossier_autorisation_type = $this->check_id_exists('dossier_autorisation_type', $valF['dossier_autorisation_type']);
                    if ($check_dossier_autorisation_type === false) {
                        $error_check_ids = true;
                        $error_msg = sprintf(__("Le type de dossier d'autorisation dont l'identifiant est %s n'existe pas."), $valF['dossier_autorisation_type']);
                        $this->f->displayMessage('error', $error_msg);
                        $this->f->addToLog(__METHOD__."(): ".$error_msg, DEBUG_MODE);
                    }
                    $check_om_collectivite = $this->check_id_exists('om_collectivite', $valF['om_collectivite']);
                    if ($check_om_collectivite === false) {
                        $error_check_ids = true;
                        $error_msg = sprintf(__("La collectivité dont l'identifiant est %s n'existe pas."), $valF['om_collectivite']);
                        $this->f->displayMessage('error', $error_msg);
                        $this->f->addToLog(__METHOD__."(): ".$error_msg, DEBUG_MODE);
                    }
                    if ($error_check_ids === false) {
                        $ajouter = $bible->ajouter($valF);
                        if ($ajouter === false) {
                            $error_add = true;
                            $error_msg = sprintf(
                                "%s %s",
                                sprintf(__("Erreur lors de l'ajout de la bible dont les valeurs sont : %s."), print_r($valF, true)),
                                __("Veuillez contacter votre administrateur.")
                            );
                            $this->f->displayMessage('error', $error_msg);
                            $this->f->addToLog(__METHOD__."(): ".$error_msg, DEBUG_MODE);
                            if ($bible->msg !== null && $bible->msg !== '') {
                                $this->f->displayMessage('error', $bible->msg);
                            }
                        } else {
                            $valid_msg = sprintf(__("Ajout de la bible dont les valeurs sont %s."), print_r($valF, true));
                            $this->f->addToLog(__METHOD__."(): ".$valid_msg, VERBOSE_MODE);
                        }
                    }
                }
            }
            // On annule toute la transaction dès la première erreur d'ajout
            if ($error_add === true) {
                $this->f->db->rollback();
                return false;
            }

            // Vérification du verrou
            if ($verrou == 1) {
                // Commit de la transaction
                $this->f->db->commit();
            } else {
                $this->f->db->rollback();
                $error_msg = sprintf(
                    "%s %s",
                    __("Le traitement d'import ne possède pas la permission de mettre à jour la base de données."),
                    __("Veuillez contacter votre administrateur.")
                );
                $this->f->displayMessage('error', $error_msg);
                $this->f->addToLog(__METHOD__."(): ".$error_msg, DEBUG_MODE);
                return false;
            }
        }
    }

    /**
     * Vérifie que l'enregistrement existe.
     *
     * @return mixed
     */
    function check_id_exists($table, $idx) {
        if ($table === null || $table === '') {
            return false;
        }
        if ($idx === null || $idx === '' || $idx === 'NULL') {
            return null;
        }
        $enr = $this->f->get_inst__om_dbform(array(
            "obj" => $table,
            "idx" => $idx,
        ));
        if ($enr->getVal($enr->clePrimaire) !== null && $enr->getVal($enr->clePrimaire) !== '') {
            return true;
        }
        return false;
    }

    /**
     * Traitement d'import pour csv provenant d'ads2007
     *
     * @param string $obj Identifiant de l'import.
     *
     * @todo Modifier cette méthode pour la rendre générique et éventuellement
     *       utilisable depuis d'autres contextes que celui de la vue principale
     *       du module import.
     *
     * @return boolean false si erreur
     */
    function treatment_import_ads2007($obj) {
        
        // On vérifie que le formulaire a bien été validé
        if (!isset($_POST['submit-csv-import'])) {
            //
            return false;
        }

        // On récupère les paramètres du formulaire
        $separateur=$_POST['separateur'];

        // On vérifie que le fichier a bien été posté et qu'il n'est pas vide
        if (isset($_POST['fic1']) && $_POST['fic1'] == "") {
            //
            $class = "error";
            $message = _("Vous n'avez pas selectionne de fichier a importer.");
            $this->f->displayMessage($class, $message);
            //
            return false;
        }

        // On enlève le préfixe du fichier temporaire
        $fichier_tmp = str_replace("tmp|", "", $_POST['fic1']);
        // On récupère le chemin vers le fichier
        $path = $this->f->storage->storage->temporary_storage->getPath($fichier_tmp);
        // On vérifie que le fichier peut être récupéré
        if (!file_exists($path)) {
            //
            $class = "error";
            $message = _("Le fichier n'existe pas.");
            $this->f->displayMessage($class, $message);
            //
            return false;
        }

        // Configuration par défaut du fichier de paramétrage de l'import
        //
        $table = "";
        // Clé primaire numérique automatique. Si la table dans laquelle les
        // données vont être importées possède une clé primaire numérique 
        // associée à une séquence automatique, il faut positionner le nom du
        // champ de la clé primaire dans la variable $id. Attention il se peut 
        // que ce paramètre se chevauche avec le critère OBLIGATOIRE. Si ce
        // champ est défini dans $zone et qu'il est obligatoire et qu'il est
        // en $id, les valeurs du fichier CSV seront ignorées.
        $id = "";
        // 
        $verrou = 1; // =0 pas de mise a jour de la base / =1 mise a jour
        //
        $fic_rejet = 1; // =0 pas de fichier pour relance / =1 fichier relance traitement
        //
        $ligne1 = 1; // = 1 : 1ere ligne contient nom des champs / o sinon

        // Récupération du fichier de paramétrage de l'import
        // XXX Faire un accesseur pour vérifier l'existence du fichier
        include $this->import_list[$obj]["path"];

        $this->column = $fields;

        $header = array();
        foreach ($fields as $key => $value) {
            $header[] = $fields[$key]["header"];
        }

        // On ouvre le fichier en lecture
        $fichier = fopen($path, "r");

        // Initialisation des variables
        $cpt = array(
            "total" => 0,
            "rejet" => 0,
            "insert" => 0,
            "error" => 0,
            "firstline" => 0,
            "empty" => 0,
        );

        // Boucle sur chaque ligne du fichier
        while (!feof($fichier)) {
            // Incrementation du compteur de lignes
            $cpt['total']++;
            // Logger
            $this->f->addToLog(__METHOD__."(): LINE ".$cpt['total'], EXTRA_VERBOSE_MODE);
            // On définit si on se trouve sur la ligne titre
            $firstline = ($cpt['total'] == 1 && $ligne1 == 1 ? true : false);
            //
            $valF = array();
            $this->line_error = array();

            // Récupération de la ligne suivante dans le fichier
            $contenu = fgetcsv($fichier, 4096, $separateur);
            //
            $this->f->addToLog(
                __METHOD__."(): LINE ".$cpt['total']." - contenu = ".print_r($contenu, true),
                EXTRA_VERBOSE_MODE
            );
            // Si la ligne un champ ou moins et qu'il est vide on passe a la ligne
            // suivante 
            if ($contenu === false
                || (is_array($contenu) === true && count($contenu) == 1 && $contenu[0] == "")) { // enregistrement vide
                $cpt["empty"]++;
                continue;
            }

            // Suppression des espaces superflus
            $contenu = array_map("trim", $contenu);
            array_walk(
                $contenu,
                function (&$entry) {
                    $entry = iconv("ISO-8859-15", "UTF-8", $entry);
                }
            );
            // Suppression des colonnes de trop
            while(count($contenu) > 61) {
                unset($contenu[count($contenu)-1]);
            }

            // Si pas le bon nombre de colonnes on en ajoute pour ajouter le message
            // d'erreur
            if(count($contenu) != 61) {
                // Ajout des colonnes
                while(count($contenu) != 61) {
                    $contenu[] = "";
                }
                $contenu[] = _("Le format de la ligne n'est pas valide");
                $this->rejet[] = $contenu;
                $cpt["rejet"]++;
                continue;
            }

            // Si la première ligne est entête
            if ($contenu[0] === "Type") {
                //
                $cpt['firstline']++;
                // Logger
                $this->f->addToLog(
                    __METHOD__."(): LINE ".$cpt['total']." - firstline",
                    EXTRA_VERBOSE_MODE
                );
                continue;
            }

            $contenu = array_combine(array_keys($this->column), $contenu);

            // Définition de la variable de travail
            $this->line = $contenu;

            // Traitement des lignes du csv

            // Si une date de decision est définie sans nature de decision alors 
            // le dossier est implicitement accordé
            if(!empty($this->line["date_de_decision"]) and 
                empty($this->line["nature_decision"])) {

                $this->line["nature_decision"] = "Favorable";
            }
            // vérification de clôture du DI
            $this->is_cloture();

            // définision de l'avis en fonction des date saisie
            $this->set_avis_decision_from_date($this->line);

            // reformatage du code INSEE
            $this->format_code_insee();

            // Pour chaque champs vérifications définie dans la conf
            foreach ( $this->line as $key => $value ) {

                $this->line[$key] = trim($this->line[$key]);
                // Vérification du format des valeurs selon leurs type
                if($this->check_type($key) === false) {
                    $this->line_error[] = sprintf(
                        _("La colonne %s ne correspond pas au format requis"),
                        $this->column[$key]["header"]
                    );
                }
                // Mise en correspondance des valeurs de la base
                $this->set_linked_value($key);
                // Vérification de l'existance des clés etrangères
                if($this->get_foreign_key_id($key) === false) {
                    $this->line_error[] = sprintf(
                        _("Aucune correspondance pour la colonne %s"),
                        $this->column[$key]["header"]
                    );
                }

                // Vérification des champs obligatoires
                if($this->check_required($key) === false) {
                    $this->line_error[] = sprintf(
                        _("La colonne %s est obligatoire"),
                        $this->column[$key]["header"]
                    );
                }

            }

            // Vérification des numéros de dossier
            $regex_di = "/^[0-9]{3}[0-9]{3}[0-9]{2}[A-Z0][0-9]{4}(-(P|M|T|DOC|DAACT|PRO|ANNUL)[0-9]{1,2})?/i";
            if(! preg_match($regex_di, $this->line["numero"], $matches)) {
                $this->f->addToLog(
                    __METHOD__."(): LINE  Failed to match regex on DI numero: '" . $this->line["numero"] . "'",
                    EXTRA_VERBOSE_MODE
                );
                $this->line_error[] = _("Numéro de dossier instruction invalide");
            }
            $regex_da = "/^[0-9]{3}[0-9]{3}[0-9]{2}[A-Z0][0-9]{4}$/i";
            if(! empty($this->line["initial"]) && ! preg_match($regex_da, $this->line["initial"], $matches)) {
                $this->f->addToLog(
                    __METHOD__."(): LINE  Failed to match regex on DA numero: '" . $this->line["initial"] . "'",
                    EXTRA_VERBOSE_MODE
                );
                $this->line_error[] = _("Numéro de dossier autorisation invalide");
            }

            // on continue seulement si les numéros de dossier sont valides
            if(empty($this->line_error)) {

                // Définition de la collectivité du dossier
                $this->set_collectivite();

                // Formatage (explode) de l'adresse du demandeur
                if($this->explode_address($this->line["adresse_demandeur"]) === false) {
                    $this->line_error[] = 
                        _("Le format de l'adresse demandeur n'est pas correct");
                } else {
                    $this->line["adresse_demandeur"] = 
                    $this->explode_address($this->line["adresse_demandeur"]);
                }
                // Formatage (explode) de l'adresse du terrain
                if($this->explode_address($this->line["terrain"]) === false) {
                    $this->line_error[] = 
                        _("Le format de la localisation du dossier n'est pas correct");
                } else {
                    $this->line["terrain"] = 
                    $this->explode_address($this->line["terrain"]);
                }
                // Formatage des références cadastrales
                if($this->parse_reference_cadastrale("references_cadastrales") === false) {
                    $this->line_error[] = 
                        _("Le format des references cadastrale n'est pas correct");
                }
                // Définition du numéro de version du DI
                if(! $this->set_version()) {
                    $this->line_error[] =
                        _("Numéro de dossier invalide");
                }
                // Définition du prefixe des numéro DI et DA
                $this->set_prefix_di();
            }

            if(!empty($this->line_error)) {
                $contenu[] = implode("\n", $this->line_error);
                $this->rejet[] = $contenu;
                $cpt["rejet"]++;
                continue;
            } else {
                $this->line['original_line'] = $contenu;
            }

            // Ajout de la ligne traitée au tableau final
            $this->dossier_autorisation[$this->line["initial"]][$this->line["version"]] = array(
                'data' => $this->line,
                'errors' => $this->line_error
            );
        }

        if(!empty($this->dossier_autorisation)) {

            // Vérification de l'intégrité de l'instruction
            foreach ($this->dossier_autorisation as $da_id => $list_di) {

                // récupère la liste des DI qui ne sont pas en erreur
                $list_of_valid_DI = array();
                foreach ($list_di as $version => $data_di) {

                    // pas d'erreur préalable
                    if (empty($data_di['errors'])) {

                        // ajout du DI à la liste des DI valides du DA
                        $list_of_valid_DI[$version] = $data_di['data'];
                    }
                }

                // si aucun DI est valide, on ne traite pas ce DA
                if (empty($list_of_valid_DI)) {
                    continue;
                }

                $this->f->db->autoCommit(false);
                $commit = true;

                if($this->is_da_exist($da_id) != true) {
                    if($this->add_dossier_autorisation($da_id, $list_of_valid_DI) != true) {
                        $cpt["error"]++;
                        $this->f->db->rollback();
                        continue;
                    }
                }

                // On boucle maintenant sur les DI valides du DA
                foreach ($list_of_valid_DI as $version => $data_di) {

                    // Définition du suffixe des numéro DI
                    $code = $this->get_dossier_instruction_type_code(
                        $version,
                        $list_of_valid_DI
                    );

                    $data_di["dossier_instruction_type"] = 
                        $this->get_dossier_instruction_type($data_di["type"], $code);

                    // Récupération du statut de l'option suffixe pour ce type de DI
                    $suffixe = $this->get_dossier_instruction_type_suffixe($data_di["dossier_instruction_type"]);

                    if($data_di["dossier_instruction_type"] === null) {
                        $cpt["rejet"]++;
                        $data_di['original_line'][] = sprintf(
                            _("Aucun type de dossier d'instruction ne correspond (type = %s, code = %s)"),
                            $data_di["type"],
                            $code
                        );
                        $this->rejet[] = $data_di['original_line'];
                        $commit = false;
                        continue;
                    }

                    // Si le suffixe est activé pour le type de DI du dossier importé, on
                    // l'ajoute à la fin du numéro de dossier
                    if ($suffixe === 't'){
                        $data_di["numero"] .= $code.$version;
                    }

                    // si le DI est un modificatif et que le DI initial n'est pas importé
                    if ($version !== 0 &&
                        (! isset($list_of_valid_DI[0]) || $list_of_valid_DI[0]['numero'] != $da_id)
                    ) {
                        $di_initial_type = $this->get_dossier_instruction_type($data_di["type"], 'P');
                        if($di_initial_type === null) {
                            $cpt["rejet"]++;
                            $data_di['original_line'][] = sprintf(
                                _("Aucun type de dossier d'instruction ne correspond (type = %s, code = %s)"),
                                $data_di["type"],
                                'P'
                            );
                            $this->rejet[] = $data_di['original_line'];
                            $commit = false;
                            continue;
                        }
                        $di_initial_suffixe = $this->get_dossier_instruction_type_suffixe($di_initial_type);
                        $di_initial_num = $da_id.($di_initial_suffixe === 't' ? 'P0' : '');

                        // récupère le DI initial
                        $sql = sprintf("
                            SELECT
                                dossier
                            FROM
                                ".DB_PREFIXE."dossier
                            WHERE
                                dossier = '%s'",
                                $di_initial_num
                        );
                        $this->f->addToLog(__METHOD__."(): SQL: $sql", DEBUG_MODE);
                        $dossier_initial = $this->f->db->getOne($sql);
                        $this->f->isDatabaseError($dossier_initial);

                        // si le DI initial n'existe pas déjà en base
                        if (empty($dossier_initial)) {

                            // on renvoi une erreur
                            $cpt["rejet"]++;
                            $data_di['original_line'][] = sprintf(
                                _("Aucun dossier d'instruction initial correspondant (initial = %s)"),
                                $di_initial_num
                            );
                            $this->rejet[] = $data_di['original_line'];
                            $commit = false;
                            continue;
                        }
                    }

                    // Si initial on récupère le numéro de dossier si il existe
                    $di_exist = $this->get_di_id_if_exist($data_di);
                    if($di_exist === false) {
                        $data_di["dossier_exist"] = false;
                    } else {
                        $data_di["dossier_exist"] = true;
                        // On remplace le numéro de dossier par celui déjà en base
                        $data_di["numero"] = $di_exist;
                    }

                    if($this->add_dossier_instruction($data_di) === false) {
                        $cpt["error"]++;
                        $commit = false;
                        continue;
                    }

                    if($this->add_donnees_techniques($data_di) === false) {
                        $cpt["error"]++;
                        $commit = false;
                        continue;
                    }

                    if($data_di["dossier_exist"] == false) {
                        if($this->add_demandeur($data_di) === false) {
                            $cpt["error"]++;
                            $commit = false;
                            continue;
                        }
                    }

                    $cpt["insert"]++;
                }

                if ($commit) {
                    $this->update_dossier_autorisation($da_id);
                    $this->f->db->commit(); // Validation des transactions
                }
                else {
                    $this->f->addToLog(__METHOD__."(): ROLLING BACK (DA: $da_id)", DEBUG_MODE);
                    $this->f->db->rollback();
                }
            }
        }
        

        // Fermeture du fichier
        fclose($fichier);

        /**
         * Affichage du message de résultat de l'import
         */
        // Composition du message résultat
        $message = _("Resultat de l'import")."<br/>";
        $message .= $cpt["total"]." "._("ligne(s) dans le fichier dont :")."<br/>";
        $message .= " - ".$cpt["firstline"]." "._("ligne(s) d'entete")."<br/>";
        $message .= " - ".$cpt["insert"]." "._("ligne(s) importee(s)")."<br/>";
        $message .= " - ".$cpt["error"]." "._("ligne(s) en erreur")."<br/>";
        $message .= " - ".$cpt["rejet"]." "._("ligne(s) rejetee(s)")."<br/>";
        $message .= " - ".$cpt["empty"]." "._("ligne(s) vide(s)")."<br/>";
        //
        if($cpt["error"] > 0 ) {
            //
            $class = "error";
            $message .= 
                _("Erreur de base de donnees. Contactez votre administrateur.")."<br/>";

        }
        if ($fic_rejet == 1 && $cpt["rejet"] != 0) {
            //
            $class = "error";
            $header[] = "Erreur (s)";
            $header = array_map(array($this, "encodeFunc"), $header);
            $rejet = implode(";", $header)."\n";
            // Composition du fichier de rejet
            foreach ($this->rejet as $line_rejet) {
                $line_rejet = array_map(array($this, "encodeFunc"), $line_rejet);
                $rejet .= implode(";", $line_rejet)."\n";
            }
            $rejet = iconv("UTF-8", "ISO-8859-15", $rejet);
            $metadata = array(
                "filename" => "import_".$obj."_".date("Ymd_Gis")."_rejet.csv",
                "size" => strlen($rejet),
                "mimetype" => "application/vnd.ms-excel",
            );
            $uid = $this->f->storage->create_temporary($rejet, $metadata);
            // Enclenchement de la tamporisation de sortie
            ob_start();
            //
            $this->f->layout->display_link(
                array(
                    "href" => "../app/index.php?module=form&snippet=file&uid=".$uid."&amp;mode=temporary",
                    "title" => _("Télécharger le fichier CSV rejet"),
                    "class" => "om-prev-icon reqmo-16",
                    "target" => "_blank",
                )
            );
            // Affecte le contenu courant du tampon de sortie au message puis l'efface
            $message .= ob_get_clean();
        } else {
            //
            $class = "ok";
        }
        //
        $this->f->displayMessage($class, $message);
    }

    /**
     * Formate le code insee fourni pas l'export ads2007.
     */
    function format_code_insee() {
        if(!isset($this->line["insee"]) or $this->line["insee"] == "") {
            return false;
        }
        $this->line["insee"] = 
            str_pad(
                strval(
                    intval($this->line["insee"])
                    ),
                5,
                0,
                STR_PAD_LEFT
            );
    }

    /**
     * Permet d'échapper des quote autour de chaque valeur.
     *
     * @param string $value chaine à enquoter
     *
     * @return string m€me chaine avec quotes
     */
    function encodeFunc($value) {
        return "\"".$value."\"";
    }

    /**
     * [is_da_exist description]
     *
     * @param [type] $id [description]
     *
     * @return boolean [description]
     */
    function is_da_exist($id) {
        $sql = "SELECT count(*) FROM ".
            DB_PREFIXE."dossier_autorisation WHERE dossier_autorisation='".$id."'";

        $count = $this->f->db->getone($sql);

        $this->f->isDatabaseError($id);

        if($count != "0") {
            return true;
        }

        return false;

    }

    /**
     * Vérifie si le di existe en BDD, si il existe on retourne le numéro sinon false.
     *
     * @param string $id identifiant du dossier
     *
     * @return mixed numéro de dossier si existe false sinon
     */
    function get_di_id_if_exist($data_di) {

        // Création de la requête en fonction du numéro de version du dossier
        $sql = "SELECT dossier FROM ".DB_PREFIXE."dossier WHERE ";
        if($data_di['version'] == 0) {
            $sql .= "dossier_autorisation='".$data_di['initial']."' AND version = ".$data_di['version'];
        } else {
            $sql .= "dossier = '".$data_di['numero']."'";
        }
        $dossier = $this->f->db->getOne($sql);
        $this->f->isDatabaseError($dossier);

        // On retourne le numéro de dossier ou false
        if($dossier != null) {
            return $dossier;
        }
        return false;

    }



    /**
     * Vérifie le contenu en fonction du paramétrage
     *
     * @param integer $key clé de la colonne
     * 
     * @return string message d'erreur ou chaine vide
     */
    function check_required($key) {
        if($this->column[$key]["require"] === true and $this->line[$key] =="") {
            return false;
        }
        return true;
    }

    /**
     * Vérifie le contenu en fonction du paramétrage
     *
     * @param integer $key clé de la colonne
     *
     * @return string message d'erreur ou chaine vide
     */
    function check_type($key) {
        if($this->line[$key] === "") {
            return true;
        }
        $regex = '';
        switch ($this->column[$key]["type"]) {

            case 'integer':
                $this->line[$key] = str_replace(' ', '', $this->line[$key]);
                $regex = '/^\d*$/';
                break;
            case 'float':
                $this->line[$key] = str_replace(' ', '', $this->line[$key]);
                $regex = '/^(\d*[,|.])?\d*$/';
                break;
            case 'boolean':
                $regex = '/^(Oui|Non)$/i';
                break;
            case 'date':
                $regex = '/^\d{2}\/\d{2}\/\d{4}$/';
                break;
            default:
                $regex = '/^.*$/m';
                break;
        }
        if(preg_match ($regex, $this->line[$key])) {
            return true;
        }
        return false;
    }

    /**
     * Vérifie si une date de clôture ou une decision est présente.
     */
    function is_cloture() {
        if( 
            empty($this->line["date_accord_tacite"]) and
            empty($this->line["date_de_rejet_tacite"]) and
            empty($this->line["date_de_refus_tacite"]) and
            (empty($this->line["date_de_decision"]) or
            empty($this->line["nature_decision"]))
            ) {

            $this->line_error[] = _("Ce dossier n'est pas cloture");
        }
    }

    /**
     * Positionne l'avis en fonction des dates de décision.
     */
    function set_avis_decision_from_date() {
        if(!isset($this->line["date_accord_tacite"]) or 
            !isset($this->line["date_de_rejet_tacite"]) or
            !isset($this->line["date_de_refus_tacite"])) {
            return false;
        }
        $this->line["date_accord_tacite"] = trim($this->line["date_accord_tacite"]);
        $this->line["date_de_rejet_tacite"] = trim($this->line["date_de_rejet_tacite"]);
        $this->line["date_de_refus_tacite"] = trim($this->line["date_de_refus_tacite"]);

        if(!empty($this->line["date_accord_tacite"])) {
            $this->line["nature_decision"] = "Accord Tacite";
            $this->line["date_de_decision"] = $this->line["date_accord_tacite"];
        }
        if(!empty($this->line["date_de_rejet_tacite"])) {
            $this->line["nature_decision"] = "Rejet tacite";
            $this->line["date_de_decision"] = $this->line["date_de_rejet_tacite"];
        }
        if(!empty($this->line["date_de_refus_tacite"])) {
            $this->line["nature_decision"] = "Refus tacite";
            $this->line["date_de_decision"] = $this->line["date_de_refus_tacite"];
        }
    }

    /**
     * Récupération des clés étrangères.
     *
     * @param integer $key clé de la colonne
     *
     * @return string message d'erreur ou chaine vide
     */
    function get_foreign_key_id($key) {
        if(!isset($this->column[$key]["foreign_key"]) or $this->line[$key] ==="") {
            return true;
        }

        // Récupération de la clé étrangère avec la requète sql définie dans le
        // paramétrage du champ
        $sql = str_replace(
                '<value>',
                $this->f->db->escapeSimple($this->line[$key]),
                $this->column[$key]["foreign_key"]["sql"]
            );
        $id = $this->f->db->getOne($sql);

        $this->f->isDatabaseError($id);

        // si on trouve une valeur on remplace dans le tableau
        if ($id != "") {
            $this->line[$key] = $id;
            return true;
        }
        return false;
    }

    /**
     * Méthode de substition de valeurs du csv avec du paramétrage de la base.
     *
     * @param integer $key clé de la colonne
     */
    function set_linked_value($key) {
        if(isset($this->column[$key]["link"]) and
            $this->line[$key] != "" and
            array_key_exists($this->line[$key], $this->column[$key]["link"])) {

            $this->line[$key] = $this->column[$key]["link"][$this->line[$key]];
        }
    }


    /**
     * Formate les references cadastrale.
     *
     * @param string $key clé de la colonne
     *
     * @return string vide
     */
    function parse_reference_cadastrale($key) {
        if($this->line[$key] == "") {
            return true;
        }
        $regex = "/^(\d{0,3})?-?(\D{1,2})-(\d{0,4})\w?$/i";
        
        // Les ref sont sepparées par une virgule
        $reference = explode(',', $this->line[$key]);
        $ref_format = array();

        foreach ($reference as $value) {
            if(trim($value) == "") {
                continue;
            }
            $array_ref = array();

            // Pour chaque ref on vérifie le format
            if(!preg_match($regex, trim($value), $array_ref)) {
                
                return false;
            }
            // Et on les format pour openads
            $ref_format[] = sprintf(
                "%s%s%s",
                str_pad($array_ref[1], 3, "0", STR_PAD_LEFT),
                $array_ref[2],
                str_pad($array_ref[3], 4, "0", STR_PAD_LEFT)
                );
        }
        $this->line[$key] = implode(";", $ref_format);
        return true;
    }

    /**
     * Décompose une adresse postale complète en éléments distincts
     *
     * @param string $adresse_complete Adresse complète
     * 
     * @return array Adresse triée
     */
    function explode_address($adresse_complete) { 
        /**
         * Le script procède comme suit :
         *
         * - on supprime le pays
         * - Ã  chaque extraction on supprime les espaces en début et fin de chaîne
         * - on récupère le numéro puis la ville puis le code postal
         * - on récupère la voie qui, si trop longue, est scindée en complément(s)
         */
        // Préparation du tableau de retour
        $adresse_triee = array(
            "numero" => "",
            "voie" => "",
            "complement1" => "",
            "complement2" => "",
            "cp" => "",
            "ville" => "",
        );
        // Suppression du pays
        $adresse_complete = preg_replace('/france/i', '', $adresse_complete);
        // Suppression des espaces superflus
        $adresse_complete = trim($adresse_complete);
        // Récupération du numéro : NN(-NN)
        $matches = array();
        // Récupération de la ville
        $matches = array();
        // Si succès
        if (preg_match('/[\D\-\s]*(?:\d)*$/i', $adresse_complete, $matches)) {
            $ville = $matches[0];
            // Suppression des espaces superflus
            $ville = trim($ville);
            $adresse_triee['ville'] = $ville;
            // Suppression du numéro dans l'adresse complète
            $adresse_complete = str_replace($ville, '', $adresse_complete);
            // Suppression des espaces superflus
            $adresse_complete = trim($adresse_complete);
        }
        // Récupération du code postal
        $matches = array();
        // Si succès
        if (preg_match('/[0-9]{5}$/', $adresse_complete, $matches)) {
            $cp = $matches[0];
            $adresse_triee['cp'] = $cp;
            // Suppression du numéro dans l'adresse complète
            $adresse_complete = str_replace($cp, '', $adresse_complete);
            // Suppression des espaces superflus
            $adresse_complete = trim($adresse_complete);
        }
        // Si succès
        if (preg_match('/^\d+(?:\s?[,-]?\s?\d{0,4})?/', $adresse_complete, $matches)) {
            $numero = $matches[0];
            // Suppression des espaces superflus
            $numero = str_replace(' ','',$numero);
            $adresse_triee['numero'] = $numero;
            // Suppression du numéro dans l'adresse complète
            $adresse_complete = str_replace($numero, '', $adresse_complete);
            // Suppression de la virgule qui suit le numéro
            $adresse_complete = preg_replace('/^\s*,+/', '', $adresse_complete);
            // Suppression des espaces superflus
            $adresse_complete = trim($adresse_complete);
        }
        // Récupération de la voie en la divisant en deux voire trois parties
        // si la chaîne de caractères est trop longue.
        // Cela ne fractionne pas les mots.
        $max_size = 30; // longueur maximum de la chaîne
        if (strlen($adresse_complete) > $max_size ) {
            $decoupe = explode(
                '\n',
                wordwrap($adresse_complete, $max_size , '\n')
            );
            // Première partie : la voie
            $adresse_triee['voie'] = $decoupe[0];
            // Deuxième partie : le complément
            $adresse_triee['complement1'] = $decoupe[1];
            // Eventuel second complément
            if (isset($decoupe[2])) {
                $adresse_triee['complement2'] = $decoupe[2];
            }
        } else {
            $adresse_triee['voie'] = $adresse_complete;
        }

        foreach ($adresse_triee as $value) {
            if(strlen($value) > $max_size) {
                return false;
            }
        }

        // Renvoi du tableau
        return $adresse_triee;
    }

    /**
     * Permet de définir le numéro de version
     */
    function set_version() {
        $regex = "/^(\w+)-?(\w*)?$/i";
        $dossier=array();

        // On récupère les derniers chiffres après le possible '-'
        if(! preg_match($regex, $this->line["numero"], $dossier)) {
            $this->f->addToLog(
                __METHOD__."(): Failed to match regex on dossier numero: '" . $this->line["numero"] . "'",
                DEBUG_MODE
            );
            return false;
        }
        // Definition du numero de DA
        $this->line["initial"] = $dossier[1];
        if($dossier[2] == '') {
            // si pas de '-' demande initial
            $this->line["version"] = 0;
        } else {
            // sinon on récupère les derniers chiffres
            preg_match('/^(\D)?(\d*)$/', $dossier[2], $version);
            
            $this->line["version"] = intval($version[2]);
        }
        // On supprime l'extension
        $this->line["numero"] = preg_replace ( $regex, '$1', $this->line["numero"]);

        return true;
    }

    /**
     * Permet de définir la collectivité du dossier en fonction de son code INSEE
     * 
     */
    function set_collectivite() {
        $sql = "SELECT om_collectivite FROM ".DB_PREFIXE."om_parametre WHERE libelle='insee' and valeur='".$this->line["insee"]."'";
        $om_collectivite = $this->f->db->getOne($sql);

        $this->f->isDatabaseError($om_collectivite);
        if($om_collectivite != "") {
            $this->line["om_collectivite"] = intval($om_collectivite);
            return null;
        } else {
            $this->line_error[] = _("Le code INSEE de la commune n'est pas paramétré dans l'application");
        }
    }

    /**
     * Recupère le prefix du DI et DA en fonction du DATD
     */
    function set_prefix_di() {
        if(!is_numeric($this->line["type"])) {
            return;
        }
        $sql = "SELECT dossier_autorisation_type.code FROM "
        .DB_PREFIXE."dossier_autorisation_type_detaille
        JOIN ".DB_PREFIXE."dossier_autorisation_type ON
        dossier_autorisation_type_detaille.dossier_autorisation_type=dossier_autorisation_type.dossier_autorisation_type
        WHERE dossier_autorisation_type_detaille.dossier_autorisation_type_detaille=".$this->line["type"];

        $prefix = $this->f->db->getOne($sql);

        $this->f->isDatabaseError($prefix);

        $this->line["initial"] = $prefix.$this->line["initial"];
        $this->line["numero"] = $prefix.$this->line["numero"];

    }


    /**
     * Ajout des DA.
     *
     * @param array $di_data données du DA
     */
    function add_dossier_autorisation($da_id, $list_di) {

        $da_valF["dossier_autorisation"] = $da_id;
        $da_valF["exercice"] = substr($list_di[min(array_keys($list_di))]["depot_en_mairie"], -2);
        $da_valF["insee"] = $list_di[min(array_keys($list_di))]["insee"];
        $da_valF["terrain_references_cadastrales"] = $list_di[min(array_keys($list_di))]["references_cadastrales"];
        $da_valF["terrain_adresse_voie_numero"] = $list_di[min(array_keys($list_di))]["terrain"]["numero"];
        $da_valF["terrain_adresse_voie"] = $list_di[min(array_keys($list_di))]["terrain"]["voie"];
        $da_valF["terrain_adresse_lieu_dit"] = $list_di[min(array_keys($list_di))]["terrain"]["complement1"];
        $da_valF["terrain_adresse_localite"] = $list_di[min(array_keys($list_di))]["terrain"]["ville"];
        $da_valF["terrain_adresse_code_postal"] = $list_di[min(array_keys($list_di))]["terrain"]["cp"];
        $surf = $this->get_surface($list_di[min(array_keys($list_di))]["surface_terrain"]);
        $da_valF["terrain_superficie"] = (($surf===0)? null : $surf);
        $da_valF["depot_initial"] = $list_di[min(array_keys($list_di))]["depot_en_mairie"];
        
        $da_valF["om_collectivite"] = $list_di[min(array_keys($list_di))]["om_collectivite"];
        $da_valF["dossier_autorisation_type_detaille"] = $list_di[min(array_keys($list_di))]["type"];
        
        $regex = "/^([A-Z]{2})([0-9]{3}[0-9]{3})([0-9]{2})([A-Z0][0-9]{4})$/i";
        $dossier=array();
        // Préparation du libelle du dossier d'autorisation
        if(! preg_match($regex, $da_id, $dossier)) {
            $this->f->addToLog(
                __METHOD__."(): LINE  Failed to match regex on dossier autorisation numero: '$da_id'",
                DEBUG_MODE
            );
            return false;
        }
        $da_valF["dossier_autorisation_libelle"] = $dossier[1].' '.$dossier[2].' '.$dossier[3].' '.$dossier[4];

        // Execution de la requete d'insertion des donnees de l'attribut
        // valF de l'objet dans l'attribut table de l'objet
        $res = $this->f->db->autoExecute(DB_PREFIXE."dossier_autorisation", $da_valF, DB_AUTOQUERY_INSERT);
        // Si une erreur survient
        if ($this->f->isDatabaseError($res, true)) {
            return false;
        }
        return true;
    }

    /**
     * Ajout des DI.
     *
     * @param array $di_data données du DI
     */
    function add_dossier_instruction($di_data) {

        $di_valF["dossier"] = $di_data["numero"];
        $regex = "/^(.{2})(.{6})(.{2})(.*)$/i";
        $dossier=array();
        // Préparation du libelle du dossier d'autorisation
        preg_match($regex, $di_data["numero"], $dossier);
        $di_valF["dossier_libelle"] = $dossier[1].' '.$dossier[2].' '.$dossier[3].' '.$dossier[4];
        $di_valF["etat"] = $di_data["etat"];

        $di_valF["date_demande"] = $this->prepare_date($di_data["depot_en_mairie"]);
        $di_valF["date_depot"] = $this->prepare_date($di_data["depot_en_mairie"]);
        $di_valF["date_dernier_depot"] = $this->prepare_date($di_data["depot_en_mairie"]);
        $di_valF["date_complet"] = $this->prepare_date($di_data["completude"]);
        $di_valF["date_notification_delai"] = $this->prepare_date($di_data["notification_majoration"]);
        $di_valF["date_limite"] = $this->prepare_date($di_data["dli"]);
        $di_valF["date_decision"] = $this->prepare_date($di_data["date_de_decision"]);
        $di_valF["date_chantier"] = $this->prepare_date($di_data["doc"]);
        $di_valF["date_achevement"] = $this->prepare_date($di_data["daact"]);
        $di_valF["avis_decision"] = $this->prepare_date($di_data["nature_decision"]);

        $di_valF["autorite_competente"] = $di_data["autorite"];

        $di_valF["terrain_references_cadastrales"] = $di_data["references_cadastrales"];
        $di_valF["terrain_adresse_voie_numero"] = $di_data["terrain"]["numero"];
        $di_valF["terrain_adresse_voie"] = $di_data["terrain"]["voie"];
        $di_valF["terrain_adresse_lieu_dit"] = $di_data["terrain"]["complement1"];
        $di_valF["terrain_adresse_localite"] = $di_data["terrain"]["ville"];
        $di_valF["terrain_adresse_code_postal"] = $di_data["terrain"]["cp"];
        $surf = $this->get_surface($di_data["surface_terrain"]);
        $di_valF["terrain_superficie"] = (($surf===0)? null : $surf);

        $di_valF["dossier_autorisation"] = $di_data["initial"];
        $di_valF["dossier_instruction_type"] = $di_data["dossier_instruction_type"];

        $di_valF["version"] = $di_data["version"];

        $di_valF["om_collectivite"] = $di_data["om_collectivite"];

        // Si le dossier existe on le met à jour
        if($di_data["dossier_exist"] == true) {
            $mode = DB_AUTOQUERY_UPDATE;
        } else {
            $mode = DB_AUTOQUERY_INSERT;
        }

        // Execution de la requete d'insertion des donnees de l'attribut
        // valF de l'objet dans l'attribut table de l'objet
        $res = $this->f->db->autoExecute(
            DB_PREFIXE."dossier",
            $di_valF,
            $mode,
            "dossier='".$di_data["numero"]."'");
        // Si une erreur survient
        if ($this->f->isDatabaseError($res, true)) {
            return false;
        }

        // Si le champ des références cadastrales n'est pas vide
        if ($di_valF['terrain_references_cadastrales'] != '') {
            // Si le dossier existe, les references cadastrales peuvent êtres
            // mise à jour on les supprimes donc pour insérer des parcelles à jour
            $sql = "delete from ".DB_PREFIXE."dossier_parcelle where dossier='".$di_data["numero"]."'";
            // Execution de la requete de suppression de l'objet
            $res = $this->f->db->query($sql);
            // Si une erreur survient
            if ($this->f->isDatabaseError($res, true)) {
                return false;
            }
            // Parse les parcelles
            $list_parcelles = $this->f->parseParcelles($di_valF['terrain_references_cadastrales']);
            // A chaque parcelle une nouvelle ligne est créée dans la table
            // dossier_parcelle
            foreach ($list_parcelles as $parcelle) {

                // Instance de la classe dossier_parcelle
                $dossier_parcelle = $this->f->get_inst__om_dbform(array(
                    "obj" => "dossier_parcelle",
                    "idx" => "]",
                ));

                // Valeurs à sauvegarder
                $value = array(
                    'dossier_parcelle' => '',
                    'dossier' => $di_valF['dossier'],
                    'parcelle' => '',
                    'libelle' => $parcelle['quartier']
                                    .$parcelle['section']
                                    .$parcelle['parcelle']
                );

                // Ajout de la ligne
                $dossier_parcelle->ajouter($value);
            }

        }

        return true;
    }

    /**
     * Mise en forme des dates.
     *
     * @param date $date format DD/MM/YYYY
     *
     * @return date format DD/MM/YYYY null si chaine vide
     */
    function prepare_date($date) {
        if($date == '') {
            return null;
        }
        return $date;
    }

    /**
     * Ajout des données techniques.
     *
     * @param array $di_data données du DI
     */
    function add_donnees_techniques($di_data) {

        $cerfa = $this->get_cerfa($di_data["type"]);

        $val_dt["donnees_techniques"] = $this->f->db->nextId(DB_PREFIXE.'donnees_techniques');
        $val_dt["cerfa"] = $cerfa;
        $val_dt["dossier_instruction"] = $di_data["numero"];
        $val_dt["am_projet_desc"] = "";
        $val_dt["co_projet_desc"] = "";
        $val_dt["dm_projet_desc"] = "";
        // PI et PC
        if($di_data['type'] == 1 or $di_data['type'] == 2) {
            $val_dt["co_projet_desc"] = $di_data["projet"];
        }
        // PA
        if($di_data['type'] == 4) {
            $val_dt["am_projet_desc"] = $di_data["projet"];
        }
        // PD
        if($di_data['type'] == 3) {
            $val_dt["dm_projet_desc"] = $di_data["projet"];
        }
        // DP et DPS
        if($di_data['type'] == 5 || $di_data['type'] == 370) {
            $val_dt["co_projet_desc"] = $di_data["projet"];
        }
        // CUa et CUb
        if($di_data['type'] == 6 || $di_data['type'] == 9) {
            $val_dt["ope_proj_desc"] = $di_data["projet"];
        }


        $val_dt["co_tot_log_nb"] = intval($di_data["nb_logements"]);

        $val_dt["am_terr_surf"] = $this->get_surface($di_data["surface_terrain"]);

        $val_dt["am_lotiss"] = $this->get_boolean($di_data["lotissement"]);
        $val_dt["terr_juri_afu"] = $this->get_boolean($di_data["afu"]);

        $val_dt["code_cnil"] = $this->get_boolean($di_data["opposition_cnil"]);

        // Définition des surfaces selon destination
        $destination = explode(',', $di_data["destination"]);
        switch (trim($destination[0])) {
            case 'Habitation':
                $i = 1;
                break;
            case 'Hébergement hôtelier':
                $i = 2;
                break;
            case 'Bureaux':
                $i = 3;
                break;
            case 'Commerce':
                $i = 4;
                break;
            case 'Artisanat':
                $i = 5;
                break;
            case 'Industrie':
                $i = 6;
                break;
            case 'Exploit. agricole ou forestière':
                $i = 7;
                break;
            case 'Entrepôt':
                $i = 8;
                break;
            case 'Service public ou d\'intérêt général':
                $i = 9;
                break;

            default:
                $i = 1;
                break;
        }
        // Tableau des surfaces
        $val_dt["su_avt_shon".$i] = $this->get_surface($di_data["shon_existante"]);
        $val_dt["su_cstr_shon".$i] = $this->get_surface($di_data["shon_construite"]);
        $val_dt["su_trsf_shon".$i] = $this->get_surface($di_data["shon_transformation_shob"]);
        $val_dt["su_chge_shon".$i] = $this->get_surface($di_data["shon_changement_destination"]);
        $val_dt["su_demo_shon".$i] = $this->get_surface($di_data["shon_demolie"]);
        $val_dt["su_sup_shon".$i] = $this->get_surface($di_data["shon_supprimee"]);

        // dates DOC/DAACT
        $val_dt["doc_date"] = $this->prepare_date($di_data["doc"]);
        $val_dt["daact_date"] = $this->prepare_date($di_data["daact"]);

        // Si les données techniques existe on les met à jour
        if($di_data["dossier_exist"] == true) {
            $mode = DB_AUTOQUERY_UPDATE;
        } else {
            $mode = DB_AUTOQUERY_INSERT;
        }
        // Execution de la requete d'insertion des donnees de l'attribut
        // valF de l'objet dans l'attribut table de l'objet
        $res = $this->f->db->autoExecute(
            DB_PREFIXE."donnees_techniques",
            $val_dt,
            $mode,
            "dossier_instruction='".$di_data["numero"]."'");

        // On retourne l'inverse du resultat d'erreur
        return !$this->f->isDatabaseError($res, true);

    }

    /**
     * Ajout d'un demandeur.
     *
     * @param array $di_data liste des données du DI
     */
    function add_demandeur($di_data) {

        $val_demandeur["demandeur"] = $this->f->db->nextId(DB_PREFIXE.'demandeur');
        $val_demandeur["type_demandeur"] = 'petitionnaire';
        $val_demandeur["qualite"] = 'particulier';
        $val_demandeur["particulier_nom"] = $di_data["demandeur"];
        $val_demandeur["numero"] = $di_data["adresse_demandeur"]["numero"];
        $val_demandeur["voie"] = $di_data["adresse_demandeur"]["voie"];
        $val_demandeur["complement"] = $di_data["adresse_demandeur"]["complement1"];
        $val_demandeur["lieu_dit"] = $di_data["adresse_demandeur"]["complement2"];
        $val_demandeur["code_postal"] = $di_data["adresse_demandeur"]["cp"];
        $val_demandeur["localite"] = $di_data["adresse_demandeur"]["ville"];
        $val_demandeur["om_collectivite"] = $di_data["om_collectivite"];

        // Execution de la requete d'insertion des donnees de l'attribut
        // valF de l'objet dans l'attribut table de l'objet
        $res = $this->f->db->autoExecute(
            DB_PREFIXE."demandeur",
            $val_demandeur,
            DB_AUTOQUERY_INSERT
        );

        if($this->f->isDatabaseError($res, true)) {
            return false;
        }

        $val_lien_dossier_demandeur = array(
            'lien_dossier_demandeur' => $this->f->db->nextId(DB_PREFIXE.'lien_dossier_demandeur'),
            'petitionnaire_principal' => "t",
            'dossier' => $di_data["numero"],
            'demandeur' => $val_demandeur["demandeur"]
        );
        // Execution de la requete d'insertion des donnees de l'attribut
        // valF de l'objet dans l'attribut table de l'objet
        $res = $this->f->db->autoExecute(
            DB_PREFIXE."lien_dossier_demandeur",
            $val_lien_dossier_demandeur,
            DB_AUTOQUERY_INSERT
        );

        if($this->f->isDatabaseError($res, true)) {
            return false;
        }

        return true;
    }

    /**
     * Retourne un float
     *
     * @param string $surf valeur à virgule
     *
     * @return float
     */
    function get_surface($surf) {
        if($surf == '') {
            return null;
        }
        return floatval(str_replace(',', '.', $surf));
    }

    /**
     * Transforme Oui/Non en booleen interpretable par la base.
     *
     * @param String $bool Oui/Non
     *
     * @return string t/f
     */
    function get_boolean($bool) {
        if($bool == '' or $bool == 'NULL') {
            return null;
        }
        if($bool == 'Oui') {
            return 't';
        }
        if($bool == 'Non') {
            return 'f';
        }
    }

    /**
     * Récupération du cerfa associé au DATD.
     *
     * @param integer $datd identifiant du DATD
     *
     * @return integer identifiant du cerfa
     */
    function get_cerfa($datd) {
        $sql = "SELECT cerfa FROM ".DB_PREFIXE."dossier_autorisation_type_detaille
        WHERE dossier_autorisation_type_detaille=".$datd;
        $cerfa = $this->f->db->getOne($sql);
        $this->f->isDatabaseError($cerfa);
        return $cerfa;
    }

    /**
     * Méthode de mise à jour des données du DA passé en paramètre.
     *
     * @param string $id_da identifiant du DA
     *
     * @return boolean true/false
     */
    function update_dossier_autorisation($id_da) {
        $da = $this->f->get_inst__om_dbform(array(
            "obj" => "dossier_autorisation",
            "idx" => $id_da,
        ));
        // Mises à jour du DA à exécuter
        $updates_da = array(
            'localisation',
            'lot',
            'demandeur',
            'etat',
            'date_init_import',
            'date_validite',
            'date_doc_import',
            'date_daact_import',
            'dt',
        );
        return $da->majDossierAutorisation(array(
            'updates_da' => $updates_da,
        ));
    }

    /**
     * Récupération du code du type de dossier d'instruction.
     *
     * @param integer $version numero d'ordre du DI dans le DA
     * @param array   $list_di liste des DI avec leurs données
     *
     * @return string P/T/M
     */
    function get_dossier_instruction_type_code($version, $list_di) {
        $list_di[$version]["demandeur"];

        // Si version = 0 DI initial (P)
        $type_demande = "P";
        if($version !== 0) {
            // Sinon on verifie le nom du demandeur avec le DI précédent
            // si il existe dans le tableau fourni en paramètre
            if(isset($list_di[$version-1])) {
                // Si different il s'agit d'un transfert
                if($list_di[$version]["demandeur"] != $list_di[$version-1]["demandeur"]) {
                    $type_demande = "T";
                } else {
                    // Sinon modificatif
                    $type_demande = "M";
                }
            } else {
                // Si il n'existe pas dans le tableau on verifie en base
                $sql_demandeur = "SELECT particulier_nom FROM ".DB_PREFIXE."demandeur
                    JOIN ".DB_PREFIXE."lien_dossier_demandeur ON lien_dossier_demandeur.demandeur=demandeur.demandeur
                    JOIN ".DB_PREFIXE."dossier ON lien_dossier_demandeur.dossier=dossier.dossier
                    WHERE lien_dossier_demandeur.dossier = '".$list_di[$version]["numero"]."' AND version<".$version." ORDER BY version DESC";
                $demandeur = $this->f->db->getOne($sql_demandeur);
                $this->f->isDatabaseError($demandeur);
                if($list_di[$version]["demandeur"] != $demandeur AND $demandeur != "") {
                    $type_demande = "T";
                } else {
                    $type_demande = "M";
                }
            }
        }

        return $type_demande;
    }


    /**
     * Récupération du boolean qui définit si le suffixe est activé pour ce type de
     * dossier d'instruction.
     *
     * @param integer $id_dossier_instruction_type identifiant du type de DI
     *
     * @return boolean vrai si le suffixe est activé, sinon faux
     */
    function get_dossier_instruction_type_suffixe($id_dossier_instruction_type) {
        $sql = "SELECT suffixe FROM ".DB_PREFIXE."dossier_instruction_type WHERE dossier_instruction_type='".$id_dossier_instruction_type."'";
        $suffixe = $this->f->db->getOne($sql);
        $this->f->isDatabaseError($suffixe);
        return $suffixe;
    }


    /**
     * Récupération de l'identifiant du type de dossier d'instruction.
     *
     * @param integer $type dossier_autorisation_type_detaille
     * @param string  $code P/T/M
     *
     * @return integer identifiant du type de dossier d'instruction
     */
    function get_dossier_instruction_type($type, $code) {
        $sql = "SELECT dossier_instruction_type FROM ".DB_PREFIXE."dossier_instruction_type WHERE dossier_autorisation_type_detaille=".$type." and code='".$code."'" ;
        $dossier_instruction_type = $this->f->db->getOne($sql);
        $this->f->isDatabaseError($dossier_instruction_type);
        return $dossier_instruction_type;
    }
}


