var Search = {};
Search.Base = function() {};
Search.Base.prototype = {
    baseInitialize: function(element, options)
    {
        //Variables importantes
        this.element                = $(element);       //Objeto de la tabla, default reporte
        this.selectElement          = null;
        this.selectOptions          = null;
        this.span                   = null;
        this.divSiguienteAnterior   = null;
        this.divSelected            = null;
        this.requestHTTP            = null;             //Objeto que contiene el xmlHTTPrequest
        this.tempSearch             = "";               //Guarda el texto de la ultima consulta realizada
        this.element.setAttribute('autocomplete','off');
        
        this.iefix = false;
        
        //Variable options
        this.options                = options || {};
        this.options.maxReg         = this.options.maxReg || 0;         //Máximo registros
        this.options.totalRows      = this.options.totalRows || "";     //Total filas de la consulta sin LIMIT
        this.options.pagActual      = this.options.pagActual || 1;      //Pagina actual
        this.options.cantPag        = this.options.cantPag || 0;        //
        if(typeof this.options.multiple == "undefined")
        {
            this.options.multiple = true;
        }
        
        //Control paginación
        this.filtroNumerico         = this.options.filtroNumerico || "";
        this.filtroTexto            = this.options.filtroTexto || "";
        this.retornaValue           = this.options.retornaValue || "";
        this.retornaTexto           = this.options.retornaTexto || "";
        this.origenInfo             = this.options.origenInfo || "";
        this.options.parameters     = this.options.parameters || null;
        this.options.filtros        = $H(this.options.filtros) || new Hash();
        this.options.selected       = this.options.selected || null;    //El arreglo de opciones seleccionadas
        
        //Ordenamiento
        this.options.ordenar        = this.options.ordenar || null;     //ordenar:{numero_columna_tabla: 'nombre_campo', ...} Columnas que se pueden ordenar
        this.options.ordenarPor     = this.options.ordenarPor || "";    //Nombre de la columna que se envía para que sea ordenada
        this.options.ordenaTipo     = "DESC";                           //Si es ASC o DESC, default DESC
        this.options.ordenarPorNoCol= null;                             //
        
        this.options.minCaracteres  = this.options.minCaracteres || 2;
        
        this.destInfo               = $(this.options.destInfo);      //id del Text o Hidden a donde se enviará la información que se está seleccionando
        
        this.rutaImagenes           = this.options.rutaImagenes || "./images/";
        
        //Info seleccionada
        this.selected               = []; //Opciones seleccionadas
        this.selectedValue          = []; //Texto visible de las opciones seleccionadas
        
        //Parent Node
        var elementParent = this.element.parentNode;
        
        //Icono de buscar
        var icoSearch = document.createElement("A");
        icoSearch = elementParent.insertBefore(icoSearch, this.element.nextSibling);
        Element.addClassName(icoSearch, 'ajaxSearchBuscar');
        icoSearch.onclick = this.consultar.bindAsEventListener(this);
        Element.hide(icoSearch);
        
        //Icono de Borrar seleccionados
        var icoDeleteAll = document.createElement("A");
        icoDeleteAll.id = 'deleteAll';
        this.icoDeleteAll = elementParent.insertBefore(icoDeleteAll, icoSearch.nextSibling);
        Element.addClassName(this.icoDeleteAll, 'icoDeleteAll');
        this.icoDeleteAll.onclick = this.borrar.bindAsEventListener(this);
        Element.hide(this.icoDeleteAll);
        
        //Div que encapsula el siguiente anterior y el select
        var divSelectElement = document.createElement("div");
        this.selectElement = elementParent.insertBefore(divSelectElement, this.icoDeleteAll.nextSibling);
        this.selectElement.style.zIndex = 1002;
        this.selectElement.id = "search_" + element;
        Position.clone(this.element, this.selectElement, {setHeight: false, offsetTop: this.element.offsetHeight});
        Element.addClassName(this.selectElement, 'search');
        Element.setStyle(this.selectElement, { height: '200px'});
        Element.hide(this.selectElement);
        
        //Opción siguiente anterior
        var divSiguienteAnterior = document.createElement("DIV");
        this.divSiguienteAnterior = this.selectElement.appendChild(divSiguienteAnterior);
        this.divSiguienteAnterior.id = "search_sigAnt_" + element;
        Element.setStyle(this.divSiguienteAnterior, { height: '20px'});
        Element.setStyle(this.divSiguienteAnterior, { backgroundColor: '#efefef'});
        
        //Se activa una vez digiten en la caja de texto
        this.element.onkeyup     = this.activaBusqueda.bindAsEventListener(this);
        
        //Crea el espacio para las options del pseudo select
        this.createSelect("", {destInfo : this.destInfo});
        var span = document.createElement("span");
        this.span = this.selectElement.appendChild(span);
        this.span.id = "search_select_" + this.element.id;
        
        //Adiciona el select al span
        this.span.appendChild(this.selectOptions);
        
        ////////      
        Element.setStyle(this.selectElement, {'position' : 'absolute'});
        if(!this.iefix
            && (navigator.appVersion.indexOf('MSIE')>0)
            && (navigator.userAgent.indexOf('Opera')<0)
            && (Element.getStyle(this.selectElement, 'position')=='absolute'))
        {
            new Insertion.After(this.selectElement, '<iframe id="' + this.selectElement.id + '_iefix" '+
            'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' +
            'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');
            this.iefix = $(this.selectElement.id + '_iefix');
        }
        /////////
        //Crea el espacio para las seleccionadas
        var _divSelected = document.createElement("DIV");
        this.divSelected = elementParent.insertBefore(_divSelected, this.selectElement.nextSibling);
        this.divSelected.id = "search_selected_" + this.element.id;
        //Position.clone(this.element, this.divSelected, {setHeight: false, offsetTop: this.element.offsetHeight, left: this.element.offsetLeft, width: '500px!important', overflow: 'hidden!important'});
        Element.setStyle(this.divSelected, { width: 500+'px', overflow: 'hidden'});//, zIndex: 1
        
        Element.addClassName(this.divSelected, 'sindatos');
        
        //Aqui se pobla la información seleccionada antes
        //En caso de recibir seleccionados por parametro actualiza los arreglos en invoca actualizaSelected()
        if(this.options.selected != null)
        {
            for(var key in this.options.selected)
            {
                this.selected.push(key);
                this.selectedValue.push(this.options.selected[key]);
            }
            //Actualiza el hidden
            this.aceptar();
            //Muestra el ícono externo de borrar todo
            Element.show(this.icoDeleteAll);
        }
    },
    
    //Hack para que no haga overlapping con los input select
    fixIEOverlapping: function()
    {
        //Position.clone(this.span, this.iefix);
        Position.clone(this.selectElement, this.iefix);
        this.iefix.style.zIndex = 1001;
        this.selectElement.style.zIndex = 1002;
        Element.show(this.iefix);
    },
    
    activaBusqueda: function(event)
    {
        if(this.element.value == "" || this.element.value.length < this.options.minCaracteres)
        {
            Element.hide(this.element.nextSibling);
            Element.hide(this.selectElement);
            if(this.iefix) Element.hide(this.iefix);
        }
        else if(this.element.value.length > (this.options.minCaracteres-1))
        {
            if(event.keyCode > 40 && event.keyCode < 37)
            {
                Element.hide(this.selectElement);
            }
            Element.removeClassName(this.element.nextSibling, 'icoActivity');
            Element.removeClassName(this.element.nextSibling, 'icoExclamacion');
            Element.addClassName(this.element.nextSibling, 'ajaxSearchBuscar');
            Element.show(this.element.nextSibling);
            this.options.totalRows = "";
            this.options.pagActual = 1;
            if(event.keyCode == 13)
            {
                this.consultar();
            }
        }
    },
    
    limpiarBusqueda: function(str)
    {
        //&=%26, ?=%3F, ==%3D, (espacio)=+
        str = str.replace("&","%26");
        str = str.replace("?","%3F");
        str = str.replace("=","%3D");
        str = str.replace(" ","+");
        return str;
    },
    
    consultar: function()
    {
        var myElement = this.element.nextSibling;
        //Valida que si la consulta que se va a realizar se acaba de realizar y evita el invocar los datos del servidor
        if(this.element.value != this.tempSearch)
        {
            var search = this.element.value;
            this.tempSearch = this.element.value;
            Element.removeClassName(myElement, 'ajaxSearchBuscar');
            Element.addClassName(myElement, 'icoActivity');
            
            //this.options.filtros = "";

            this.adicionaFiltro({'search' : this.limpiarBusqueda(search)});
            this.adicionaFiltro({'filtroNumerico' : this.filtroNumerico});
            this.adicionaFiltro({'filtroTexto' : this.filtroTexto});
            this.adicionaFiltro({'retornaValue' : this.retornaValue});
            this.adicionaFiltro({'retornaTexto' : this.retornaTexto});
            this.adicionaFiltro({'origenInfo' : this.origenInfo});
            this.adicionaFiltro({'total_rows' : this.options.totalRows});
            this.adicionaFiltro({'pag_actual' : this.options.pagActual});
            
            //Se le pasan los parámetros
            //this.options.parameters = this.options.filtros + '&total_rows=' + this.options.totalRows + '&pag_actual=' + this.options.pagActual;
            this.options.parameters = this.filtroSerialize();
            
            //Cierra cualquier request existente
            if(this.requestHTTP != null && this.requestHTTP.readyState != 0 && this.requestHTTP.readyState != 4 && Ajax.activeRequestCount > 0)
            {
                try
                {
                    if(this.requestHTTP.readyState != "undefined")
                    {
                        this.requestHTTP.abort();
                    }
                }
                catch (error)
                {
                    //alert(this.requestHTTP.readyState + " " + Ajax.activeRequestCount + " " + error );
                }
                this.requestHTTP = null;
            }
            this.requestHTTP = new Ajax.Request(this.url, this.options);
        }
        else
        {
            var ul = this.span.firstChild;
            if(ul.childNodes.length > 0)
            {
                Element.show(this.selectElement);
                if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 10);
            }
            else
            {
                Element.removeClassName(this.element.nextSibling, 'ajaxSearchBuscar');
                Element.addClassName(this.element.nextSibling, 'icoExclamacion');
            }
        }
    },
    
    siguienteAnterior: function(crearEn)
    {
        var sigAnt = crearEn;
        
        sigAnt.innerHTML = "";
        //Calcular cantidad de páginas
        this.options.cantPag =  Math.ceil(this.options.totalRows/this.options.maxReg);
        
        if(this.options.pagActual > this.options.cantPag)
        {
            this.options.pagActual = this.options.cantPag;
        }
        
        if(this.options.cantPag >= 1)
        {
            //Primero
            pagPrimero = document.createElement("img");
            Element.addClassName(pagPrimero, 'pagPrimero');
            if(this.options.pagActual == 1)
            {
                Element.addClassName(pagPrimero, 'disabled');
                pagPrimero.src = this.rutaImagenes + "ico_primero_off.gif";
            }
            else
            {
                Element.removeClassName(pagPrimero, 'disabled');
                pagPrimero.src = this.rutaImagenes + "ico_primero.gif";
                pagPrimero.onclick = this.paginar.bind(this, 1);
            }
            //Adiciona el icono
            sigAnt.appendChild(pagPrimero);
            
            //Anterior
            pagAnterior = document.createElement("img");
            Element.addClassName(pagAnterior, 'pagAnterior');
            if(this.options.pagActual == 1)
            {
                Element.addClassName(pagAnterior, 'disabled');
                pagAnterior.src = this.rutaImagenes + "ico_anterior_off.gif";
                
            }
            else
            {                
                Element.removeClassName(pagAnterior, 'disabled');
                pagAnterior.src = this.rutaImagenes + "ico_anterior.gif";
                pagAnterior.onclick = this.paginar.bind(this, this.options.pagActual - 1);
            }
            //Adiciona el icono
            sigAnt.appendChild(pagAnterior);
            
            //Texto
            pagTexto = document.createElement("span");
            //pagTexto.id = "pagTexto";
            Element.addClassName(pagTexto, 'pagTexto');
            pagTexto.innerHTML = "[" + this.options.pagActual + " (" + this.options.cantPag + ") ]";
            sigAnt.appendChild(pagTexto);
                            
            //Siguiente
            pagSiguiente = document.createElement("img");
            Element.addClassName(pagSiguiente, 'pagSiguiente');
            if(this.options.pagActual == this.options.cantPag)
            {
                Element.addClassName(pagSiguiente, 'disabled');
                pagSiguiente.src = this.rutaImagenes + "ico_siguiente_off.gif";
            }
            else
            {
                Element.removeClassName(pagSiguiente, 'disabled');
                pagSiguiente.src = this.rutaImagenes + "ico_siguiente.gif";
                pagSiguiente.onclick = this.paginar.bind(this, this.options.pagActual + 1);
            }
            //Adiciona el ícono
            sigAnt.appendChild(pagSiguiente);
            
            //Ultimo
            pagUltimo = document.createElement("img");
            Element.addClassName(pagUltimo, 'pagUltimo');
            if(this.options.pagActual == this.options.cantPag)
            {
                Element.addClassName(pagUltimo, 'disabled');
                pagUltimo.src = this.rutaImagenes + "ico_ultimo_off.gif";
                sigAnt.appendChild(pagUltimo);
            }
            else
            {
                Element.removeClassName(pagUltimo, 'disabled');
                pagUltimo.src = this.rutaImagenes + "ico_ultimo.gif";
                pagUltimo.onclick = this.paginar.bind(this, this.options.cantPag);
            }
            sigAnt.appendChild(pagUltimo);
            
            //Icono de Cancelar
            var icoCancelar = document.createElement("A");
            Element.addClassName(icoCancelar, 'accept');
            icoCancelar.setAttribute('title', 'Close')
            icoCancelar.onclick = this.cancelar.bindAsEventListener(this);
            sigAnt.appendChild(icoCancelar);
            
            //Icono de Borrar todo
            var icoBorrar = document.createElement("A");
            Element.addClassName(icoBorrar, 'delete');
            icoBorrar.setAttribute('title', 'Delete All')
            icoBorrar.onclick = this.borrar.bindAsEventListener(this);
            sigAnt.appendChild(icoBorrar);
        }
        else
        {
        
        }
    },
    
    paginar: function(pagina)
    {
        this.tempSearch = "";
        this.options.pagActual = pagina;
        this.consultar();
    },
    
    aceptar: function()
    {
        this.destInfo.value = this.selected.join(',');
        //console.debug(this.destInfo.value);
        Element.hide( this.selectElement );
        this.actualizaSelected();
    },
    
    cancelar: function(event)
    {
        Element.hide( this.selectElement );
        this.aceptar();
    },
    
    borrar: function(event)
    {
        this.divSelected.innerHTML = "";
        this.destInfo.value = "";
        this.selected = [];
        this.selectedValue = [];
        Element.hide( this.divSelected );
        var ul = this.span.firstChild;
        for(i = 0; i < ul.childNodes.length; i++)
        {
            //alert(ul.childNodes[i]);
            Element.removeClassName(ul.childNodes[i], 'selected');
        }
        //Oculta el ícono externo de borrar todo
        Element.hide(this.icoDeleteAll);
    },
    
    actualizaSelected: function()
    {
        this.divSelected.innerHTML = "";
        if(this.selected.length > 0)
        {
            var ul = this.divSelected.appendChild(document.createElement('UL'));
            
            Element.show(this.divSelected);
            Element.removeClassName(this.divSelected, 'sindatos');
            Element.addClassName(this.divSelected, 'condatos');
            Element.setStyle(this.divSelected, { width: '550px'});
            Element.setStyle(this.divSelected, { marginRight: '10px'});
            
            for(var i = 0; i < this.selected.length; i++)
            {
                var item = ul.appendChild(document.createElement('LI'));
                item.setAttribute('arrId', i);
                item.setAttribute('searchid', this.selected[i]);
                item.setAttribute('searchvalue', this.selectedValue[i]);
                
                item.onclick = this.liOnClick.bind(this, item);
                item.onmouseover = this.liOnOver.bind(this, item);
                item.onmouseout = this.liOnOut.bind(this, item);
                
                Element.update(item, this.selectedValue[i]);
            }
            
            //Muestra el ícono externo de borrar todo
            Element.show(this.icoDeleteAll);
        }
        else
        {
            Element.hide(this.icoDeleteAll);
            Element.hide(this.divSelected);
        }
        if(this.iefix) Element.hide(this.iefix);
    },
    
    liOnClick: function(myElement)
    {
        var parent = myElement.parentNode;
        
        //Ubica la opción a quitar
        var idElemento = this.selected.indexOf(myElement.getAttribute('searchid'));
        //La quita del arreglo de seleccionados
        this.selected.splice(idElemento, 1);
        this.selectedValue.splice(idElemento, 1);
        
        var arrLi = this.selectOptions.childNodes;
        
        for(i = 0; i< arrLi.length; i++)
        {
            if(arrLi[i].getAttribute('searchid') == myElement.getAttribute('searchid'))
            {
                Element.removeClassName(arrLi[i], 'selected');
                break; 
            }
        }
        //Actualiza el hidden que guarda los id de los seleccionados
        this.destInfo.value = this.selected.join(',');
        //Actualiza la pantalla
        this.actualizaSelected();
    },
    
    liOnOver: function(myElement)
    {
        Element.addClassName(myElement, 'over')
    },
    
    liOnOut: function(myElement)
    {
        Element.removeClassName(myElement, 'over')
    },
    
    actualizaInfo: function(request)
    {
        var ico = this.element.nextSibling;
        //Element.hide(ico);
        var parent = this.element.parentNode;
        Element.removeClassName(ico, 'icoActivity');
        Element.addClassName(ico, 'ajaxSearchBuscar');
        
        if(request.responseText.substring(0,6) == "Error:" || request.responseText.substring(0,2) != "<?")
        {
            //Retornó un error y se muestra el alert
            alert(request.responseText);
            Element.removeClassName(this.element.nextSibling, 'ajaxSearchBuscar');
            Element.addClassName(this.element.nextSibling, 'icoExclamacion');
            return false;
        }
        
        var filas = request.responseXML.getElementsByTagName("row");
        this.selectCleanAll();
        
        //alert(this.selectOptions);
        if(filas.length > 0)
        {
            //Actualiza la cantidad de registros encontrados sin el LIMIT
            this.options.totalRows = request.responseXML.getElementsByTagName("total_rows")[0].firstChild.data;
            //Actualiza máximo registros por página
            this.options.maxReg = request.responseXML.getElementsByTagName("maxreg")[0].firstChild.data;
            for (i = 0; i < filas.length; i++)
            {
                var fila = filas.item(i);
            
                //Separa la informacion
                var filaId = fila.childNodes.item(0).childNodes;
                var filaInfo = fila.childNodes.item(1).childNodes;
                
                if(filaInfo.length > 0)
                {
                    var id = filaId.item(0).data;
                    var text = filaInfo.item(0).data;
                    this.selectAddRow(id, text);
                }
            }
            //Iconos de siguiente anterior y cerrar
            this.siguienteAnterior(this.divSiguienteAnterior);
            //Arregla la posicion del selectElement
            Position.clone(this.element, this.selectElement, {setHeight: false, offsetTop: this.element.offsetHeight});
            Element.show(this.selectElement);
            this.selectOptions.style.width = this.selectElement.style.width;
            if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 10);
        }
        else
        {
            //No encontró datos
            Element.addClassName(ico, 'icoExclamacion');
        }
    },
    
    adicionaFiltro: function(filtro)
    {
        if(filtro)
        {
            filtro = $H(filtro);
            this.options.filtros = this.options.filtros.merge(filtro);
        }
    },
    
    filtroSerialize: function()
    {
        return this.options.filtros.toQueryString();
    },
    
    //////////Funciones para el select
    createSelect: function(element)
    {
        //Div que simula el campo select
        this.selectOptions = document.createElement("UL");
        //Element.setStyle(this.selectOptions, { width: '266px'});
        Element.setStyle(this.selectOptions, { overflowY: 'scroll'});
        Element.setStyle(this.selectOptions, { overflowX: 'hidden'});
        Element.setStyle(this.selectOptions, { height: '180px'});
    },
    
    selectAddRow: function(key, value)
    {
        //Inserta una celda a la fila
        var item = this.selectOptions.appendChild(document.createElement('LI'));
        //alert(key + " " + value);
        Element.update(item, value);
        
        if(this.selected.length >0 &&this.selected.indexOf(key) != -1)
        {
            Element.addClassName(item, 'selected');
        }
        
        item.setAttribute('searchid', key);
        item.setAttribute('searchvalue', value);
        item.setAttribute('title', value);
        
        item.onclick = this.selectClick.bindAsEventListener(this);
        item.onmouseover = this.selectOver.bindAsEventListener(this);
        item.onmouseout = this.selectOut.bindAsEventListener(this);
    },
    
    selectCleanAll: function()
    {
        // remove all children from element
        while (this.selectOptions.firstChild)
        {
            this.selectOptions.removeChild(this.selectOptions.firstChild);
        }
    },
    
    selectClick: function(event)
    {
        var myElement = Event.element(event);
        var value = myElement.getAttribute("searchid");
        var text = myElement.getAttribute("searchvalue");
        
        //Se encuentra seleccionado
        if(Element.hasClassName(myElement, 'selected'))
        {
            Element.removeClassName(myElement, 'selected');
            Element.addClassName(myElement, 'over');
            var idElemento = this.selected.indexOf(value);
            this.selected.splice(idElemento, 1);
            this.selectedValue.splice(idElemento, 1);
        }
        else //No se encuentra seleccionado
        {
            if(Element.hasClassName(myElement, 'over'))
            {
                Element.removeClassName(myElement, 'over');
            }
            
            //Si no permite multiples, deselecciona cualquier otra opción seleccionada antes
            if(!this.options.multiple)
            {
                this.selected = [];
                this.selectedValue = [];
                var myElementNode = $A(myElement.parentNode.childNodes);
                myElementNode.each(   function (_element)
                                        {
                                            Element.removeClassName(_element, 'selected');
                                        }
                );
            }
            Element.addClassName(myElement, 'selected');

            this.selected.push(value);
            this.selectedValue.push(text);
        }
    },
    
    selectOver: function(event)
    {
        var element = Event.findElement(event, 'LI');
        if(!Element.hasClassName(element, 'selected'))
        {
            Element.addClassName(element, 'over');
        }
    },
    
    selectOut: function(event)
    {
        var element = Event.findElement(event, 'LI');
        Element.removeClassName(element, 'over');
    },
    
    //Super Hack para adicionar argumentos a una función que también se asigna por medio de binding
    bindFuncArgs: function(fn, args)
    {
        return function () { return fn.apply(this, args); }; 
    }
};

Ajax.Search = Class.create();
Object.extend(Object.extend(Ajax.Search.prototype, Search.Base.prototype),
{
    initialize: function(element, url, options)
    {
        this.baseInitialize(element, options);
        this.options.asynchronous  = true;
        this.options.onComplete    = this.onComplete.bind(this);
        this.url                   = url;
    },

    onComplete: function(request)
    {
        this.actualizaInfo(request);
    }
});