﻿(function ($) {

    $.widget("ui.combobox", $.ui.autocomplete,
        {
            options: {
                // Valores por defecto
                minLength: 1,
                autoFocus: true,
                /* the argument to pass to ajax to get the complete list */
                ajaxGetAll: { get: "all" }
            },

            // Contructor de la clase
            _create: function () {
                if (this.element.is("SELECT")) {
                    this._selectInit();
                    return;
                }

                $.ui.autocomplete.prototype._create.call(this);

                // Creamos el nuevo botonJQuery
                var input = this.element;
                input.addClass("ui-widget ui-widget-content ui-corner-left");
                var idTemp = input.attr("id").substring(input.attr('id').indexOf("_") + 1);
                this.button = $("<button id = 'button_" + idTemp + "' type='button'>&nbsp;</button>")
                .attr("tabIndex", -1)
                .appendTo("#tdButton_" + idTemp)
                .button({
                    icons: { primary: "ui-icon-triangle-1-s" },
                    text: false
                })
                .removeClass("ui-corner-all")
                .addClass("ui-corner-right ui-button-icon")

                // Evento Click del boton del nuevo ComboJQuery
                .click(function () {

                    // Si no viene definido la propiedad isFullMenu ignoramos el evento click
                    if (input.isFullMenu != undefined) {
                        if (input.data("combobox").menu.element != null) {

                            // Cerramos la lista de elementos si esta visible
                            if (input.combobox("widget").is(":visible")) {
                                input.combobox("close");
                                return;
                            }

                            // when user clicks the show all button, we display the cached full menu
                            var data = input.data("combobox");
                            clearTimeout(data.closing);
                            if (!input.isFullMenu) {
                                data._swapMenu();
                                input.isFullMenu = true;
                            }

                            // La lista que contiene los elementos esta oculta en un principio, 
                            // la mostramos y mas adelante asignaremos la posición
                            input.combobox("widget").css("display", "block")
                            .position($.extend({ of: input },
                                data.options.position
                                ));
                            input.css("position", "static");
                            input.focus();
                            data._trigger("open");
                        }
                    }
                });

                // Para manejar mejor las listas largas de elementos ponemos en cola los procesos secuencialmente
                $(document).queue(function () {
                    var data = input.data("combobox");
                    if ($.isArray(data.options.source)) {
                        $.ui.combobox.prototype._renderFullMenu.call(data, data.options.source);
                    }
                });
            },

            // Función que inicializa la lista completa de elementos, se llamara cada vez que el usuario pulse el nuevo botonJQuery
            _renderFullMenu: function (source) {
                var self = this,
                input = this.element,
                ul = input.data("combobox").menu.element,
                lis = [];

                if (ul != null) {
                    var hasta = 0;
                    source = this._normalize(source);
                    input.data("combobox").menuAll = input.data("combobox").menu.element.clone(true).appendTo("body");

                    // Generamos cada uno de los elementos que contendra la lista
                    var loopEnd = 50;

                    if (this.options.numeroElementos != null) {
                        loopEnd = this.options.numeroElementos;
                    }

                    for (var i = 0; i < loopEnd; i++) {
                        if (source[i] != null) {
                            lis[i] = "<li class=\"ui-menu-item\" role=\"menuitem\"><a class=\"ui-corner-all\" tabindex=\"-1\">" + source[i].label + "</a></li>";
                        }
                    }
                    if (lis.length != 0)
                        lis[loopEnd] = "<li class=\"ui-menu-item-info\"><a class=\"ui-corner-all\" tabindex=\"-1\">Escriba para buscar otros elementos</a></li>";

                    ul.addClass("ulCombo");
                    var theWidth = input.width() + 20;
                    ul.attr("style", "width: " + theWidth + "px;")
                    ul.append(lis.join(""));
                    ul.hide();
                    this._resizeMenu();

                    // Configuramos el resto de datos y sus eventos
                    setTimeout(function () {
                        self._setupMenuItem.call(self, ul.children("li"), source);
                    }, 0);

                    input.isFullMenu = true;
                }
                else {
                    return false;
                }
            },

            // Función que configura los elementos de la lista (datos y eventos)
            _setupMenuItem: function (items, source) {
                var self = this,
                itemsChunk = items.splice(0, 50),
                sourceChunk = source.splice(0, 50);

                for (var i = 0; i < itemsChunk.length; i++) {
                    if ($(itemsChunk[i]).data("item.autocomplete", sourceChunk[i]) != null) {
                        $(itemsChunk[i]).data("item.autocomplete", sourceChunk[i]).mouseenter(function (event) {
                            self.menu.activate(event, $(this));
                        }).mouseleave(function () {
                            self.menu.deactivate();
                        });
                    }
                }

                if (items.length > 0) {
                    setTimeout(function () {
                        self._setupMenuItem.call(self, items, source);
                    }, 0);
                } else {
                    // redirigimos al siguiente proceso que este esperando en la cola
                    $(document).dequeue();
                }
            },

            // Función para marcar en negrita las letras encontradas en los elementos de la lista
            //
            _renderItem: function (ul, item) {
                if (this.options.version) {
                    var label = item.label.replace(new RegExp(
                    "(?![^&;]+;)(?!<[^<>]*)(" + $.ui.autocomplete.escapeRegex(this.term) +
                    ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
                    return $("<li></li>")
                    .data("item.autocomplete", item)
                    .append("<a>" + label + "</a>")
                    .appendTo(ul);
                }
                else {
                    var length = this.term.length;
                    if (item.label.toUpperCase().substring(0, length) == this.term.toUpperCase()) {
                        var label = item.label.replace(new RegExp(
                    "(?![^&;]+;)(?!<[^<>]*)(" + $.ui.autocomplete.escapeRegex(this.term) +
                    ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
                        return $("<li></li>")
                    .data("item.autocomplete", item)
                    .append("<a>" + label + "</a>")
                    .appendTo(ul);
                    }
                }

            },

            // Destructor de la clase
            destroy: function () {
                if (this.element.is("SELECT")) {
                    this.input.remove();
                    this.element.removeData().show();
                    return;
                }
                // SuperDestructor()
                $.ui.autocomplete.prototype.destroy.call(this);
                // Eliminamos todo lo nuevo que se añadio
                this.element.removeClass("ui-widget ui-widget-content ui-corner-left");
                this.button.remove();
            },

            // Función para buscar un elemento en la lista
            search: function (value, event) {
                var input = this.element;
                if (input != null) {
                    if (input.isFullMenu) {
                        this._swapMenu();
                        input.isFullMenu = false;
                    }
                    // super()
                    $.ui.autocomplete.prototype.search.call(this, value, event);
                }

            },

            // Función para manejar el cambio de uno de los elementos seleccionados en la lista
            _change: function (event) {
                abc = this;
                if (!this.selectedItem) {
                    /*var matcher = new RegExp("^" + $.ui.autocomplete.escapeRegex(this.element.val().toUpperCase()) + "$", "i"),
                    match = $.grep(this.options.source, function (value) {
                    return matcher.test(value.label);*/
                    var matcher = new RegExp("^" + $.ui.autocomplete.escapeRegex(this.element.val().toUpperCase()), "i");
                    match = $.grep(this.options.source, function (value) {
                        return matcher.test(value.label);
                    });
                    if (match.length) {
                        match[0].option.selected = true;
                        this.options.selectElement.val(match[0].option.value);
                    } else {

                        //                        var suggestion = this.menu.element[0].childNodes[0];
                        //                        this.element.val(suggestion.textContent);
                        //                        this.options.selectElement.select(suggestion.textContent).val()
                        //remove invalid value, as it didn't match anything
                        this.element.val("");
                        if (this.options.selectElement) {
                            this.options.selectElement.val("");
                        }
                    }
                }
                // super()

                //                $.ui.autocomplete.prototype._change.call(this, event);
                //                this.options.selectElement.focusout();
            },

            // Función para mostrar u ocultar la lista de elementos
            _swapMenu: function () {
                var input = this.element,
                data = input.data("combobox"),
                tmp = data.menuAll;
                if (data.menu.element != null) {
                    data.menuAll = data.menu.element.hide();

                }
                data.menu.element = tmp;
            },

            // Función que construye la lista de elementos a partir del los elementos cargados en el Combo
            _selectInit: function () {
                var theWidht = (this.element.width() > 480) ? 480 : this.element.width();
                var idSelect = (this.element[0].name);
                var select = this.element.hide(),
                selected = select.children(":selected"),
                value = selected.text();
                this.options.source = select.children("option[value!='']").map(function () {
                    return { label: $.trim(this.text), option: this };
                }).toArray();
                var userSelectCallback = this.options.select;
                var userSelectedCallback = this.options.selected;
                this.options.select = function (event, ui) {
                    ui.item.option.selected = true;
                    if (userSelectCallback) userSelectCallback(event, ui);
                    // compatibility with jQuery UI's combobox.
                    if (userSelectedCallback) userSelectedCallback(event, ui);
                    select.trigger("change");
                };
                if (theWidht < 2) {
                    theWidht = 150;
                }

                // Creamos el nuevo inputJQuery
                var idTemp = Math.floor(Math.random() * 1000)
                this.options.selectElement = select;
                var table = $("<table  border = '0' cellpadding = '0' cellspacing = '0'" + " style=' width:" + theWidht + "px'" + "><tr><td id = 'tdInput_" + idTemp + "' nowrap='nowrap'></td><td id = 'tdButton_" + idTemp + "' nowrap='nowrap'></td></tr></table>").insertAfter(select);
                this.input = $("<input id='" + idSelect + "_" + idTemp + "' style='width:" + theWidht + "px'>").appendTo("#tdInput_" + idTemp)
                .val(value).combobox(this.options);
            }
        }
);
})(jQuery);


