Source: pede_nicho.js


/**
 * Éste módulo es el encargado de inicializar los controladores de los diferentes módulos que son utilizados 
 * en la configuración y ejecución de los análisis de nicho ecológico.
 *
 * @module module_pede_nicho
 */
var module_nicho = (function () {

    var _TEST = false;
    var MOD_NICHO = 0;
    var _VERBOSE = true;
    var _REGION_SELECTED;
    var _REGION_TEXT_SELECTED;

    // actualizar este arreglo si cambian los ids de las secciones
    var _SCROLL_SECTIONS = ["section0","section1","map","myScrollableBlockEpsilonDecil","histcontainer_row"];
    var _SCROLL_INDEX = 0;

    var _loadeddata = false;

    var _tipo_modulo = MOD_NICHO;

    var _map_module_nicho,
        _variable_module_nicho,
        _res_display_module_nicho,
        _region_module_nicho,
        _table_module,
        _histogram_module_nicho,
        _language_module_nicho,
        _module_toast, _utils_module;

    var _componente_fuente;

    var _url_front, _url_api, _url_nicho;

    var _url_geoserver = "http://geoportal.conabio.gob.mx:80/geoserver/cnb/wms?",
            _workspace = "cnb";

    var _iTrans;
    
    const _ACGetEntList = new AbortController();
    const signal = _ACGetEntList.signal;
    
    var _getEntListInProcess = false;

    var groupSpSelection = [];

    var _columns_name = ["anio_colecta", "es_fosil", "latitud", "longitud"];

    var map_taxon = new Map()
    map_taxon.set("reino", "kingdom");
    map_taxon.set("kingdom", "kingdom");
    map_taxon.set("phylum", "phylum");
    map_taxon.set("clase", "class");
    map_taxon.set("class", "class");
    map_taxon.set("orden", "order");
    map_taxon.set("order", "order");
    map_taxon.set("familia", "family");
    map_taxon.set("family", "family");
    map_taxon.set("genero", "genus");
    map_taxon.set("género", "genus");
    map_taxon.set("genus", "genus");
    map_taxon.set("especie", "species");
    map_taxon.set("species", "species");

    var _taxones = [];

    var _datafile_loaded = [];



    /**
     * Este método inicializa el módulo de internacionalización del sistema 
     * y enlaza el método de configuración e inicialización para el análisis de nicho.
     *
     * @function startModule
     * 
     * @param {string} tipo_modulo - Identificador del módulo 0 para nicho y 1 para comunidad
     * @param {string} verbose - Bandera para desplegar modo verbose
     */
    function startModule(verbose) {

        _VERBOSE = verbose;
        _VERBOSE ? console.log("startModule") : _VERBOSE;


        _VERBOSE ? console.log("before language_module NICHO") : _VERBOSE;
        // Se cargan los archivos de idiomas y depsues son cargados los modulos subsecuentes
        _language_module_nicho = language_module(_VERBOSE);
        _language_module_nicho.startLanguageModule(this, _tipo_modulo);

    }


    /**
     * Método ejecutado después de la configuración del módulo de internacionalización. Se encarga de
     * inicializar los controladores de mapas, tablas, histogramas y otros componentes principales.
     *
     * @function loadModules
     * @public
     * 
     */
    function loadModules() {

        _VERBOSE ? console.log("loadModules") : _VERBOSE;

        _module_toast = toast_module(_VERBOSE);
        _module_toast.startToast();


        _iTrans = _language_module_nicho.getI18();

        _utils_module = utils_module();
        _utils_module.startUtilsModule();

        _histogram_module_nicho = histogram_module(_VERBOSE);
        _histogram_module_nicho.setLanguageModule(_language_module_nicho);
        _histogram_module_nicho.startHistogramModule();
        

        _map_module_nicho = map_module(_url_geoserver, _workspace, _VERBOSE, _url_api);
        _map_module_nicho.startMap(_language_module_nicho, _tipo_modulo, _histogram_module_nicho);

        _table_module = table_module(_VERBOSE);
        _table_module.startTableModule();


        _language_module_nicho.setTableModule(_table_module)


        _res_display_module_nicho = res_display_module(_VERBOSE, _url_api);

        _map_module_nicho.setDisplayModule(_res_display_module_nicho);

        _histogram_module_nicho.setDisplayModule(_res_display_module_nicho);



        // un id es enviado para diferenciar el componente del grupo de variables en caso de que sea mas de uno (caso comunidad)
        _variable_module_nicho = variable_module(_VERBOSE, _url_api);
        _variable_module_nicho.startVar(0, _language_module_nicho, _tipo_modulo, _map_module_nicho);


        var ids_comp_variables = ['fuente', 'target'];
        _componente_fuente = _variable_module_nicho.createSelectorComponent("variables", ids_comp_variables[0], "lb_panel_variables", true, false, false, 0, true);

        _componente_target = _variable_module_nicho.createSelectorComponent("var_target", ids_comp_variables[1], "", false, true, true, 4, false);

        // enlazando los modulos que tienen interacción en los procesos
        _res_display_module_nicho.startResDisplay(_map_module_nicho, _histogram_module_nicho, _table_module, _language_module_nicho, ids_comp_variables);


        // se envia url con direccion a servidor zacatuche
        // _region_module_nicho = region_module(_url_api, _VERBOSE);
        // _region_module_nicho.startRegion(_map_module_nicho, _language_module_nicho);

        _language_module_nicho.addModuleForLanguage(_res_display_module_nicho, _histogram_module_nicho, _map_module_nicho, _variable_module_nicho);

        _initializeComponents();

    }


    /**
     * Inicializa y configura los diferentes componetes secundarios que son necesarios para la ejecución de un análisis de niho.
     *
     * @function _initializeComponents
     */
    function _initializeComponents() {

        _VERBOSE ? console.log("_initializeComponents") : _VERBOSE;

        $("#lb_do_apriori").text(_iTrans.prop('lb_no'));
        $("#lb_mapa_prob").text(_iTrans.prop('lb_no'));


        $(function () {

            var year = parseInt(new Date().getFullYear());
            // obtnego el proximo numero divisible entre 10. 2016 -> 2020; 2017 -> 2020; 2021 -> 2030
            year = Math.round(year / 10) * 10;

            $("#sliderFecha").slider({
                range: true,
                min: 1500,
                max: year,
                step: 10,
                values: [1500, year],
                change: function (event, ui) {

                    var value = ui.values[1];
                    if (value == year) {
                        value = _iTrans.prop('val_actual');
                    }

                    $("#labelFecha").text(_iTrans.prop('labelFecha', ui.values[0], value));

                    _regenMessage();


                    _module_toast.showToast_BottomCenter(_iTrans.prop('lb_rango_fecha', ui.values[0], value), "info");

                    if (ui.values[0] !== 1500 || ui.values[1] !== year) {
                        $("#chkFecha").prop('checked', false);
                        $("#lb_sfecha").text(_iTrans.prop('lb_no'));
                    } else {
                        $("#chkFecha").prop('checked', true);
                        $("#lb_sfecha").text(_iTrans.prop('lb_si'));
                    }



                }
            });

        });


        function forceNumeric() {
            var $input = $(this);
            $input.val($input.val().replace(/[^\d]+/g, ''));
        }


        $('body').on('propertychange input', 'input[type="number"]', forceNumeric);


        // checkbox que se activa cuando se desea realizar el proceso de validación. (Proceso de validación todavia no implementado)
        $("#chkValidation").click(function (event) {

            console.log("cambia validacion");

            var $this = $(this);

            if ($this.is(':checked')) {

                $("#labelValidation").text("Si");

                _module_toast.showToast_BottomCenter(_iTrans.prop('lb_status_validacion_act'), "info");

            } else {

                $("#labelValidation").text("No");
                _module_toast.showToast_BottomCenter(_iTrans.prop('lb_status_validacion_des'), "info");

            }

        });


        // checkbox que se activa cuando se desea tomar en cuanta un minimo de ocurrencias
        $("#chkMinOcc").click(function (event) {

            var $this = $(this);

            if ($this.is(':checked')) {

                $("#occ_number").prop("disabled", false);

                _module_toast.showToast_BottomCenter(_iTrans.prop('lb_status_minocc_act'), "info");

            } else {

                $("#occ_number").prop("disabled", true);

                _module_toast.showToast_BottomCenter(_iTrans.prop('lb_status_minocc_des'), "info");

            }

        });


        $("#chkFosil").click(function (event) {

            var $this = $(this);

            if ($this.is(':checked')) {

                $("#labelFosil").text("Si");

                _regenMessage();
                _module_toast.showToast_BottomCenter(_iTrans.prop('lb_status_fosil_act'), "info");

            } else {

                $("#labelFosil").text("No");

                _regenMessage();

                _module_toast.showToast_BottomCenter(_iTrans.prop('lb_status_fosil_des'), "info");

            }

        });


        // checkbox que se activa cuando se desea tomar en cuanta un minimo de ocurrencias
        $("#chkFecha").click(function (event) {

            var $this = $(this);

            if ($this.is(':checked')) {
                $("#sliderFecha").slider("enable");
                $("#lb_sfecha").text(_iTrans.prop('lb_si'));

                _regenMessage();
                _module_toast.showToast_BottomCenter(_iTrans.prop('lb_status_chkfecha'), "info");

            } else {

                $("#lb_sfecha").text(_iTrans.prop('lb_no'));

                _regenMessage();
                _module_toast.showToast_BottomCenter(_iTrans.prop('lb_status_chkfecha_des'), "info");

            }

        });


        $("#footprint_region_select").change(function (e) {

            _VERBOSE ? console.log("Cambiando a " + parseInt($("#footprint_region_select").val())) : _VERBOSE

            _REGION_SELECTED = parseInt($("#footprint_region_select").val());
            _REGION_TEXT_SELECTED = $("#footprint_region_select option:selected").text();
            _map_module_nicho.changeRegionView(_REGION_SELECTED);

            _regenMessage();

        });


        $("#grid_resolution").change(function (e) {

            _VERBOSE ? console.log("Cambia grid resolución") : _VERBOSE;
            // No es necesario regenerar resultados
            _regenMessage();

        });


        // checkbox que se activa cuando se desea realizar el proceso de validación. (Proceso de validación todavia no implementado)
        $("#chkApriori").click(function (event) {

            var $this = $(this);

            if ($this.is(':checked')) {
                $("#lb_do_apriori").text(_iTrans.prop('lb_si'));
                _module_toast.showToast_BottomCenter(_iTrans.prop('lb_status_apriori_act'), "info");

            } else {
                $("#lb_do_apriori").text(_iTrans.prop('lb_no'));
                _module_toast.showToast_BottomCenter(_iTrans.prop('lb_status_apriori_desc'), "info");
            }

        });


        // checkbox que se activa cuando se desea realizar el proceso de validación. (Proceso de validación todavia no implementado)
        $("#chkMapaProb").click(function (event) {

            var $this = $(this);

            if ($this.is(':checked')) {
                $("#lb_mapa_prob").text(_iTrans.prop('lb_si'));
                _module_toast.showToast_BottomCenter(_iTrans.prop('lb_status_mapprob_act'), "info");

            } else {
                $("#lb_mapa_prob").text(_iTrans.prop('lb_no'));
                _module_toast.showToast_BottomCenter(_iTrans.prop('lb_status_mapprob_des'), "info");
            }

        });


        // deshabilita controles temporales
        $("#chkFecha").prop('disabled', false);


        $("#sliderFecha").slider({
            disabled: false
        });


        $("#nicho_link").click(function () {
            window.location.replace(_url_front + "/comunidad_v0.1.html");
        });

        $("#btn_tutorial").click(function () {
            window.open(_url_front + "/docs/tutorial.pdf");
        });

        _SCROLL_INDEX = 0;

        $("#specie_next").click(function () {

            if(_SCROLL_INDEX >= _SCROLL_SECTIONS.length-1)
                return;

            _SCROLL_INDEX = _SCROLL_INDEX + 1;

            // console.log(_SCROLL_SECTIONS[_SCROLL_INDEX]) 
            
            $('html, body').animate({
                scrollTop: $("#"+_SCROLL_SECTIONS[_SCROLL_INDEX]).offset().top - 40
            }, 1000);

            

        });


        $("#specie_before").click(function () {

            if(_SCROLL_INDEX == 0)
                return;

            _SCROLL_INDEX = _SCROLL_INDEX - 1;

            // console.log(_SCROLL_SECTIONS[_SCROLL_INDEX]) 
            
            $('html, body').animate({
                scrollTop: $("#"+_SCROLL_SECTIONS[_SCROLL_INDEX]).offset().top - 40
            }, 1000);

            

        });


        $('.ct-sliderPop-close').on('click', function () {
            $('.sliderPop').hide();
            $('.ct-sliderPop-container').removeClass('open');
            $('.sliderPop').removeClass('flexslider');
            $('.sliderPop .ct-sliderPop-container').removeClass('slides');
        });


        $("#reload_map").click(function () {

            _VERBOSE ? console.log("reload_map") : _VERBOSE;

            $("#sp_download").css('visibility', 'visible');
            $("#sp_download_csv").css('visibility', 'visible');

            var region = _REGION_SELECTED;

            var groupDatasetTotal = _componente_target.getGroupDatasetTotal()

            _VERBOSE ? console.log(groupDatasetTotal) : _VERBOSE

            if(groupDatasetTotal.length == 0){
                console.log("No species selected");
                _module_toast.showToast_BottomCenter(_iTrans.prop('msg_noespecies_selected'), "warning");
                return;
            }

            _taxones = [];

            $.each(groupDatasetTotal, function(index_i, grupo){

                console.log(grupo);

                $.each(grupo.elements, function(index_j, sp_grupo){

                    
                    var array_sp = sp_grupo.label.split(">>");

                    var temp_item = {};

                    temp_item["taxon_rank"] = map_taxon.get(array_sp[0].trim().toLowerCase());
                    temp_item["value"] = array_sp[1].trim();
                    temp_item["title"] = grupo.title;
                    temp_item["nivel"] = parseInt(sp_grupo.level); //0:root, 1:reino, etc...
                    _taxones.push(temp_item);
                })

            })

            console.log(_taxones);

            var val_process = $("#chkValidation").is(':checked');
            var grid_res = $("#grid_resolution").val();
            var footprint_region = parseInt($("#footprint_region_select").val());

            // _map_module_nicho.loadD3GridMX(val_process, grid_res, footprint_region, _taxones);

            _map_module_nicho.busca_especie_grupo(_taxones, footprint_region, val_process, grid_res);

            // se establece que el funcionamiento es por seleccion de especie
            _loadeddata = false;

        });


        $("#show_gen").click(function (e) {

            _VERBOSE ? console.log("show_gen") : _VERBOSE;

            var data_link = creaCamposLinkConfiguracion();            
            _getLinkToken(data_link);

        });


        $("#accept_link").click(function () {

            $("#modalRegenera").modal("hide");
            document.execCommand("copy");
            console.log('se copia url con toker');
        });



        $('#modalRegenera').on('shown.bs.modal', function (e) {

            $('#modalRegenera input[type="text"]')[0].select();

        });


        var _exist_tblload = false;

        $('#csv_load').change(function(e){

            console.log("selecciona archivo");

            _VERBOSE ? console.log("_exist_tblload: " + _exist_tblload) : _VERBOSE
            
            if(_exist_tblload){
                _VERBOSE ? console.log("clean table") : _VERBOSE
                // $('#tbl_spload').dataTable().fnDestroy();    
                $('#wrapper').empty();
            }


            var reader = new FileReader();
            reader.readAsArrayBuffer(e.target.files[0]);
            
            reader.onload = function(e) {

                _VERBOSE ? console.log("carga archivo") : _VERBOSE
                _exist_tblload = true;

                var data = new Uint8Array(reader.result);

                var wb = XLSX.read(data,{type:'array'});

                var ws = wb.Sheets[wb.SheetNames[0]];

                var json = XLSX.utils.sheet_to_json(ws, { header: 1, raw: true });

                // console.log(json);

                
                var BreakException = {};
                var column_index = d3.map([]);
                // var htmlstr = "";

                // htmlstr += "<table>"

                try {

                    json.forEach(function(columns) {

                        // htmlstr += "<th>"

                        // _VERBOSE ? console.log(columns) : _VERBOSE
                        columns.forEach(function (column, index) {


                            // _VERBOSE ? console.log(column) : _VERBOSE
                            if(_columns_name.indexOf(column) != -1){
                                
                                // htmlstr += "<td>" + column + "</td>"
                                column_index.set(index, column)

                            }
                        });

                        // htmlstr += "</th>"

                        throw BreakException;

                    });

                } 
                catch (e) {
                  if (e !== BreakException) throw e;
                }


                // _VERBOSE ? console.log(column_index.values()) : _VERBOSE

                if(column_index.values().length != 4){
                    _module_toast.showToast_BottomCenter("El excel no contiene las columnas requeridas, verifica el formato requerido", "error");
                    return;
                }

                _datafile_loaded = [];


                json.forEach(function(columns, indexi) {

                    // Descarta encabezados
                    if(indexi != 0){

                        // _VERBOSE ? console.log(columns) : _VERBOSE

                        // htmlstr += "<tr>"

                        var temp = {}

                        columns.forEach(function (column, indexj) {
                            
                            // _VERBOSE ? console.log(column + " " +indexj) : _VERBOSE

                            if(column_index.has(indexj)){

                                // _VERBOSE ? console.log(column_index.get(indexj)) : _VERBOSE

                                switch(column_index.get(indexj)){

                                    case _columns_name[0]:
                                        // column = column != "" && column != undefined ? column : ""
                                        temp.anio = column
                                        // htmlstr += "<td>" + column + "</td>"
                                        break;

                                    case _columns_name[1]:
                                        // column = column != "" && column != undefined ? column : ""
                                        temp.fosil = column
                                        // htmlstr += "<td>" + column + "</td>"
                                        break;

                                    case _columns_name[2]:
                                        // column = column != "" && column != undefined ? column : ""
                                        temp.latitud = column
                                        // htmlstr += "<td>" + column + "</td>"
                                        break;

                                    case _columns_name[3]:
                                        // column = column != "" && column != undefined ? column : ""
                                        temp.longitud = column
                                        // htmlstr += "<td>" + column + "</td>"
                                        break;

                                }

                            }  
                    
                        });

                        // htmlstr += "</tr>"

                        _datafile_loaded.push(temp)                     

                    }
                    
                });

                // console.log(_datafile_loaded);

                // htmlstr += "</table>"

                // var html = XLSX.utils.sheet_to_html(ws, { header: 1, raw: true });
                // console.log(html);

                var htmlstr = XLSX.write(wb,{type:'binary',bookType:'html'});
                // _VERBOSE ? console.log(htmlstr) : _VERBOSE


                $('#wrapper')[0].innerHTML += htmlstr;
                // _VERBOSE ? console.log($("#wrapper table")) : _VERBOSE

                var raw_table = $("#wrapper table");
                // console.log(raw_table);
                raw_table.attr("id","tbl_spload");
                raw_table.prop("id","tbl_spload")                    

                // $('#tbl_spload').DataTable({
                //     language: {
                //         "sEmptyTable": _iTrans.prop('sEmptyTable'), 
                //         "info": _iTrans.prop('info'),
                //         "search": _iTrans.prop('search') + " ",
                //         "zeroRecords": _iTrans.prop('zeroRecords'),
                //         "infoEmpty": _iTrans.prop('infoEmpty'),
                //         "infoFiltered": _iTrans.prop('infoFiltered')
                //     }
                // });

                
            }
        });


        $("#muestra_puntos").click(function () {

            _VERBOSE ? console.log("muestra_puntos") : _VERBOSE;

            $("#modalloaddata").modal("hide");

            console.log(_datafile_loaded);

            // TODO: 
            // - Generación de histograma fechas
            // - Conexión con verbo de meustra de puntos
            // $("#get_esc_dataloaded").css('visibility', 'visible');
            $("#sp_download").css('visibility', 'hidden');
            $("#sp_download_csv").css('visibility', 'hidden');

            var val_process = $("#chkValidation").is(':checked');
            var grid_res = $("#grid_resolution").val();
            var footprint_region = parseInt($("#footprint_region_select").val());

            // se establece que el análisis sera por carga de datos
            _loadeddata = true;

            // se ejecuta función para cargar las mallas
            _map_module_nicho.busca_especie_grupo([], footprint_region, val_process, grid_res, _loadeddata, _datafile_loaded);


        });

        _genLinkURL();


        // Funcionalidad de mensaje de bienvenida
        $('#nomostrar_msg').change(function() {
            
            if(this.checked) {
                // _VERBOSE ? console.log("agrega cookie") : _VERBOSE
                Cookies.set('cacher_modal', true)
            }
            else{
                // _VERBOSE ? console.log("borra cookie") : _VERBOSE
                Cookies.remove('cacher_modal')
            }
            
        });

        $("#cancel_wel").click(function(){
            $("#modalInicio").modal("hide");
        })

        $("#tuto_wel").click(function(){

            $("#modalInicio").modal("hide");
            _language_module_nicho.liveTutorialConfNiche();
            
        })

        $("#usecase_wel").click(function(){
            $("#modalInicio").modal("hide");
            $("#modalDemo").modal("show")
        })


        // se ejecutan los modulos necesarios para iniciar el proceso de obteción de epsilon y score y visualización de tablas, histogramas y mapa
        $("#get_esc_ep").click(function () {

            _VERBOSE ? console.log("get_esc_ep") : _VERBOSE;

            if (_taxones.length === 0 && _loadeddata == false) {
                _module_toast.showToast_BottomCenter(_iTrans.prop('lb_error_especie'), "warning");
                return;
            } 

            startNicheAnalisis();

            // Guarda ultima configuración ejecutada
            var data_link = creaCamposLinkConfiguracion();
            var openmodal = false;
            _getLinkToken(data_link, openmodal);


        });

        _showTutorialPopUp()

    }


    /**
     * Se encarga de validar si el modal de primera visita el sistema es desplegado al usuario.
     *
     * @function _showTutorialPopUp
     * @private
     */
    function _showTutorialPopUp(){

        if (Cookies.get('cacher_modal')) {
            $("#modalInicio").remove();
        } else {
            $("#modalInicio").modal("show");
        }        

    }


    /**
     * Cambia la tonalidad del color del botón que obtiene las ocurrencias 
     * de la especie para saber si es necesario volver a ejecutarlo.
     * Actualmente esta en desuso.
     *
     * @function _regenMessage
     * @private
     */
    function _regenMessage() {

        if ($("#reload_map").hasClass("btn-primary") && _map_module_nicho.get_specieTarget()) {

            _module_toast.showToast_BottomCenter(_iTrans.prop('lb_gen_values'), "warning");
            $("#reload_map").addClass('btn-success').removeClass('btn-primary');
            

        }

    }


    /**
     * Construye el objeto json que guarda la configuración de un análisis de nicho ejecutado previamente.
     *
     * @function creaCamposLinkConfiguracion
     */
    function creaCamposLinkConfiguracion(){

        console.log("creaCamposLinkConfiguracion");

        var data_link = {};

        if(_loadeddata){
            
            var subgroups_target = [{title:"na",type:"na",groupid:-1}];
            // _module_toast.showToast_BottomCenter(_iTrans.prop('lb_gen_values'), "warning");
            _module_toast.showToast_BottomCenter("La regeneración de este análisis requerirá tener el conjunto de datos que fue cargado.", "warning");
        }
        else{
            
            var subgroups_target = _componente_target.getVarSelArray();
        }
        
        var subgroups = _componente_fuente.getVarSelArray();    
        data_link.tfilters = subgroups;            

        data_link.tipo = "nicho"
        
        // data_link.taxones = _taxones;
        data_link.sfilters = subgroups_target;

        data_link.val_process = $("#chkValidation").is(":checked");
        data_link.idtabla = data_link.val_process === true ? _res_display_module_nicho.getValidationTable() : "no_table";
        data_link.mapa_prob = $("#chkMapaProb").is(":checked");
        data_link.fossil = $("#chkFosil").is(":checked");
        data_link.apriori = $("#chkApriori").is(':checked');
        data_link.sfecha = $("#chkFecha").is(':checked');

        var rango_fechas = $("#sliderFecha").slider("values");
        if (rango_fechas[0] !== $("#sliderFecha").slider("option", "min") || rango_fechas[1] !== $("#sliderFecha").slider("option", "max")) {
            data_link.lim_inf = rango_fechas[0];
            data_link.lim_sup = rango_fechas[1];
        } else {
            data_link.lim_inf = undefined;
            data_link.lim_sup = undefined;
        }

        data_link.min_occ = $("#chkMinOcc").is(':checked') === true ? parseInt($("#occ_number").val()) : 0;
        data_link.grid_res = $("#grid_resolution").val();
        data_link.footprint_region = parseInt($("#footprint_region_select").val());

        data_link.discardedFilterids = _map_module_nicho.get_discardedPoints().values().map(function (value) {
            return value.feature.properties.gridid
        });
        // console.log(data_link.discardedFilterids);

        data_link.loadeddata=_loadeddata

        console.log(data_link);

        return data_link;

    }

    
    /**
     * Genera un token de recuperación de un análisis previamente ejecutado.
     *
     * @function _getLinkToken
     * 
     * @param {String} data_link - Cadena que contiene los parametros selecicoandos por el usuario en el análisis.
     * @param {Boolean} openmodal - Bandera por default en true, para desplegar el modal donde se encuentra el token generado.
     * 
     */
    function _getLinkToken(data_link, openmodal = true) {

        console.log("_getLinkToken");
        _VERBOSE ? console.log(data_link) : _VERBOSE

        $.ajax({
            url: _url_api + "/niche/especie/getToken",
            type: 'post',
            data: data_link,
            dataType: "json",
            success: function (resp) {

                var cadena_ini = _url_nicho + '#link/?';
                var tokenlink = resp.data[0].token;

                console.log("token: " + tokenlink);

                if(openmodal){
                    $("#modalRegenera").modal();
                    $("#lb_enlace").val(cadena_ini + "token=" + tokenlink);
                }
                else{
                    _VERBOSE ? console.log("guarda token en input hidden") : _VERBOSE
                    // Asigna a input hidden para reporteo
                    $("#link_gen").val(cadena_ini + "token=" + tokenlink)
                    _VERBOSE ? console.log("link_gen: " + $("#link_gen").val()) : _VERBOSE
                }

            },
            error: function (jqXHR, textStatus, errorThrown) {
                _VERBOSE ? console.log("error: " + textStatus) : _VERBOSE;

            }
        });

    }


    /**
     * A partir de un token, obtiene los parámetros guardados de un análisis de nicho y ejecuta el método que carga la información en la interfaz del sistema.
     *
     * @function _getValuesFromToken
     * @param {String} token - token relacionado a un conjunto de paramétros utilizados en un análisis.
     * 
     */
    function _getValuesFromToken(token) {

        console.log("_getValuesFromToken");
        console.log("token: " + token);


        $.ajax({
            url: _url_api + "/niche/especie/getValuesFromToken",
            type: 'post',
            data: {
                token: token,
                tipo: 'nicho'
            },
            dataType: "json",
            success: function (resp) {

                console.log(resp);

                if(resp.data.length === 0){
                    _module_toast.showToast_BottomCenter(_iTrans.prop('lb_error_link'), "error");
                    return
                }

                var all_data = resp.data[0].parametros;
                _json_config = _utils_module.parseURL("?" + all_data);

                var chkVal = _json_config.chkVal ? _json_config.chkVal === "true" : false;

                var chkPrb = _json_config.chkPrb ? _json_config.chkPrb === "true" : false;

                var chkFosil = _json_config.chkFosil ? _json_config.chkFosil === "true" : false;

                var chkApr = _json_config.chkApr ? _json_config.chkApr === "true" : false;

                var chkFec = _json_config.chkFec ? _json_config.chkFec === "true" : false;

                var chkOcc = _json_config.chkOcc ? parseInt(_json_config.chkOcc) : undefined;

                var minFec = _json_config.minFec ? parseInt(_json_config.minFec) : undefined;

                var maxFec = _json_config.maxFec ? parseInt(_json_config.maxFec) : undefined;

                var gridRes = _json_config.gridRes ? _json_config.gridRes : 16;

                var region = _json_config.region ? parseInt(_json_config.region) : 1;

                var rango_fechas = minFec != undefined && maxFec != undefined ? [minFec, maxFec] : undefined;

                // recover deleted items
                var num_dpoints = parseInt(_json_config.num_dpoints);
                var map_dPoints = d3.map([]);
                for (i = 0; i < num_dpoints; i++) {
                    var item = JSON.parse(_json_config["deleteditem[" + i + "]"]);
                    map_dPoints.set(item.feature.properties.gridid, item);
                }
                _VERBOSE ? console.log(map_dPoints.values()) : _VERBOSE

                var num_sfilters = parseInt(_json_config.num_sfilters);
                var sfilters = [];
                var loadeddata = false;
                
                if(num_sfilters >= 1){
                    var temp = JSON.parse(_json_config["sfilters[0]"]);
                    _VERBOSE ? console.log(temp) : _VERBOSE
                    
                    if(temp["title"] == "na" && temp["groupid"] == -1){
                        loadeddata = true;
                        // _module_toast.showToast_BottomCenter(_iTrans.prop('lb_error_link'), "error");
                        _module_toast.showToast_BottomCenter("Este analisis necesita el conjunto de datos con el que fue generado", "warning");
                    }
                    else{

                        for (i = 0; i < num_sfilters; i++) {
                            var item = _json_config["sfilters[" + i + "]"];
                            sfilters.push(JSON.parse(_json_config["sfilters[" + i + "]"]));
                        }

                    }
                }

                var num_filters = parseInt(_json_config.num_filters);
                var filters = [];
                for (i = 0; i < num_filters; i++) {
                    var item = _json_config["tfilters[" + i + "]"];
                    filters.push(JSON.parse(_json_config["tfilters[" + i + "]"]));
                }

                // se establece que el analisis fue por carga de datos
                _loadeddata = loadeddata
                _VERBOSE ? console.log("_loadeddata: " + _loadeddata) : _VERBOSE

                _procesaValoresEnlace(sfilters, filters, chkVal, chkPrb, chkApr, chkFec, chkOcc, rango_fechas, chkFosil, gridRes, region, map_dPoints);
                
                $("#show_gen").css('visibility', 'hidden');



            },
            error: function (jqXHR, textStatus, errorThrown) {
                _VERBOSE ? console.log("error: " + textStatus) : _VERBOSE;

            }
        });


    }


    /**
     * Verifica si existe un token de regeneración de análisis, en caso de existir, obtiene y parsea el contenido 
     * en la URL para ejecutar el método encargado de obtener y procesar los parámetros guardados.
     *
     * @function _genLinkURL
     * @public
     * 
     */
    function _genLinkURL() {

        _VERBOSE ? console.log("_genLinkURL") : _VERBOSE;

        if (_json_config == undefined) {
            return;
        }

        var token = _json_config.token;
        _getValuesFromToken(token);

    }

   
    /**
     * De los parámetros obtenidos de un token, configura y asigna los valores guardados en los componentes de la interfaz para regenerar nuevamente el análisis de nicho.
     *
     * @function _procesaValoresEnlace
     *
     * @param {json} subgroups_target - JSON  con el grupo de variables objetivo seleccionado 
     * @param {json} subgroups - JSON  con el grupo de variables seleccionado
     * @param {boleano} chkVal - Bandera si esta activado el proceso de validación
     * @param {boleano} chkPrb - Bandera si esta activado el mapa de probabilidad
     * @param {boleano} chkApr - Bandera si esta activado el cálculo con a priori
     * @param {boleano} chkFec - Bandera si esta activado el cálculo con registros sin fecha
     * @param {integer} chkOcc - Número mínimo de ocurrencias en nj para ser considerado en los cálculos
     * @param {array} rango_fechas - Rango de fecha para realizar los cálculos
     * @param {boleano} chkFosil - Bandera si esta activado la consideración de registros fósiles
     * @param {integer} gridRes - Resolución de la malla para ser considerado en los cálculos
     * @param {integer} region - Identificador de la región donde se guardo el análisis
     * @param {array} map_dPoints - Arreglo con los identificadores de celda que no deben ser considerados en el análisis
     */
    function _procesaValoresEnlace(subgroups_target, subgroups, chkVal, chkPrb, chkApr, chkFec, chkOcc, rango_fechas, chkFosil, gridRes, region, map_dPoints) {

        _VERBOSE ? console.log("_procesaValoresEnlace") : _VERBOSE;

        console.log("Region : " + region);
        var idreg = ["Estados"]; // Módulo por desarrollar
        
        if (chkFec) {
            $("#chkFecha").prop('checked', true);
            $("#lb_sfecha").text(_iTrans.prop('lb_si'));
        } else {
            $("#chkFecha").prop('checked', false);
            $("#lb_sfecha").text(_iTrans.prop('lb_no'));
        }

        if (chkVal) {
            $("#chkValidation").prop('checked', true);
            $("#labelValidation").text(_iTrans.prop('lb_si'));
        } else {
            $("#chkValidation").prop('checked', false);
            $("#labelValidation").text(_iTrans.prop('lb_no'));
        }

        if (chkPrb) {
            $("#chkMapaProb").prop('checked', true);
            $("#lb_mapa_prob").text(_iTrans.prop('lb_si'));
        } else {
            $("#chkMapaProb").prop('checked', false);
            $("#lb_mapa_prob").text(_iTrans.prop('lb_no'));
        }


        if (chkFosil) {
            $("#chkFosil").prop('checked', true);
            $("#labelFosil").text(_iTrans.prop('lb_si'));
        } else {
            $("#chkFosil").prop('checked', false);
            $("#labelFosil").text(_iTrans.prop('lb_no'));
        }

        if (chkApr) {
            $("#chkApriori").prop('checked', true);
            $("#lb_do_apriori").text(_iTrans.prop('lb_si'));
        } else {
            $("#chkApriori").prop('checked', false);
            $("#lb_do_apriori").text(_iTrans.prop('lb_no'));
        }

        if (chkOcc) {
            $("#chkMinOcc").prop('checked', true);
            $("#occ_number").prop("disabled", false);
            $("#occ_number").val(chkOcc);

        } else {
            $("#chkMinOcc").prop('checked', false);
            $("#occ_number").prop("disabled", true);
            $("#occ_number").val(chkOcc);
        }

        if (rango_fechas !== undefined) {
            $("#sliderFecha").slider('values', 0, rango_fechas[0]);
            $("#sliderFecha").slider('values', 1, rango_fechas[1]);
        }

        $('#grid_resolution option[value=' + gridRes + ']').attr('selected', 'selected');

        $('#footprint_region_select option[value=' + region + ']').attr('selected', 'selected');

        _VERBOSE ? console.log(subgroups_target) : _VERBOSE
        _VERBOSE ? console.log(subgroups) : _VERBOSE

        
        _taxones = [];


        if(!_loadeddata){

            _VERBOSE ? console.log("Se cargan valores de especie objetivo") : _VERBOSE

            _componente_target.setVarSelArray(subgroups_target);

            $.each(subgroups_target, function(index_i, grupo){

                console.log(grupo);

                $.each(grupo.value, function(index_j, sp_grupo){

                    var array_sp = sp_grupo.label.split(">>");

                    var temp_item = {};

                    temp_item["taxon_rank"] = map_taxon.get(array_sp[0].trim().toLowerCase());
                    temp_item["value"] = array_sp[1].trim();
                    temp_item["title"] = grupo.title;
                    temp_item["nivel"] = parseInt(sp_grupo.level); //0:root, 1:reino, etc...
                    _taxones.push(temp_item);

                })

            })

            _VERBOSE ? console.log(_taxones) : _VERBOSE

            _map_module_nicho.loadD3GridMX(chkVal, gridRes, region, _taxones);   

            _componente_target.addUIItem(subgroups_target.slice());

        }


        _componente_fuente.addUIItem(subgroups.slice());
        
        _res_display_module_nicho.set_idReg(idreg);
  
        _componente_fuente.setVarSelArray(subgroups);
        
        _res_display_module_nicho.set_subGroups(subgroups);


        if (subgroups.length == 0) {
            _module_toast.showToast_BottomCenter(_iTrans.prop('lb_error_variable'), "warning");
        } 
        else {
            _module_toast.showToast_BottomCenter(_iTrans.prop('lb_gen_link'), "info");
        }
        

    }

   
    /**
     * Agrupa todos los valores configurados por el usuario para iniciar el proceso de análisis de nicho.
     *
     * @function startNicheAnalisis
     * 
     */
    function startNicheAnalisis(){

        _VERBOSE ? console.log("startNicheAnalisis") : _VERBOSE;

        var num_items = 0, spid, idreg, subgroups, sp_target;

        
        $("#show_gen").css('visibility', 'visible');   
        $("#btn_tuto_steps_result").css('visibility', 'visible');
        
        // agregar validación para estados
        // idreg = _region_module_nicho.getRegionSelected();
        // _res_display_module_nicho.set_idReg(idreg);

        subgroups = _componente_fuente.getVarSelArray();

        _res_display_module_nicho.set_taxones(_taxones);
        
        var type_time = _componente_fuente.getTimeBioclim();

        _res_display_module_nicho.set_subGroups(subgroups);

        _res_display_module_nicho.set_typeBioclim(type_time);


        if (subgroups.length <= 0) {

            $("#show_gen").css('visibility', 'hidden');
            $("#btn_tuto_steps_result").css('visibility', 'hidden');
            $("#tuto_res").css('visibility', 'hidden');
            // $("#params_next").css('visibility', 'hidden');

            _module_toast.showToast_BottomCenter(_iTrans.prop('lb_error_variable'), "error");
            return;
        }


        _VERBOSE ? console.log(_map_module_nicho.get_discardedPoints()) : _VERBOSE

        _res_display_module_nicho.set_discardedPoints(_map_module_nicho.get_discardedPoints());
        _res_display_module_nicho.set_discardedCellFilter(_map_module_nicho.get_discardedCellFilter());
        _res_display_module_nicho.set_allowedCells(_map_module_nicho.get_allowedCells());


        var val_process = $("#chkValidation").is(':checked');
        var min_occ = $("#chkMinOcc").is(':checked');
        var mapa_prob = $("#chkMapaProb").is(':checked');
        var grid_res = $("#grid_resolution").val();
        var footprint_region = parseInt($("#footprint_region_select").val());

        console.log("grid_res: " + grid_res);

        var fossil = $("#chkFosil").is(':checked');
        var rango_fechas = $("#sliderFecha").slider("values");

        if (rango_fechas[0] == $("#sliderFecha").slider("option", "min") && rango_fechas[1] == $("#sliderFecha").slider("option", "max")) {
            rango_fechas = undefined;
        }

        var chkFecha = $("#chkFecha").is(':checked');

        var slider_value = val_process ? true : false;

        _VERBOSE ? console.log("analisis_level_selected: " + _componente_fuente.analisis_level_selected) : _VERBOSE
        var analisis_level_selected = _componente_fuente.analisis_level_selected

        // Falta agregar la condición makesense. 
        // Cuando se realiza una consulta por region seleccioanda se verica que la especie objetivo se encuentre dentro de esta area
        _res_display_module_nicho.refreshData(num_items, val_process, slider_value, min_occ, mapa_prob, rango_fechas, chkFecha, fossil, grid_res, footprint_region, _loadeddata, _datafile_loaded, analisis_level_selected);


    }
    


    /**
     * Método setter para la variable que almacena la URL de la versión del API utilizada
     *
     * @function setUrlApi
     * @public
     * 
     * @param {string} url_api - URL del servidor
     */
    function setUrlApi(url_api) {
        _url_api = url_api
    }

    /**
     * Método setter para la variable que almacena la URL base del frontend
     *
     * @function setUrlFront
     * @public
     * 
     * @param {string} url_front - URL del cliente
     */
    function setUrlFront(url_front) {
        _url_front = url_front
    }

    /**
     * Método setter para la variable que almacena la URL base del frontend para el nicho ecológico
     *
     * @function setUrlNicho
     * @public
     * 
     * @param {string} url_nicho - URL del cliente en nicho ecológico
     */
    function setUrlNicho(url_nicho) {
        _url_nicho = url_nicho;
    }


    // retorna solamente un objeto con los miembros que son públicos.
    return {
        startModule: startModule,
        loadModules: loadModules,
        setUrlApi: setUrlApi,
        setUrlFront: setUrlFront,
        setUrlNicho: setUrlNicho
    };


})();


$(document).ready(function () {

    // _VERBOSE ? console.log(config.url_front) : _VERBOSE
    // _VERBOSE ? console.log(config.url_api) : _VERBOSE
    // _VERBOSE ? console.log(config.url_nicho) : _VERBOSE
    // _VERBOSE ? console.log(config.url_comunidad) : _VERBOSE

    module_nicho.setUrlFront(config.url_front);
    module_nicho.setUrlApi(config.url_api);
    module_nicho.setUrlNicho(config.url_nicho);
    module_nicho.startModule(config.verbose);

});