# Source: histogram_module.js

    /**
     * Módulo histograma, utilizado para crear y gestionar los histogramas en nicho ecológico y comunidad ecológica.
     *
     * @namespace histogram_module
     */
    var histogram_module = (function(verbose) {

        var _VERBOSE = verbose;
        var _table_module_decil, _language_module_nicho;
        var _highlight_color = "#48D7D5";
        var _iTrans;
        var _NUM_DECIL = 10;

        /**
         * Método setter del módulo table.
         *
         * @function setTableModule
         * @public
         * @memberof! histogram_module
         *
         * @param {object} tableModule - Módulo table
         */
        function setTableModule(tableModule) {
            _table_module_decil = tableModule;
        }

        /**
         * Método setter del módulo de internacionalización.
         *
         * @function setLanguageModule
         * @public
         * @memberof! histogram_module
         *
         * @param {object} languageModule - Módulo de internacionalización.
         */
        function setLanguageModule(languageModule) {
            _language_module_nicho = languageModule;
            _iTrans = _language_module_nicho.getI18();
        }

        /**
         * Éste método inicializa variables globales y componentes visuales que son necesarios para la creación de histogramas.
         *
         * @function _initilizeHistogram
         * @private
         * @memberof! histogram_module
         *
         */
        function _initilizeHistogram() {

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

        }

        /**
         * Éste método crea el histograma de score decil del sistema de nicho, genera la interacción de tooltips, genera la interacción con histogramas y genera un line chart cuando el proceso de validación esta activado. Además genera una tabla de información por decil.
         *
         * @function createMultipleBarChart
         * @public
         * @memberof! histogram_module
         *
         * @param {array} json_decil - Array con el resultado de los grupos de vartiables seleccionados por decil
         * @param {array} array_recall - Contiene los resultados por grupo de variables por decil. Contiene verdaderos positivos, falsos negativos y recall. Este array solo es utilizado en el proceso de validación
         * @param {String} idComponent - Id del contenedor del histograma
         * @param {map} nameMap - Mapa de los grupos de variables seleccionados en el análisis de nicho ecológico
         */
        function createMultipleBarChart(json_decil, array_recall, idComponent, nameMap) {

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

            $("#" + idComponent.id).empty();

            var margin = {top: 30, right: 40, bottom: 50, left: 40},
            width = $(".myScrollableBlockEpsilonDecil").width() - margin.left - margin.right,
                    height = $(".myScrollableBlockEpsilonDecil").height() - margin.top - margin.bottom - 15; // 10px del icono de info

            var x0 = d3.scale.ordinal()
                    .rangeRoundBands([0, width], .1);

            var x1 = d3.scale.ordinal();

            var y = d3.scale.linear()
                    .range([height, 0]);

            var color_array = [];

            // variable que sirve para conocer el decil donde ya existen valores prar generar la gráfica
            var value_decil_ready = 0;

            for (value_decil_ready = 0; value_decil_ready < _NUM_DECIL; value_decil_ready++) {
                try {
                    length_names = json_decil[value_decil_ready].names.length;
                    break;
                } catch (e) {
                    _VERBOSE ? console.log("sin valores decil: " + value_decil_ready) : _VERBOSE;
                }
            }

            _VERBOSE ? console.log("value_decil_ready: " + value_decil_ready) : _VERBOSE;
            _VERBOSE ? console.log("length_names: " + length_names) : _VERBOSE;

            for (i = 0; i < length_names; i++) {
                color_array.push(_randomColor());
            }
            // _VERBOSE ? console.log(color_array) : _VERBOSE;

            var color = d3.scale.ordinal()
                    .range(color_array);

            var xAxis = d3.svg.axis()
                    .scale(x0)
                    .orient("bottom");

            var yAxis = d3.svg.axis()
                    .scale(y)
                    .orient("left")
                    .tickFormat(d3.format(".2s"));
            // .ticks(10);

            var svg = d3.select("#" + idComponent.id).append("svg")
                    .attr("width", width + margin.left + margin.right)
                    .attr("height", height + margin.top + margin.bottom)
                    .append("g")
                    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

            svg.append("text")
                    .attr("id", idComponent.legend)
                    .attr("y", -22)
                    .attr("x", width / 2 + 40)
                    .attr("dy", ".71em")
                    .style("font-size", "20px")
                    .style("text-anchor", "end")
                    .text(_iTrans.prop('titulo_hist_score_decil'));

            var tip = d3.tip()
                    .attr('class', 'd3-tip')
                    .offset([-10, 0])
                    .html(function(d) {

                        var_group_label = "<strong>" + d.name.p + "</strong><br/>" +
                                "<strong>" + _iTrans.prop('lb_score_conjunto') + ":</strong> <span >" + parseFloat(d.value.p).toFixed(2) + "</span><br/><br/>" +
                                "<strong>" + _iTrans.prop('lb_conformado') + ":</strong><br/><br/>";

                        d.name.s.forEach(function(item, index) {

                            var_group_label += "<strong>" + _iTrans.prop('lb_grupo') + ":</strong> <span >" + item + "</span><br/>" +
                                    "<strong>" + _iTrans.prop('tip_tbl_score') + ":</strong> <span >" + d.value.s[index] + "</span><br/><br/>"
                        });

                        return  var_group_label;

                    });

            svg.call(tip);

            // nameMap es mayor que 0 cuando se realiza el proceso de validación
            var ageNames = []; //nameMap.values();

            _VERBOSE ? console.log(nameMap) : _VERBOSE;

            json_decil[value_decil_ready].names.forEach(function(name, index) {

                var obj;

                if (nameMap.values().length > 0) {
                    arg_nulos = nameMap.get(name.p).recall_nulo;
                    // _VERBOSE ? console.log(arg_nulos) : _VERBOSE;
                    // si al menos existe un valor calculado de recall (diferente a cero) se realiza el line chart del recall
                    fin_recall = ($.inArray(false, arg_nulos) != -1) ? false : true;
                    _VERBOSE ? console.log("name: " + name.p + " fin_recall: " + fin_recall) : _VERBOSE;

                    obj = {name: name.p, nulos: nameMap.get(name.p).nulos, recall_nulo: fin_recall};
                }
                else {
                    obj = {name: name.p};
                }

                ageNames.push(obj);

            });

            _VERBOSE ? console.log(ageNames) : _VERBOSE;

            json_decil.forEach(function(d, index) {
                // no retorna el objeto json cuando el decil no tiene valores
                if (value_decil_ready <= index) {
                    d.ages = d.names.map(function(name, i) {
                        return {name: name, value: d.values[i], decil: d.decil, species: d.species[i], gridids: d.gridids[i]};
                    });
                }
                // asigna valores falsos a los deciles ausentes
                else {
                    // d.decil_nulo = true;
                    d.ages = json_decil[value_decil_ready].names.map(function(name, i) {
                        return {name: name, value: [], decil: "" + (_NUM_DECIL - index), species: [], gridids: [], decil_nulo: true};
                    });
                }
            });

            _VERBOSE ? console.log(json_decil) : _VERBOSE;

            x0.domain(json_decil.map(function(d) {
                return d.decil;
            }));
            // _VERBOSE ? console.log("x0: " + x0.rangeBand()) : _VERBOSE;
            x1.domain(ageNames.map(function(item, i) {
                return item.name;
            })).rangeRoundBands([0, x0.rangeBand()]);

            totalmax_avg = d3.max(json_decil.map(function(d, index) {
                if (value_decil_ready <= index) {
                    return d3.max(d.values, function(d) {
                        return parseFloat(d.p)
                    });
                }
            }));

            totalmin_avg = d3.min(json_decil.map(function(d, index) {
                if (value_decil_ready <= index) {
                    return d3.min(d.values, function(d) {
                        return parseFloat(d.p)
                    });
                }
            }));

            // que ocurre cuando min y max son iguales, no se esta generando la gráfica... cehcar validacion
            if (totalmax_avg == totalmin_avg) {
                if (totalmax_avg < 0) {
                    totalmax_avg = 0;
                }
                else {
                    totalmin_avg = 0;
                }
            }

            totalmin_nice = Math.floor(totalmin_avg);
            totalmax_nice = Math.ceil(totalmax_avg);

            // TODO: analizar cuando son solo possitovos, solo negativos o combinación
            // solo negativos
            if (totalmax_avg < 0 && totalmin_avg < 0) {
                NEG_DECIL = -1;
            }
            // combinado
            else if (totalmin_avg < 0) {
                NEG_DECIL = 0;
            }
            // solo positivos
            else {
                NEG_DECIL = 1;
            }

            // NOTA: En d3 el max de -0.12 y -0.86 es "-0.86", obtiene el minimo de los negativos
            maxmin_avg = d3.max(json_decil.map(function(d, index) {
                if (value_decil_ready <= index) {
                    return d3.max(d.values, function(d) {
                        if (d.p < 0)
                            return d.p
                    });
                }
            }));

            // si existen valores combinados el axis se divide de forma equitativa
            if (NEG_DECIL == 0) {

                if (Math.abs(totalmin_avg) < Math.abs(totalmax_avg)) {

                    y.domain([-totalmax_avg, totalmax_avg])
                            .nice([totalmin_nice, totalmax_nice]);

                }
                else {

                    y.domain([totalmin_avg, -totalmin_avg])
                            .nice([totalmin_nice, totalmax_nice]);

                }

            }
            else {

                y.domain([totalmin_avg, totalmax_avg])
                        .nice([totalmin_nice, totalmax_nice]);

            }

            // set the x axis in middle of the chart when there are negative values.
            // solo negativos
            if (NEG_DECIL == -1) {

                translate_axis = y(totalmax_avg); // valor de cero, ajusta en la parte superior del histograma
            }
            // combinado
            else if (NEG_DECIL == 0) {

                translate_axis = y(Math.max(0, maxmin_avg)); // ajusta en la parte superior del histograma
            }
            // solo positivos
            else {

                translate_axis = height; // valor maximos, ajusta en la parte inferior del histograma
            }

            svg.append("g")
                    .attr("class", "x axis")
                    .attr("transform", "translate(0," + translate_axis + ")")
                    .call(xAxis)
                    .append("text")
                    .attr("id", idComponent.xaxis)
                    .attr("y", margin.bottom - 10)
                    .attr("x", width / 2)
                    .attr("dy", ".71em")
                    .style("text-anchor", "end")
                    .text(_iTrans.prop('lb_xaxis_decil'));

            svg.append("g")
                    .attr("class", "y axis")
                    .call(yAxis)
                    .append("text")
                    .attr("id", idComponent.yaxis)
                    .attr("y", -10)
                    .attr("x", margin.left - 40)
                    .attr("dy", ".71em")
                    .style("text-anchor", "end")
                    .text(_iTrans.prop('tip_tbl_score'));

            var state = svg.selectAll(".state")
                    .data(json_decil)
                    .enter().append("g")
                    .attr("class", "state")
                    .attr("transform", function(d) {
                        return "translate(" + x0(d.decil) + ",0)";
                    });

            state.selectAll(".rect")
                    .data(function(d) {
                        return d.ages;
                    })
                    .enter().append("rect")
                    .attr("class", "bar")
                    .attr("width", x1.rangeBand())
                    .attr("x", function(d) {

                        // _VERBOSE ? console.log("decil_nulo: " + d.decil_nulo) : _VERBOSE;
                        // _VERBOSE ? console.log(x1(d.name.p)) : _VERBOSE;
                        return x1(d.name.p);
                    })
                    .attr("y", function(d) {

                        _VERBOSE ? console.log("decil_nulo: " + d.decil_nulo) : _VERBOSE;

                        if (d.decil_nulo)
                            return y(0);

                        // locate the bars in the chart correctly when there are negative values.
                        if (NEG_DECIL == -1) {
                            return y(totalmax_avg);
                        }
                        else if (NEG_DECIL == 0) {
                            return y(Math.max(0, d.value.p));
                        }
                        else {
                            return y(d.value.p);
                        }
                    })
                    .attr("height", function(d) {

                        _VERBOSE ? console.log("decil_nulo: " + d.decil_nulo) : _VERBOSE;
                        var val_h = d.decil_nulo ? 0 : d.value.p;

                        // locate the bars in the chart correctly when there are negative values.
                        if (NEG_DECIL == -1) {

                            return Math.abs(y(val_h) - y(totalmax_avg))
                        }
                        else if (NEG_DECIL == 0) {

                            return Math.abs(y(val_h) - y(0))
                        }
                        else {

                            return height - y(val_h);
                        }
                    })
                    .style("fill", function(d) {

                        // _VERBOSE ? console.log(d.name.p) : _VERBOSE;

                        return color(d.name.p);
                    })
                    .style("opacity", 0.7)
                    .on('mouseover', function(d) {

                        tip.show(d);

                    })
                    .on('mouseout', function(d) {

                        tip.hide(d);

                    })
                    .on("click", function(d) {

                        _VERBOSE ? console.log("decil_nulo: " + d.decil_nulo) : _VERBOSE;
                        if (d.decil_nulo)
                            return;

                        // _VERBOSE ? console.log(d.gridids.p) : _VERBOSE;

                        g = d3.select("#grid_map");
                        feature = g.selectAll("path");

                        feature.each(function(cell, i) {

                            if ($.inArray(cell.properties.gridid, d.gridids.p) != -1) {
                                d3.select(this).style("stroke", _highlight_color);
                                d3.select(this).style("stroke-width", 2);
                            } else {
                                d3.select(this).style("stroke", "none");
                                d3.select(this).style("stroke-width", "none");
                            }

                        });

                        state.selectAll("rect.bar").each(function(bar, i) {
                            d3.select(this).style("stroke", "none");
                        });
                        d3.select(this).style("stroke", "black");
                        d3.select(this).style("stroke-width", 3);

                        decil_list = [];
                        d.species.p.forEach(function(sp, index) {

                            // spid, label, epsilon, score, occ(nj), occ_decil
                            params = sp.split("|");
                            // _VERBOSE ? console.log(params) : _VERBOSE;

                            occ = parseFloat(params[4]);
                            occ_decil = parseFloat(params[5])
                            per_decil = parseFloat(occ_decil / occ * 100).toFixed(2) + "%";

                            // console.log(params[1]);
                            // console.log(params[4]);
                            // console.log(params[5]);

                            decil_list.push({decil: d.decil, species: params[1], epsilons: params[2], scores: params[3], occ: per_decil});
                        });

                        // _VERBOSE ? console.log(decil_list) : _VERBOSE;

                        _table_module_decil.createDecilList(decil_list);

                    });

            decil_list = [];
            $.each(json_decil, function(index, value) {

                _VERBOSE ? console.log("decil_nulo: " + value.decil_nulo) : _VERBOSE;
                if (value.decil_nulo)
                    return false;

                value.species[0].p.forEach(function(sp, index) {

                    // spid, label, epsilon, score, occ(nj), occ_decil
                    params = sp.split("|");
                    // _VERBOSE ? console.log(params) : _VERBOSE;

                    // EJEMPLO Panthera leo - occ_total = 2 y occ_decil = 3 => 1.5 => 150% (ERROR)
                    occ_total = parseFloat(params[4]);
                    occ_decil = parseFloat(params[5]);
                    per_decil = parseFloat(occ_decil / occ_total * 100).toFixed(2) + "%";

                    decil_list.push({decil: value.decil, species: params[1], epsilons: params[2], scores: params[3], occ: per_decil});
                });

                return false;
            });

            _table_module_decil.createDecilList(decil_list);

            /***************** rect legend */
            var yTextPadding = -5;

            state.selectAll(".rect")
                    .data(function(d) {
                        return d.ages;
                    })
                    .enter()
                    .append("text")
                    .style("font-size", "8px")
                    .attr("text-anchor", "middle")
                    .attr("fill", "black")
                    .attr("x", function(d, i) {
                        return x1(d.name.p) + 10;
                    })
                    .attr("y", function(d, i) {

                        if (d.decil_nulo)
                            return y(0) + yTextPadding;
                        // locate the bars in the chart correctly when there are negative values.
                        if (NEG_DECIL == -1) {
                            return y(totalmax_avg) + yTextPadding;
                        }
                        else if (NEG_DECIL == 0) {
                            return y(Math.max(0, d.value.p)) + yTextPadding;
                        }
                        else {
                            return y(d.value.p) + yTextPadding;
                        }

                    })
                    .text(function(d) {
                        // // console.log(d);
                        // if( parseFloat(d.value.p) == 0.0)
                        // 	return "";
                        // else
                        return d.value.p;
                    });

            var legend = svg.selectAll(".legend")
                    .data(ageNames.slice().reverse())
                    .enter().append("g")
                    .attr("class", "legend")
                    .attr("transform", function(d, i) {
                        return "translate(0," + (height + 20) + ")";
                    });

            legend.append("rect")
                    .attr("x", function(d, i) {
                        return (width - 18) - (i * 130);
                    })
                    .attr("y", 3)
                    .attr("width", 20)
                    .attr("height", 20)
                    .style("fill", function(d, i) {

                        if (d.recall_nulo) {
                            return "black";
                        }
                        else {
                            return color(d.name);
                        }

                    })
                    .style("opacity", 0.7);

            legend.append("text")
                    .attr("x", function(d, i) {
                        return (width - 24) - (i * 130);
                    })
                    .attr("y", 9)
                    .attr("dy", ".35em")
                    .style("text-anchor", "end")
                    .text(function(d) {
                        return d.name;
                    });

            if (nameMap.values().length > 0) {

                legend.append("text")
                        .attr("x", function(d, i) {
                            return (width - 24) - (i * 130);
                        })
                        .attr("y", 20)
                        .attr("dy", ".35em")
                        .style("text-anchor", "end")
                        .text(function(d) {
                            _VERBOSE ? console.log(d.recall_nulo) : _VERBOSE;

                            prom = 0;
                            $.each(d.nulos, function() {
                                prom += this;
                            });

                            if (d.recall_nulo) {
                                _VERBOSE ? console.log("aplica recall nulo") : _VERBOSE;

                                return _iTrans.prop('recall_nulo');
                            }
                            else {
                                return _iTrans.prop('lb_nulos') + ": " + parseFloat(prom / d.nulos.length).toFixed(2);
                            }

                        });

            }

            if ($("#chkValidation").is(':checked')) {

                var tip_recall = d3.tip()
                        .attr('class', 'd3-tip')
                        .offset([-10, 0])
                        .html(function(d) {
                            recall_values = "<strong>" + _iTrans.prop('lb_recall_avg') + ":</strong> <span >" + parseFloat(d.recall * 100).toFixed(2) + "%</span><br/><br/>" +
                                    "<strong>" + _iTrans.prop('lb_vp_avg') + ":</strong> <span >" + parseFloat(d.vp).toFixed(2) + "</span><br/>" +
                                    "<strong>" + _iTrans.prop('lb_fn_avg') + ":</strong> <span >" + parseFloat(d.fn).toFixed(2) + "</span><br/>";
                            // "<strong>CSS prom:</strong> <span >" + parseFloat(d.ausentes).toFixed(2) + "%</span><br/>"
                            return  recall_values;
                        });

                svg.call(tip_recall);

                var y_right = d3.scale.linear()
                        .range([translate_axis, 0]);

                y_right.domain([0, 1]);

                var yRightAxis = d3.svg.axis()
                        .scale(y_right)
                        .orient("right")
                        .ticks(5, "%");

                // ** si el label cambia, es necesario agregar id **
                svg.append("g")
                        .attr("class", "y axis")
                        .attr("transform", "translate(" + width + " ,0)")
                        .call(yRightAxis)
                        .append("text")
                        .attr("y", -10)
                        .attr("x", margin.right - 40)
                        .attr("dy", ".71em")
                        .style("text-anchor", "end")
                        .text(_iTrans.prop('lb_recall'));

                // adding recall line
                _VERBOSE ? console.log(array_recall) : _VERBOSE;

                $.each(array_recall, function(i, recall_item) {

                    var line = d3.svg.line()
                            .x(function(d, i) {
                                // _VERBOSE ? console.log("movement: " + x1.rangeBand() * (ageNames.length/2)) : _VERBOSE;
                                // _VERBOSE ? console.log("x0: " + x0(array_recall.length - i) + x1.rangeBand()) : _VERBOSE;
                                // (x1.rangeBand() * (ageNames.length/2)) ---> Moves the line to the center of the bars
                                return x0(recall_item.length - i) + (x1.rangeBand() * (ageNames.length / 2));
                            })
                            .y(function(d) {
                                // _VERBOSE ? console.log("y: " + y_right(d.recall)) : _VERBOSE;
                                return y_right(d.recall);
                            });

                    svg.append("path")
                            .datum(recall_item)
                            .attr("class", "line")
                            .attr("d", line)
                            .style("stroke", function(d) {
                                // _VERBOSE ? console.log(color(d[0].group_name)) : _VERBOSE;

                                // _VERBOSE ? console.log( nameMap.get(d[0].group_name.name).recall_nulo ) : _VERBOSE;

                                if ($.inArray(false, nameMap.get(d[0].group_name.name).recall_nulo) != -1) {
                                    return color(d[0].group_name.name);
                                }
                                else {
                                    return "none";
                                }

                            })

                    svg.selectAll("dot")
                            .data(recall_item)
                            .enter().append("circle")
                            .attr("class", "dot")
                            .attr("r", 3.5)
                            .attr("cx", function(d, i) {
                                return x0(recall_item.length - i) + (x1.rangeBand() * (ageNames.length / 2));
                            })
                            .attr("cy", function(d) {
                                return y_right(d.recall);
                            })
                            .on('mouseover', function(d) {

                                d3.select(this).attr("r", function(d) {
                                    return 8 + Math.pow(d.recall / Math.PI, 0.5);
                                });
                                tip_recall.show(d)
                            })
                            .on('mouseout', function(d) {

                                d3.select(this).attr("r", function(d) {
                                    return 3.5;
                                });
                                tip_recall.hide(d)
                            })
                            .style("stroke", function(d) {

                                // _VERBOSE ? console.log( nameMap.get(d.group_name.name).recall_nulo ) : _VERBOSE;

                                if ($.inArray(false, nameMap.get(d.group_name.name).recall_nulo) != -1) {
                                    return color(d.group_name.name);
                                }
                                else {
                                    return "none";
                                }

                            })

                });

            }

        }

        /**
         * Éste método crea el histograma de las ocurrencias que tiene la especie objetivo selecionada en el análisis de nicho ecológico.
         *
         * @function createBarChartFecha
         * @public
         * @memberof! histogram_module
         *
         * @param {array} distinctPoints - Array con las ocurrencias que tiene la especie objetivo selecionada en el análisis de nicho ecológico.
         */
        function createBarChartFecha(distinctPoints) {

            var puntos_json = d3.map([]);

            $.each(distinctPoints, function(index, item) {

                fecha_ano = item.fechacolecta == null || item.fechacolecta.split("-")[0] == "" ? 0 : parseInt(item.fechacolecta.split("-")[0]);

                if (puntos_json.has(fecha_ano)) {

                    var item_colecta = puntos_json.get(fecha_ano);
                    puntos_json.set(fecha_ano, {"fechacolecta": fecha_ano, "cantidad": (item_colecta.cantidad + 1)});

                }
                else {

                    puntos_json.set(fecha_ano, {"fechacolecta": fecha_ano, "cantidad": 1});

                }

            });

            var colectas = puntos_json.values();
            var colectas_zero = [];
            var colectas_dif = [];
            $.each(colectas, function(index, item) {

                if (item.fechacolecta > 0) {
                    colectas_dif.push(item);
                }
                else {
                    colectas_zero.push(item);
                }

            })

            // VERIFICAR SI SE PUEDEN DESPLEGAR LOS REGISTROS SIN FECHA
            // if(colectas_zero.length == 0){
            // 	$("#lb_regfecha").text("0");
            // }
            // else{
            // 	$("#lb_regfecha").text(colectas_zero[0].cantidad);
            // }

            var max_fecha = d3.max(colectas_dif.map(function(d) {
                return d.fechacolecta;
            }));
            var min_fecha = d3.min(colectas_dif.map(function(d) {
                return d.fechacolecta;
            }));

            var NUM_BARS = d3.range(1, 11, 1);

            var rangofechas = d3.scale.quantize().domain([min_fecha, max_fecha]).range(NUM_BARS);

            var rango_fechas = d3.map([]);
            $.each(NUM_BARS, function(index, item) {

                var rango = parseInt(rangofechas.invertExtent(item)[0]) + " - " + parseInt(rangofechas.invertExtent(item)[1]);
                rango_fechas.set(item, {"fechas": rango, "cantidad": 0});

            })

            $.each(colectas_dif, function(index, item) {

                if (rango_fechas.has(rangofechas(item.fechacolecta))) {

                    var it_temp = rango_fechas.get(rangofechas(item.fechacolecta));
                    it_temp.cantidad = it_temp.cantidad + item.cantidad;

                }

            });

            var data = rango_fechas.values();

            $("#hist_fecha_container").empty();

            var margin = {top: 10, right: 10, bottom: 20, left: 30},
            width = $("#hist_fecha_container").width() - margin.left - margin.right,
                    height = $("#hist_fecha_container").height() - margin.top - margin.bottom;

            var x = d3.scale.ordinal()
                    .rangeRoundBands([0, width], .1);

            var y = d3.scale.linear()
                    .range([height, 0]);

            x.domain(data.map(function(d) {
                return d.fechas;
            }));
            y.domain([0, d3.max(data, function(d) {
                    return d.cantidad;
                })]);

            var xAxis = d3.svg.axis()
                    .scale(x)
                    .orient("bottom");

            var yAxis = d3.svg.axis()
                    .scale(y)
                    // .ticks(10)
                    // .tickSize(-width, 0)
                    .orient("left");

            var svg = d3.select("#hist_fecha_container").append("svg")
                    .attr("width", width + margin.left + margin.right)
                    .attr("height", height + margin.top + margin.bottom)
                    .append("g")
                    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

            var tip = d3.tip()
                    .attr('class', 'd3-tip')
                    .offset([-10, 10])
                    .html(function(d) {
                        return  "<strong>Fechas:</strong> <span >" + d.fechas + "</span><br/>" +
                                "<strong>Registros:</strong> <span >" + d.cantidad + "</span>";
                    });
            svg.call(tip);

            svg.append("g")
                    .attr("class", "xaxis")
                    .attr("transform", "translate(0," + height + ")")
                    .call(xAxis)
                    // .text("Fecha colecta")
                    .selectAll("text")
                    .style("font-size", "0px")

            svg.append("g")
                    .attr("class", "yaxis")
                    .call(yAxis)
                    // .ticks(5);
                    // .text("Registros")
                    .selectAll("text")
                    .style("font-size", "8px")

            svg.selectAll(".bar")
                    .data(data)
                    .enter().append("rect")
                    .attr("class", "bar")
                    .attr("x", function(d) {
                        return x(d.fechas);
                    })
                    .attr("y", function(d) {
                        return y(d.cantidad);
                    })
                    .attr("height", function(d) {
                        return height - y(d.cantidad);
                    })
                    .attr("width", x.rangeBand())
                    .on("mouseover", function(d) {
                        tip.show(d);
                    })
                    .on("mouseout", function(d) {
                        tip.hide(d);
                    });

        }

        /**
         * Crea los histogramas de épsilon especie, score especie y score celda en el análisis de nicho ecológico.
         *
         * @function createBarChart
         * @public
         * @memberof! histogram_module
         *
         * @param {String} idComponent - Id del contenedor del histograma
         * @param {array} data - Array con los resultados del histograma por especie y por celda en el análisis de nicho ecológico
         * @param {String} f_legend - Título del histograma
         */
        function createBarChart(idComponent, data, f_legend) {

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

            $("#" + idComponent.id).empty();
            // _VERBOSE ? console.log($(window).width()) : _VERBOSE;
            // _VERBOSE ? console.log($(".myScrollableBlockEpsilon").height()) : _VERBOSE;

            var margin = {top: 30, right: 40, bottom: 60, left: 40},
            width = $(".myScrollableBlockEpsilonSmallHist").width() - margin.left - margin.right,
                    height = $(".myScrollableBlockEpsilonSmallHist").height() - margin.top - margin.bottom;

            // _VERBOSE ? console.log(width) : _VERBOSE;
            // _VERBOSE ? console.log(height) : _VERBOSE;

            var x = d3.scale.ordinal()
                    .rangeRoundBands([0, width], .1);

            var y = d3.scale.linear()
                    .range([height, 0]);

            var xAxis = d3.svg.axis()
                    .scale(x)
                    .orient("bottom");
            // .ticks(5);

            var yAxis = d3.svg.axis()
                    .scale(y)
                    .orient("left")
                    .ticks(10, "%");

            var svg = d3.select("#" + idComponent.id).append("svg")
                    .attr("width", width + margin.left + margin.right)
                    .attr("height", height + margin.top + margin.bottom)
                    .append("g")
                    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

            svg.append("text")
                    .attr("id", idComponent.legend)
                    .attr("y", -22)
                    .attr("x", width / 2 + 60)
                    .attr("dy", ".71em")
                    .style("font-size", "20px")
                    .style("text-anchor", "end")
                    .text(f_legend);

            // svg.append("rect")
            //   	.attr("y", -22)
            //     	.attr("x", width/2 + 70)
            //     	.attr("width", "20px")
            //     	.attr("height", "20px")
            //     	.attr("fill", "#3B6A93")
            //     	.append("title")
            //     		.text("test")
            //     	.style("margin-left", "20px")
            // svg.append("text")
            //   	.attr("y", -8)
            //     	.attr("x", width/2 + 77)
            //     	.style("fontColor","white")
            //     	.style("fontWeight","bold")
            //   	.text("?")

            var tip = d3.tip()
                    .attr('class', 'd3-tip')
                    .offset([-10, 0])
                    .html(function(d) {
                        return  "<strong>" + _iTrans.prop('lb_rango') + ":</strong> <span >" + d.title + "</span><br/><br/>" +
                                "<strong>" + _iTrans.prop('lb_frecuencia') + ":</strong> <span >" + parseInt(d.frequency * 100) + " %</span>";
                    });

            svg.call(tip);

            x.domain(data.map(function(d) {
                return d.bcenter;
            }));

            max_freq = d3.max(data.map(function(d) {
                return parseFloat(d.frequency);
            }));
            // _VERBOSE ? console.log(max_freq) : _VERBOSE;

            y.domain([0, max_freq]);

            svg.append("g")
                    .attr("class", "xaxis")
                    .attr("transform", "translate(0," + height + ")")
                    .call(xAxis)
                    .selectAll("text")
                    .attr("id", idComponent.xaxis)
                    .style("text-anchor", "end")
                    .style("font-size", "10px")
                    .attr("dx", "-.8em")
                    .attr("dy", "-.55em")
                    .attr("transform", function(d) {
                        return "rotate(-90)"
                    });
            // .append("text")
            //   .attr("y", margin.bottom-10)
            //   .attr("x", width/2)
            //   .attr("dy", ".71em")
            //   .style("text-anchor", "end")
            //   .text(legend);

            svg.append("g")
                    .attr("class", "yaxis")
                    .call(yAxis)
                    .append("text")
                    .attr("id", idComponent.yaxis)
                    .attr("transform", "rotate(-90)")
                    .attr("y", 6)
                    .attr("dy", ".71em")
                    .style("text-anchor", "end")
                    .text(_iTrans.prop('lb_frecuencia'));

            svg.selectAll(".bar")
                    .data(data)
                    .enter().append("rect")
                    .attr("class", "bar")
                    .attr("x", function(d) {
                        return x(d.bcenter);
                    })
                    .attr("width", x.rangeBand())
                    .attr("y", function(d) {
                        return y(parseFloat(d.frequency));
                    })
                    .attr("height", function(d) {
                        return height - y(parseFloat(d.frequency));
                    })

                    .on('mouseover', function(d) {
                        tip.show(d)
                    })
                    .on('mouseout', function(d) {
                        tip.hide(d)
                    })

        }

        /**
         * Genera colores aleatorios para asignarlo al histograma de decil en el análisis de nicho ecológico.
         *
         * @function _randomColor
         * @private
         * @memberof! histogram_module
         *
         */
        var _randomColor = (function() {
            var golden_ratio_conjugate = 0.618033988749895;
            var h = Math.random();

            var hslToRgb = function(h, s, l) {
                var r, g, b;

                if (s == 0) {
                    r = g = b = l; // achromatic
                } else {
                    function hue2rgb(p, q, t) {
                        if (t < 0)
                            t += 1;
                        if (t > 1)
                            t -= 1;
                        if (t < 1 / 6)
                            return p + (q - p) * 6 * t;
                        if (t < 1 / 2)
                            return q;
                        if (t < 2 / 3)
                            return p + (q - p) * (2 / 3 - t) * 6;
                        return p;
                    }

                    var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
                    var p = 2 * l - q;
                    r = hue2rgb(p, q, h + 1 / 3);
                    g = hue2rgb(p, q, h);
                    b = hue2rgb(p, q, h - 1 / 3);
                }

                return '#' + Math.round(r * 255).toString(16) + Math.round(g * 255).toString(16) + Math.round(b * 255).toString(16);
            };

            return function() {
                h += golden_ratio_conjugate;
                h %= 1;
                return hslToRgb(h, 0.5, 0.60);
            };
        })();

        /**
         * Retorna un objeto de tipo Chart para generar el histograma en el anáisis de comunidad ecológica.
         *
         * @function createBarChartNet
         * @public
         * @memberof! histogram_module
         *
         * @param {json} json - Json que contiene los nodos y los enlaces resultado del análisis de communidad ecológica
         * @param {object} display_obj - Referencia al controlador de comunidad ecológica
         */
        function createBarChartNet(json, display_obj) {

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

            var chart_array = [
                BarChart(json, display_obj)
                        .group(display_obj.group_eps_freq)
                        .x(display_obj.x)
            ];

            var chart_component = d3.selectAll(".chart")
                    .data(chart_array)
                    .each(function(chart) {
                        chart.on("brushend", display_obj.renderAll);
                    });

            $("#lb_body_info").text(_iTrans.prop('lb_msg_hist_epsilon'));
            $('#lb_header_info').text(_iTrans.prop('titulo_hist_eps'));

            return chart_component;

        }

        /**
         * Clase tipo Chart para generar instacias que tienen interacción con el módulo de red.
         *
         * @function BarChart
         * @public
         * @memberof! histogram_module
         *
         * @param {json} json - Json que contiene los nodos y los enlaces resultado del análisis de communidad ecológica
         * @param {object} display_obj - Referencia al controlador de comunidad ecológica
         */
        function BarChart(json, display_obj) {

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

            var margin = {top: 5, right: 20, bottom: 55, left: 20};
            var width = $("#hist").width() - margin.left - margin.right;
            var height = $("#hist").height() - margin.top - margin.bottom;

            if (!BarChart.id)
                BarChart.id = 0;

            var y = d3.scale.linear()
                    .range([100, 0]);
            // .domain([0, max_eps]);

            var x = d3.scale.ordinal()
                    .rangeRoundBands([margin.left, width - margin.left], .1);

            var xAxis = d3.svg.axis()
                    .scale(x)
                    .orient("bottom");

            var yAxis = d3.svg.axis()
                    .scale(y)
                    .orient("left")
                    .ticks(5, "%");

            var id = BarChart.id++,
                    brush = d3.svg.brush(),
                    brushDirty, dimension, group, round;
            //margin = {top: 10, right: 10, bottom: 20, left: 10}
            var brushStart = 0;
            var brushEnd = display_obj.NUM_BEANS - 1;

            function chart(div) {

                height = y.range()[0];
                data = group.all();

                // it contains an array from 1 to 20, create key missing elements and set value to 0
                display_obj.epsilon_beans.forEach(function(d) {
                    exists = false;
                    $.each(data, function(index, value) {
                        if (d == value.key) {
                            exists = true;
                            return false;
                        }
                    });
                    if (exists == false) {
                        data.push({key: parseInt(d), value: 0});
                    }
                });

                // Sort by price high to low
                data.sort(_sort_by('key', false, parseInt));
                _VERBOSE ? console.log(data) : _VERBOSE;

                $.each(data, function(index, value) {

                    tvalue = value.value;

                    if (tvalue != 0)
                        value.value = tvalue / all.reduceCount().value();

                });

                _VERBOSE ? console.log(display_obj.epsRange) : _VERBOSE;
                _VERBOSE ? console.log(epsRange) : _VERBOSE;

                x.domain(data.map(function(d) {
                    avg = parseFloat((display_obj.epsRange.invertExtent(d.key)[0] + display_obj.epsRange.invertExtent(d.key)[1]) / 2).toFixed(2);
                    return avg;
                }));

                y.domain([0, group.top(1)[0].value]);

                div.each(function() {

                    _VERBOSE ? console.log("div.each chart") : _VERBOSE;

                    var div = d3.select(this),
                            g = div.select("g");

                    // Create the skeletal chart.
                    if (g.empty()) {

                        _VERBOSE ? console.log("g.empty") : _VERBOSE;

                        g = div.append("svg")
                                .attr("width", width + margin.left + margin.right)
                                .attr("height", height + margin.top + margin.bottom)
                                .append("g")
                                .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

                        // legend
                        g.append("text")
                                .attr("id", "title_barnet")
                                .attr("y", height + 40)
                                .attr("x", width / 2 + 60)
                                .attr("dy", ".71em")
                                .style("font-size", "12px")
                                .style("text-anchor", "end")
                                .text(_iTrans.prop('titulo_hist_eps'));

                        g.append("clipPath")
                                .attr("id", "clip-" + id)
                                .append("rect")
                                .attr("width", width)
                                .attr("height", height);

                        g.selectAll(".foreground.bar")
                                .attr("clip-path", "url(#clip-" + id + ")");

                        // **** Axis

                        g.append("g")
                                .attr("class", "axis")
                                .attr("transform", "translate(0," + height + ")")
                                .call(xAxis)
                                .selectAll("text")
                                .style("text-anchor", "end")
                                .style("font-size", "10px")
                                .attr("dx", "-.8em")
                                .attr("dy", "-.55em")
                                .attr("transform", function(d) {
                                    return "rotate(-90)"
                                });

                        g.append("g")
                                .attr("class", "axis")
                                .attr("transform", "translate(" + margin.left + ",0)")
                                .call(yAxis)
                                .append("text")
                                .attr("id", 'yaxis_net')
                                .attr("transform", "rotate(-90)")
                                .attr("y", 6)
                                .attr("dy", ".71em")
                                .style("text-anchor", "end")
                                .text(_iTrans.prop('lb_frecuencia'));

                        // ** Adding bars

                        g.selectAll(".bar")
                                .data(data)
                                .enter().append("rect")
                                .attr("class", "bar")
                                .attr("x", function(d) {
                                    // _VERBOSE ? console.log(d) : _VERBOSE;
                                    return x(parseFloat((display_obj.epsRange.invertExtent(d.key)[0] + display_obj.epsRange.invertExtent(d.key)[1]) / 2).toFixed(2));
                                })
                                .attr("width", x.rangeBand())
                                .attr("y", function(d) {
                                    return y(parseFloat(d.value));
                                })
                                .attr("height", function(d) {
                                    return height - y(parseFloat(d.value));
                                })
                                .attr("fill", function(d) {

                                    left = display_obj.epsRange.invertExtent(d.key)[0]
                                    right = display_obj.epsRange.invertExtent(d.key)[1]
                                    if (left <= 0 && right > 0)
                                        min_val = 0;
                                    else {
                                        min_val = Math.min(Math.abs(left), Math.abs(right));
                                    }

                                    if (display_obj.ep_th < min_val) {
                                        return d3.rgb(102, 184, 243);
                                        // return "steelblue";
                                    }
                                    else {
                                        return d3.rgb(213, 215, 223);
                                    }
                                });

                        // **** Initialize the brush component with pretty resize handles.
                        var gBrush = g.append("g")
                                .attr("class", "brush")
                                .call(brush);

                        gBrush.selectAll("rect")
                                .attr("height", height);

                        gBrush.selectAll(".resize")
                                .append("path")
                                .attr("d", resizePath);

                    }

                });

                function resizePath(d) {

                    _VERBOSE ? console.log("resizePath") : _VERBOSE;
                    // configure the values of the extent component, clips and shadow selection

                    var e = +(d == "e"),
                            x = e ? 1 : -1,
                            y = height / 3;

                    return "M" + (.5 * x) + "," + y
                            + "A6,6 0 0 " + e + " " + (6.5 * x) + "," + (y + 6)
                            + "V" + (2 * y - 6)
                            + "A6,6 0 0 " + e + " " + (.5 * x) + "," + (2 * y)
                            + "Z"
                            + "M" + (2.5 * x) + "," + (y + 8)
                            + "V" + (2 * y - 8)
                            + "M" + (4.5 * x) + "," + (y + 8)
                            + "V" + (2 * y - 8);
                }

            } // function chart(div) closed

            brush.on("brush.chart", function(e) {

                _VERBOSE ? console.log("brush.chart") : _VERBOSE;

                var y = d3.scale.linear()
                        .domain([margin.left, width - margin.left])
                        .range([0, display_obj.NUM_BEANS]);

                b = brush.extent();
                // _VERBOSE ? console.log(b) : _VERBOSE;

                // d3.round(y(b[1], 0) for rounded values
                var localBrushStart = (brush.empty()) ? brushStart : y(b[0]),
                        localBrushEnd = (brush.empty()) ? brushEnd : y(b[1]);

                // Snap to rect edge
                d3.select("g.brush").call((brush.empty()) ? brush.clear() : brush.extent([y.invert(localBrushStart), y.invert(localBrushEnd)]));

                // Fade all years in the histogram not within the brush
                d3.selectAll("rect.bar").style("opacity", function(d, i) {
                    // _VERBOSE ? console.log(d.key) : _VERBOSE;

                    if (d.key < localBrushStart || d.key >= localBrushEnd || brush.empty()) {
                        return "0.4";
                    }
                    else {
                        return "1";
                    }
                });

                // dimension.filterRange([localBrushStart,localBrushEnd]);

            });

            brush.on("brushend.chart", function() {

                _VERBOSE ? console.log("brushend.chart") : _VERBOSE;

                var y = d3.scale.linear()
                        .domain([margin.left, width - margin.left])
                        .range([0, display_obj.NUM_BEANS]);

                b = brush.extent();

                var localBrushStart = (brush.empty()) ? brushStart : y(b[0]),
                        localBrushEnd = (brush.empty()) ? brushEnd : y(b[1]);

                // Snap to rect edge
                d3.select("g.brush").call((brush.empty()) ? brush.clear() : brush.extent([y.invert(localBrushStart), y.invert(localBrushEnd)]));

                if (brush.empty()) {

                    dim_eps_freq.filterAll();

                    d3.selectAll("rect.bar").style("opacity", function(d, i) {
                        return "1";
                    });

                }
                else {

                    if (d3.round(localBrushStart, 0) == 0)
                        left_extent = 1
                    else
                        left_extent = d3.round(localBrushStart, 0)
                    if (d3.round(localBrushEnd, 0) == 21)
                        rigth_extent = 20
                    else
                        rigth_extent = d3.round(localBrushEnd, 0)

                    _VERBOSE ? console.log(display_obj.epsRange.invertExtent(left_extent)) : _VERBOSE;
                    _VERBOSE ? console.log(display_obj.epsRange.invertExtent(rigth_extent)) : _VERBOSE;

                    display_obj.dim_eps_freq.filterFunction(function(d) {
                        // _VERBOSE ? console.log(d) : _VERBOSE;

                        if (d > display_obj.epsRange.invertExtent(left_extent)[0] && d < display_obj.epsRange.invertExtent(rigth_extent)[1] + 0.1)
                            return true;

                    });

                    // Fade all years in the histogram not within the brush
                    d3.selectAll("rect.bar").style("opacity", function(d, i) {
                        if (d.key < localBrushStart || d.key > localBrushEnd) {
                            return "0.4";
                        }
                        else {
                            return "1";
                        }
                    });

                }

                // d3.event.sourceEvent.stopPropagation();

            });

            chart.margin = function(_) {

                _VERBOSE ? console.log("chart.margin") : _VERBOSE;

                if (!arguments.length)
                    return margin;
                margin = _;
                return chart;
            };

            chart.x = function(_) {

                _VERBOSE ? console.log("chart.x") : _VERBOSE;

                if (!arguments.length)
                    return x;

                x = _;

                xAxis.scale(x);
                brush.x(x);
                return chart;
            };

            chart.y = function(_) {

                _VERBOSE ? console.log("chart.y") : _VERBOSE;

                if (!arguments.length)
                    return y;
                y = _;
                return chart;
            };

            chart.dimension = function(_) {

                _VERBOSE ? console.log("chart.dimension") : _VERBOSE;
                // _VERBOSE ? console.log(_) : _VERBOSE;

                if (!arguments.length)
                    return dimension;
                dimension = _;
                return chart;
            };

            chart.filter = function(_) {

                _VERBOSE ? console.log("chart.filter") : _VERBOSE;

                if (_) {
                    brush.extent(_);
                    dimension.filterRange(_);
                } else {
                    brush.clear();
                    dimension.filterAll();
                }
                brushDirty = true;
                return chart;
            };

            chart.group = function(_) {

                _VERBOSE ? console.log("chart.group") : _VERBOSE;
                // _VERBOSE ? console.log(_) : _VERBOSE;

                if (!arguments.length)
                    return group;
                group = _;
                return chart;
            };

            chart.round = function(_) {

                _VERBOSE ? console.log("chart.round") : _VERBOSE;

                if (!arguments.length)
                    return round;
                round = _;
                return chart;
            };

            return d3.rebind(chart, brush, "on");
        }

        /**
         * Realiza el ordenamiento de un objeto tipo Json por un atributo específico.
         *
         * @function _sort_by
         * @private
         * @memberof! histogram_module
         *
         * @param {String} field - Nombre del parámetro para hacer el ordenamiento
         * @param {boolean} reverse - Bandera para hacer el ordenameinto descendiente o ascendente
         * @param {function} primer - Función para realizar el ordenamiento
         */
        function _sort_by(field, reverse, primer) {

            var key = primer ?
                    function(x) {
                        return primer(x[field])
                    } :
                    function(x) {
                        return x[field]
                    };

            reverse = !reverse ? 1 : -1;

            return function(a, b) {
                return a = key(a), b = key(b), reverse * ((a > b) - (b > a));
            }
        }

        /**
         * Función que inicializa las variables necesarias para la creación de histogramas.
         *
         * @function startHistogramModule
         * @public
         * @memberof! histogram_module
         *
         */
        function startHistogramModule() {
            _VERBOSE ? console.log("startHistogramModule") : _VERBOSE;
            _initilizeHistogram();
        }

        // Añadir los miembros públicos
        return{
            startHistogramModule: startHistogramModule,
            createMultipleBarChart: createMultipleBarChart,
            setTableModule: setTableModule,
            setLanguageModule: setLanguageModule,
            // updateLabels: updateLabels,
            createBarChart: createBarChart,
            createBarChartNet: createBarChartNet,
            createBarChartFecha: createBarChartFecha
        }

    });