var fn = {};
var busy = {};
var _hotelSeleccionado = {}
var _imagePath = "";
var _popups = [];
var _NumeroAmigo = 0;

var _Totalhab;
var _adultosHab;
var _ninosHab;
var _edadNinosHab;

if (!console) var console = { log: function() { } }

function fixme(txt) { alert(txt); }

/* alert() override */
var proxyAlert = window.alert;
window.alert = function(txt) { proxyAlert(txt); }

function INIT(plugins, parameters) {

    plugins = plugins || [];
    parameters = parameters || [];
    if (typeof opciones == "undefined") opciones = {};
    if (typeof literales == "undefined") literales = {};

    // Variables de control del servidor
    var sesId = $("input[type=hidden][id$=sesId]").val() || "";
    window.getSesId = function() { return sesId; };
    window.esSalto = function() { return parseInt(getValue("esSalto")) ? true : false };

    // Idioma para fechas
    if (typeof literales != "undefined") {
        dateFormat.i18n = {
            dayNames: literales.diaSemana || dateFormat.i18n.dayNames,
            monthNames: literales.mes || dateFormat.i18n.monthNames
        };
    }

    /* AUTOCOLUMNAS */
    $(".autoColumnas").each(function() {

        var container = $(this)
        var ncols;

        if (container.hasClass("2columnas")) ncols = 2;
        else if (container.hasClass("3columnas")) ncols = 3;
        else if (container.hasClass("4columnas")) ncols = 4;
        else ncols = 3;

        // Primera columna
        var colH = container.height() / ncols;
        var top = container.offset().top;
        var last;
        var c = 1;

        $("> *:not(h1,h2,h3,h4,h5,h6)", this).each(function() {
            var g = $(this);
            if (g.offset().top + g.height() / 2 - top > colH && c < ncols) {
                if (last) last.after('--COLBREAK--');
                top = g.offset().top;
                c++;
            }
            last = g;
        });

        container.html("<div class='columna'>" + container.html().replace(/--COLBREAK--/g, "</div> <div class='columna'>") + "</div>"); ;

    });

    /* Desplegables */
    $(".controlDesplegable").click(function(e) {
        if (e.target.href) return;
        if ($(this).attr("locked") == true) return;
        if ($(this).next().hasClass("desplegable")) {
            $(this).next().slideToggle(300, function() { $(this).trigger("toggle"); });
        } else {
            $(".desplegable:first", $(this).next()).slideToggle(300, function() { $(this).trigger("toggle"); });
        }

        if (!$(this).hasClass("open")) { $(this).addClass("open"); }
        else { $(this).removeClass("open"); }
    });
    $(".controlDesplegable").each(function() {
        if (!$(this).hasClass("open")) {
            /* Hide() deja visible algun select en IE */
            if ($(this).next().hasClass("desplegable")) $(this).next().slideUp(1);
            else $(".desplegable:first", $(this).parent()).slideUp(1);
        }
    });

    /* Botones varios */
    $(".botonGuiaDestinos").click(function(e) {
        e.preventDefault();
        openPopupURL(this.href, fn.guiaDestino, {
            sesId: getSesId(),
            DestinoNivel1: getValue("GuiaMultimediaDestinoNivel1"),
            DestinoNivel2: getValue("GuiaMultimediaDestinoNivel2"),
            DestinoNivel3: getValue("GuiaMultimediaDestinoNivel3")
        });
    });

    fixIE();

    /* Cajas de evento Hover */
    $(".hoverBox").prepend("<div class='selectBox'><span></span></div>");

    /* Campos de texto que no caben */
    $("div.moduloOferta h4 a").checkTextOverflow();

    /* Configuracion de cabecera y pie */
    fn.cabeceraPie();

    /* Vinculos a popups */
    fn.popupLinks();

    /* Validación formularios */
    fn.formValidator();

    /* Teclas */
    fn.keys();

    /* Pantalla de espera */
    fn.espera();
    hideLoader();

    /* Botones con pantalla de precarga */
    $("form.showPreload").bind("submit", preloadButton);
    $("a.showPreload, input[type=submit].showPreload, input[type=button].showPreload").bind("click", preloadButton);

    /* Carga de plugins */
    for (var i in plugins) if (fn[plugins[i]]) fn[plugins[i]](parameters[i] ? parameters[i] : []);

}

// Funciones y variables del formulario de Emails para añadir Amigos



fn.AnadirAmigos = function(obj) {
    //_NumeroAmigo = 0;
    obj.style.display = "none";
    document.getElementById("enviarAmigo").style.display = "";
    fn.OtroAmigo();
}


fn.OtroAmigo = function() {
//debugger;
//    if(document.getElementById("anadirDestinatario").style.display=="none"){
//        _NumeroAmigo=0;
//    }
    var maxAmigos = document.getElementById("MaxAmigos").value;
    document.getElementById("lblNombreApellidos").style.display = "";
    document.getElementById("lblEmailRemitente").style.display = "";
    if (_NumeroAmigo < maxAmigos) {
        _NumeroAmigo = _NumeroAmigo + 1;
        var obj = document.getElementById("direccionCorreo");
        //if ($.browser.msie) {
            //obj.innerHTML = obj.innerHTML + " <br /><label class='email'><input  id='email" + _NumeroAmigo + "' type='text' name='email' value='' /></label>";
        //
       obj.appendChild(document.createElement("br"));       
       var label=document.createElement("label");
       label.setAttribute("style","margin-top:20px");
       label.setAttribute("class","email");
       var email=document.createElement("input");
       email.setAttribute("id","email"+_NumeroAmigo);
       email.setAttribute("type","text");
       email.setAttribute("name","email");
       email.setAttribute("value","");
       label.appendChild(email);
       obj.appendChild(label);
    }
    if (_NumeroAmigo == maxAmigos) {
        document.getElementById("anadirDestinatario").style.display = "none";
    }

}

// Obtiene la ruta de imagenes (por defecto, de la primera imagen del documento)
function getImagePath(env) {
    if (opciones.pathImagenes) return opciones.pathImagenes;
    if (_imagePath) return _imagePath;
    var src = $("img:first[src]", env || document).attr("src");
    return _imagePath = src.split("/").slice(0, -1).join("/") + "/";
}
// Metodo Salto Generico
function SaltoGenerico(method, params, useGet) {

    if (!method) {
        fixme("No se ha definido un método");
        return;
    }

    var dataOut = { sesId: getSesId() }
    $.extend(dataOut, params);

    /* Enviamos los datos del formulario por AJAX */
    loadData(method, dataOut, function(data) {

        var urlSalto;

        // Elimina las comillas iniciales  y finales
        data = data.replace(/^\"(.*)\"$/, '$1');

        if (useGet == true) {

            // Nuevo método, que salta a la nueva URL sin pasar nada por POST
            document.location.href = data;

        } else {

            //Método antiguo. Por POST

            // Comprobacion de la respuesta del servidor
            if (data.substr(0, 2).toUpperCase() == "KO") {

                // Mensaje devuelto por el servidor
                alert(data.substr(3));

            } else if (data.substr(0, 2).toUpperCase() == "OK") {

                data = data.split("#");
                urlSalto = data[1];

                var dataOut = {
                    sesId: data[2] ? data[2] : getSesId(),
                    codigoCargaSalto: data[3]
                }

                if (urlSalto) sendData(urlSalto, dataOut);

            } else {

                fixme("Respuesta del servidor inesperada: " + data);

            }

        }

    });

}

// Pantalla de precarga en botones
function preloadButton(e) {
    if (typeof showLoader != "function") return;
    showLoader(false, "");
}

// Obtiene un valor de un input hidden
function getValue(id, context) {
    var o = $("input[id$=" + id + "], input[name$=" + id + "]", context).filter(":eq(0)");
    if (o.size()) return o.val();
    return "";
}

// Salto a oferta
function Salto(codOferta) {
    SaltoGenerico(proveedoresDatos.salto, { codOferta: codOferta });
}
// Salto a explorar destinos
function SaltoExplorarDestinos(codDestino) {
    SaltoGenerico(proveedoresDatos.saltoExplorarDestinos, { codDestino: codDestino });
}
// Salto a encontrar ofertas
function SaltoEncontrarOfertas(codOrigenFichero) {
    SaltoGenerico(proveedoresDatos.saltoEncontrarOfertas, { codOrigenFichero: codOrigenFichero });
}

// Cambio de página por POST
function Go(url) { sendData(url, { sesId: getSesId() }); }

// Errores Ajax
function ajaxError(xhr, status, error) {
    fixme("Error en la petición: (" + xhr.status + ") " + xhr.statusText + "\n\nStatus: " + (status || "") + "\nError: " + (error || ""));
    if (typeof hideLoader == "function") hideLoader();
    $("#contenedor").css({ "cursor": "default" });
    busy = {};
}
function ajaxTimeout() {
    fixme("Timeout!");
    $("#contenedor").css({ "cursor": "default" });
}

// Interpreta un numero desde un texto
function readNumber(txt) {

    if (!txt) return 0;

    // Caracteres separadores válidos
    var dots = "\.\,\'";

    // Elimina caracteres que no sean numeros o separadores, y posibles etiquetas HTML
    txt = txt.replace(/\<[a-z\/]*\>/gi, '').replace(new RegExp("[^0-9\-" + dots + "]", "g"), '');

    // Extrae el separador decimal (Siempre se se pasen 2 decimales)
    var dec = txt.substr(txt.length - 3, 1).replace(new RegExp("[^" + dots + "]", "g"), '');

    // Elimina otros simbolos que no sean separadores decimales
    txt = txt.replace(new RegExp("[^0-9\-" + dec + "]", "g"), '');

    // Normaliza el separador decimal
    if (dec) txt = txt.replace(new RegExp("[" + dec + "]", "g"), ".");

    // Devuelve el numero
    return parseFloat(txt);

}

// Interpreta una fecha en formato "YYYY-MM-DD"
function readDate(str) {
    var dat = str.split("-");
    return new Date(dat[0], parseInt(dat[1], 10) - 1, dat[2]);
}

// Formatea un numero con separadores de miles y de decimales
function formatNumber(number) {

    number = number.toString();

    var sRegExp = new RegExp('(-?[0-9]+)([0-9]{3})');

    while (sRegExp.test(number)) {
        number = number.replace(sRegExp, '$1.$2');
    }

    return number;
}

function addslashes(str) {
    str = str.replace(/\\/g, '\\\\');
    str = str.replace(/\'/g, '\\\'');
    str = str.replace(/\"/g, '\\"');
    str = str.replace(/\0/g, '\\0');
    return str;
}
function stripslashes(str) {
    str = str.replace(/\\'/g, '\'');
    str = str.replace(/\\"/g, '"');
    str = str.replace(/\\0/g, '\0');
    str = str.replace(/\\\\/g, '\\');
    return str;
}

// Parches para el código fuente proporcionado por IE
function fixIETags(txt, endLineTag) {
    if (!endLineTag) endLineTag = "A"

    if ($.browser.msie) {
        // Entrecomillar los parametros sin comillas
        txt = txt.replace(/=([^\"\' <>].[^\"\' <>]*)([ >])/gim, '="$1"$2');
        // Finalizar los LI correctamente
        if (parseFloat($.browser.version) < 8) {
            if (txt.match(/<\/P>/gi)) txt = txt.replace(/<\/(P)>\s*$/gim, '</$1></LI>');
            else txt = txt.replace(/<\/(A)>\s*$/gim, '</$1></LI>');
        }

        return txt;
    } else return txt;
}

// Fixes para IE varios
function fixIE(env) {

    if (!$.browser.msie) return;
    if (!env) env = document;

    if (parseInt($.browser.version) < 7) {
        $(">li:first, >tr:first, >td:first", $("ul, ol, table, thead, tbody, tr"), env).addClass("first-child");
        $(">li:last, >tr:last, >td:last", $("ul, ol, table, thead, tbody, tr"), env).addClass("last-child");
    }
    $("table tr:even", env).addClass("even");
    $("table tr:odd", env).addClass("odd");

}

// Hover <li> y <a> para IE
function fixHover(tag) {

    if (!tag) tag = "li, a"; // Tag por defecto

    if ($.browser.msie && parseInt($.browser.version) <= 6) {
        $(tag).hover(function() {
            $(this).addClass("hover");
        }, function() {
            $(this).removeClass("hover");
        });
    }
}

// Comprueba si un valor es nulo
function nulo(val) { return !val || val == "0"; }

// Ayuda formularios
$.fn.disable = function() { return this.each(function() { $(this).attr("disabled", "disabled"); }) }
$.fn.enable = function() { return this.each(function() { $(this).removeAttr("disabled"); }) }
$.fn.reset = function() { return this.each(function() { this.reset(); }); }

// Coloca ... en elementos de N lineas que no caben
$.fn.checkTextOverflow = function(lines) {
    return this.each(function() {

        if (!lines) lines = 1;

        var tar = $(this),
		os, ls, tg,
		tw = tar.css({ "display": "block", "white-space": "normal" }).width(),
		th = tar.height(),
		ot = tar.html(), pt = ot,
		alt = tar.text(),
		ok = false,
		ct = false,
		el = ' &hellip;';

        tar.css({ "position": "absolute", "white-space": (lines > 1 ? "normal" : "nowrap") });

        while (!ok) {
            os = lines > 1 ? tar.css({ "width": tw, "height": "auto" }).height() : tar.css({ "width": "auto" }).width();

            if (lines > 1 ? os > th : os > tw) {
                ls = pt.lastIndexOf(' ');
                tg = (new RegExp("<[^>]*$", "g")).test(pt.substr(0, ls));
                if (ls > 0) {
                    pt = pt.substr(0, ls);
                    tar.html(pt + el);
                    ct = true;
                } else {
                    tar.html(el).attr("title", alt);
                    ok = true && !tg;
                }
            } else {
                if (ct) {
                    tar.attr("title", alt);
                }
                tar.css({ "display": "block" }).css(lines > 1 ? { "height": th + "px"} : { "width": tw + "px" });

                ok = true;
            }
        }
        tar.css({ "position": "" });

    });
}

// Deshabilita seleccionar texto 
$.fn.disableTextSelect = function() {

    return this.each(function() {
        if ($.browser.mozilla) {//Firefox
            $(this).css('MozUserSelect', 'none');
        } else if ($.browser.msie) {//IE
            $(this).bind('selectstart', function() { return false; });
        } else {//Opera, etc.
            // Buggy on chrome
            //$(this).mousedown(function(){return false;});
        }
    });
}

/* Galerias de imágenes (requiere jquery.carousel.js) */
$.fn.galeriaImagenes = function(W, H, custom) {

    var options = {
        firstControl: '',
        leftControl: '',
        rightControl: '',
        lastControl: '',
        pageControl: '<span class="thumb">%page%</span>',
        paddingLeft: 0,
        paddingRight: 0,
        speed: 200,
        canvasItem: '',
        contentItem: 'ul',
        listItem: 'li',
        pageSeparator: '',
        onChange: function(i) { },
        itemHeight: H
    }

    $.extend(options, custom);

    return this.each(function() {
        $(this).carousel(options).addClass("galeriaImagenes");
    });
}

$.fn.tablaPaginado = function(nitems, pagcontainer) {

    if (!nitems) nitems = 8;

    return this.each(function() {

        var pagehtml = "<tbody class='page'></tbody>";

        var original = $("tbody", this);
        var list = $("tbody > tr", this);
        var page = $(pagehtml);
        var book = $("<div></div>");
        var c = 0;

        list.each(function() {



            // next page
            if (c >= nitems) {
                book.append(page);
                page = $(pagehtml); ;
                c = 0;
            }



            page.append(this);



            c++;



        });

        // Ultima pagina
        book.append(page);

        $(this).append(book.html());
        original.remove();

        list = $("tbody", this);

        $(this).carousel({
            firstControl: '<a href="#" title="' + literales.paginado_primera + '">&lt;&lt;</a> ',
            leftControl: '<a href="#" class="negro" title="' + literales.paginado_anterior + '">&lt;</a> ',
            rightControl: '<a href="#" class="negro" title="' + literales.paginado_siguiente + '">&gt;</a> ',
            lastControl: '<a href="#" title="' + literales.paginado_ultima + '">&gt;&gt;</a> ',
            pageControl: '<a href="#">%page%</a>',
            pageSeparator: ' | ',
            paddingLeft: 0,
            paddingRight: 0,
            speed: 0,
            canvasItem: this,
            contentItem: this,
            listItem: '> tbody',
            controlsItem: pagcontainer,
            disableAnimation: true,
            disableStyles: true,
            onChange: function(i) {
                list.hide();
                list.filter(":eq(" + i.current + ")").show();
            },
            itemHeight: 'auto'
        });

    });

}

// Ayuda AJAX

/* Envio de datos AJAX para devolver un XML */
function loadXmlData(url, params, success, onTimeout, onError) {

    /* Solo 1 peticion a la vez */
    var timeout = 60000;
    var currentpid = null;

    if (!url) { fixme("No se definido un método"); return; }

    /* Se pasa un timeout ? */
    if (typeof (url) != "string") {
        timeout = url[1];
        url = url[0];
    }

    /* Cancela la anterior peticion */
    if (busy.pid) {
        console.log("Ya hay una petición con ID" + busy.pid + ". Eliminando");
        clearTimeout(busy.pid);
    }

    busy = {
        pid: currentpid = setTimeout(function() {
            if (typeof (onTimeout) == "function") {
                if (!onTimeout()) {
                    busy = {};
                    cancelled = true;
                };
            } else {
                ajaxTimeout();
                busy = {};
                cancelled = true;
            }
        }, timeout)
    }
    console.log("Nueva peticion: " + busy.pid);

    $("#contenedor").css({ "cursor": "progress" });

    $.ajax({
        type: "post",
        url: url,
        data: serializeData(params),
        dataType: ($.browser.msie) ? "text" : "xml",
        contentType: "application/json; charset=utf-8",
        success: function(xmlData) {

            $("#contenedor").css({ "cursor": "default" });

            console.log("Completado " + currentpid + ". PID actual " + busy.pid);

            // Si la actual peticion es la ultima?
            if (currentpid == busy.pid) {

                var data;
                if (typeof xmlData == 'string' && $.browser.msie) {
                    data = new ActiveXObject('Microsoft.XMLDOM');
                    data.async = false;
                    data.loadXML(xmlData);
                } else {
                    data = xmlData;
                }

                clearTimeout(busy.pid);
                busy = {};

                /* Llamada a la función 'success' pasada como parametro */
                success(data);

            } else console.log("Completado " + currentpid + ". IGNORADA! ");

        },
        error: function(e) {

            if (currentpid == busy.pid) {
                clearTimeout(busy.pid);
                busy = {};

                if (typeof onError == "function") onError(e);
                else ajaxError(e);
            }

        }
    });
}

/* Envio de datos AJAX para devolver un texto plano */
function loadData(url, params, success, onTimeout, noJSON) {

    var timeout = 15000;
    var currentpid = null;

    if (!url) { fixme("No se ha definido un método"); return; }

    /* Se pasa un timeout ? */
    if (typeof (url) != "string") {
        timeout = url[1];
        url = url[0];
    }

    /* Cancela el timeout de la peticion anterior */
    if (busy.pid) {
        console.log("Ya hay una petición con ID" + busy.pid + ". Ignorandola.");
        clearTimeout(busy.pid);
    }

    busy = {
        pid: currentpid = setTimeout(function() {
            if (typeof (onTimeout) == "function") {
                cancelled = onTimeout();
            } else {
                ajaxTimeout();
                cancelled = true;
            }
        }, timeout)
    }
    console.log("Nueva peticion: " + busy.pid);

    $("#contenedor").css({ "cursor": "progress" });

    $.ajax({
        type: "post",
        url: url,
        data: noJSON ? params : serializeData(params),
        contentType: noJSON ? "application/x-www-form-urlencoded" : "application/json; charset=utf-8",
        success: function(data) {

            $("#contenedor").css({ "cursor": "default" });

            if (currentpid == busy.pid) {
                clearTimeout(busy.pid);
                busy = {};

                // Elimina las comillas iniciales  y finales				
                data = data.replace(/^\"(.*)\"$/, '$1');

                /* Llamada a la función 'success' pasada como parametro */
                success(data);
            }

        },
        error: function(e) {

            if (currentpid == busy.pid) {
                clearTimeout(busy.pid);
                busy = {};
                ajaxError(e);
            }

        }
    });
}

/* Envio de datos por formulario a una nueva página */
function sendData(url, params, target) {

    //if (!url) { alert("No se ha definido una URL"); return; }
    var form = $("<form method='post' action='" + url + "' target='" + (target || "_self") + "'></form>");

    // Creamos campos
    for (var i in params) form.append("<input type='hidden' name='" + i + "' value='' />");

    // Añadimos al DOM (Mozilla)
    $("body").append(form);

    // Asignamos valores
    for (var i in params) $("input[name=" + i + "]", form).val(params[i]);

    $("#contenedor").css({ "cursor": "progress" });

    form.submit();
}

/* Convierte un objeto en una cadena XML */
function XMLStringSinCabecera(object, name, recursiveCall) {
    var xml = "", i;
    var isArray = typeof (object) === 'object' && typeof (object.length) === 'number' && !(object.propertyIsEnumerable('length')) && typeof (object.splice === 'function');
    xml += "<" + name + ">";

    if (typeof (object) === "undefined" || object == null) return ""; //Nada
    else if (typeof (object) === "object") for (i in object) xml += XMLString(object[i], isArray ? name : i, true); // Un objeto o array
    else xml += object; // Un texto

    xml += "</" + name + ">";

    return xml;
}

///* Convierte un objeto en una cadena XML */
//function XMLStringSinCabecera(object, name, recursiveCall) {
//    var xml = "", i;
//    var isArray = typeof (object) === 'object' && typeof (object.length) === 'number' && !(object.propertyIsEnumerable('length')) && typeof (object.splice === 'function');

//    if (recursiveCall) {
//        if (!isArray) {
//            xml += "<" + name + ">";
//        }
//    }

//    if (typeof (object) === "undefined" || object == null) return ""; //Nada
//    else if (typeof (object) === "object") for (i in object) xml += XMLString(object[i], isArray ? name : i, true); // Un objeto o array
//    else xml += object; // Un texto

//    //    if (!isArray || !recursiveCall) xml += "</" + name + ">";

//    return xml;
//}

/* Convierte un objeto en una cadena XML */
function XMLStringAnadirCabecera(object, name) {
    var xml = "";

    xml += "<?xml version=\"1.0\" ?>";
    xml += "<" + name + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">";
    xml += object;
    xml += "</" + name + ">";

    return xml;
}

/* Convierte un objeto en una cadena XML */
function XMLString(object, name, recursiveCall) {
    var xml = "", i;
    var isArray = typeof (object) === 'object' && typeof (object.length) === 'number' && !(object.propertyIsEnumerable('length')) && typeof (object.splice === 'function');

    if (!recursiveCall) {
        xml += "<?xml version=\"1.0\" ?>";
        xml += "<" + name + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">";
    } else if (!isArray) {
        xml += "<" + name + ">";
    }

    if (typeof (object) === "undefined" || object == null) return ""; //Nada
    else if (typeof (object) === "object") for (i in object) xml += XMLString(object[i], isArray ? name : i, true); // Un objeto o array
    else xml += object; // Un texto

    if (!isArray || !recursiveCall) xml += "</" + name + ">";

    return xml;
}

/* Prepara los parametros para ser recibidos por el servidor */
function serializeData(data) {
    /* .NET requiere que el objeto JSON se integre en una cadena */
    return JSON.stringify(data) || "{}";
}

/* Convierte un XML a un String */
function serializeXML(xmlNode) {
    try {
        // Gecko-based browsers, Safari, Opera.
        return (new XMLSerializer()).serializeToString(xmlNode);
    }
    catch (e) {
        try {
            // Internet Explorer.
            return xmlNode.xml;
        }
        catch (e) {//Strange Browser ??
            fixme('Xmlserializer not supported');
        }
    }
    return false;
}

/* Función global para la seleccion de hotel */
function obtenerHotelSeleccionado() { return _hotelSeleccionado == {} ? false : _hotelSeleccionado; }
function seleccionarHotel(target, hotel, extraParams) {
    if (!hotel) {
        fixme("No se pudo recuperar el hotel seleccionado");
        return;
    }

    // Guarda la selección
    _hotelSeleccionado = hotel;

    if (!extraParams) extraParams = {};

    var dataOut = $.extend({
        folleto: hotel.codFolleto,
        codHotel: hotel.codHotelCompletado || hotel.codigo,
        codRegimen: hotel.codRegimen,
        codProveedor: hotel.codProveedor,
        codSubzona: hotel.codSubzona,
        codDCP: hotel.codDCP,
        sesId: getSesId()
    }, extraParams);

   
    /* Fecha de hotel, si procede */
    if (!dataOut.fechaGraf && typeof obtenerFechaGrafico == "function") dataOut.fechaGraf = obtenerFechaGrafico();

    if (esSalto()) {
        //debugger;
        if (!proveedoresDatos_popup) { fixme("Falta 'proveedoresDatos_popup'"); return; }

        // Si provenimos de un salto saltamos el popup para pedir el origen
        openPopupURL(proveedoresDatos_popup.url, function() {
        /* Configura el buscador */
            fn.registrarEventosFormulario("#seleccionHotelBuscador");
            fn.buscador(["#seleccionHotelBuscador", proveedoresDatos_popup, "infoHabitacionesHiddenNuevaBusqueda"]);
            //fn.registrarEventosFormulario("#seleccionHotelBuscador");
        }, dataOut);

    } else {

        // Pantalla de espera, si se ha cargado
        if (typeof showLoader == "function") fn.espera2(literales.pantallaEsperaVuelos);

        if (!target) { fixme("No se proviene de un salto"); return; }

        // Si no provenimos de un salto, pasamos a la pantalla de Resultados Detalle
        loadXmlData(proveedoresDatos.seleccionarHotel,
                    dataOut,
                    function(data) {//Guardado de resultados
                        // Mensajes
                        var msg = ["", ""];

                        if (msg[0]) {
                            /* El servidor devuelve un aviso */
                            if (typeof mostrarMensaje == "function") mostrarMensaje(msg[0], msg[1]);
                            else alert(msg[0] + ". " + msg[1]);
                            if (typeof hideLoader == "function") hideLoader();
                        }
                        else {
                            /* Todo Ok */
                            sendData(target, { sesId: getSesId() });
                        }
                    },
                    function() {
                        $("#aviso .contenido h3").html("No hay disponibilidad de vuelos");
                        $("#aviso .contenido p").html("");
                        $("#aviso").stop().slideDown();
                        if (typeof hideLoader == "function") hideLoader();
                    });

    }

}

/* Definición del buscador */
fn.buscador = function(params) {
    //debugger;
    var form = params[0] || "#buscador";
    var providers = params[1] || proveedoresDatos;
    var hidden = params[2] || "infoHabitacionesHidden"
    var isPopup = $(".popup " + form).size() > 0 ? true : false;

    var fechasSalida = [];
    var rangoFechas = { min: null, max: null }
    var valoresDefecto = {
        idNivel1: "",
        idNivel2: "",
        idNivel3: "",
        codOrigen: "",
        dia: "",
        AnoMes: "",
        nochesSolicitadas: "",
        habitaciones: []
    };

    // Atajo a campo
    var c = function(name) { return $(form + " select[name$='" + name + "'], " + form + " input[name$='" + name + "']"); }

    //Si descomentamos falla popup BusquedaNinos en HOME
    //fn.registrarEventosFormulario(form);

    //    var comboAdultos = function() {
    //        var form = "#buscador";
    //        var c = function(name) { return $(form + " select[name$='" + name + "'], " + form + " input[name$='" + name + "']"); }
    //        if (document.getElementsByName("numAdultos").length > 0) {
    //            numAdultos.innerHTML = _Adultos;
    //        }
    //    }

    //    c("habitacion1_adultos").change(comboAdultos);

    // Indica si deben aparecer los campos de destino o no.
    var bloquearDestino = parseInt(c("bloquearDestino").val()) ? true : false;

    // Restriccion de entrada a numeros solamente
    var soloNumeros = function(target) {
        if (target.type) target = this;
        $(target).val($(target).val().replace(/[^0-9]/gi, ''));
    }

    var limpiarLista = function(combo, loading) {

        if (typeof (combo) == "string") combo = $(form + " select[name$='" + combo + "']");

        // Limpiamos el select
        $("option", combo.disable()).remove();

        if (loading) $(combo).append("<option>" + (literales.comboLoading || "Cargando...") + "</option>");
    }

    /* Funcion al seleccionar origen */
    var crearLista = function(lista, combo, dataAttr, labelAttr, customLabel, customReg, defaultValueAttr) {

        if (typeof (combo) == "string") {
            var comboName = combo;
            combo = $(form + " select[name$='" + combo + "']");
        } else {
            var comboName = combo.attr('name');
        }
        var changeTrigger = false;
        //var comboName = combo.attr('name');

        // Tags que leera para asignar el valor y la etiqueta de la opción del select.
        // Puede especificarse en el 3er y 4o parámetro en cada llamada a la funcion 'crearLista()'
        dataAttr = dataAttr != null ? dataAttr : "> Cod";
        labelAttr = labelAttr != null ? labelAttr : "> Nom";
        defValAttr = defaultValueAttr != null ? defaultValueAttr : "> Seleccionado";

        var hasSelection = false;
        var optionList = "";
        // Añadimos los elementos
        lista.each(function() {
            var selected = "";
            var selecAttr = defValAttr ? $(defValAttr, this).text() : "false";
            var data = dataAttr ? $(dataAttr, this).text() : $(this).text();
            var label = labelAttr ? $(labelAttr, this).text() : data;
            if (customLabel && customReg) label = customLabel.replace(customReg, label);
            if (valoresDefecto[comboName]) {
                // Si la seleccion se obtiene por una petición a parte
                if (data == valoresDefecto[comboName]) {
                    selected = "selected='selected'";
                    changeTrigger = true;
                    hasSelection = true;
                }
            } else {
                // Si la seleccion viene por el XML
                if (selecAttr == "true") {
                    selected = "selected='selected'";
                    changeTrigger = true;
                    hasSelection = true;
                }
            }
            if (literales.comboDefault != label) {
                optionList += "<option value='" + data + "' " + selected + ">" + label + "</option>";
            }
        });

        // Primera opción sin valor y por defecto. Si no hay una seleccion y si la lista es superior a 1 elemento
        if (!hasSelection && lista.size() > 1) optionList = "<option value='' selected='selected'>" + literales.comboDefault + "</option>" + optionList;

        // Añadimos la lista al combo
        combo.append(optionList);

        // Si la lista solo tiene 1 elemento provocamos la carga del siguiente nivel
        if (lista.size() == 1) changeTrigger = true;

        combo.enable();
        if (changeTrigger) {
            valoresDefecto[comboName] = "";
            combo.change();
        }
    }

    var comprobarSelectHabitaciones = function() {

        var j = 0, v;
        var numTotAdultos = 0;
        var numTotNinos = 0;

        // Cargamos los valores por defecto, si los hay
        if (valoresDefecto['habitaciones'].length > 0) {

            c("habitaciones").val(valoresDefecto['habitaciones'].length);

            j = 0;
            $(form + " .habitacionFormulario").each(function() {
                var h, i;
                if (h = valoresDefecto['habitaciones'][j]) {
                    if (h.adultos) {
                        numTotAdultos = numTotAdultos + h.adultos;
                        $("[name$='_adultos'] option", this).removeAttr("selected");
                        $("[name$='_adultos'] option[value='" + h.adultos + "']", this).attr("selected", true);
                    }
                    if (h.ninos) {
                        numTotNinos = numTotNinos + h.ninos;
                        $("[name$='_ninos'] option", this).removeAttr("selected");
                        $("[name$='_ninos'] option[value='" + h.ninos + "']", this).attr("selected", true);
                    }
                    for (i in h.edades) {
                        $("[name$='_edadnino" + (parseInt(i) + 1) + "'] option", this).removeAttr("selected");
                        $("[name$='_edadnino" + (parseInt(i) + 1) + "'] option[value='" + h.edades[i] + "']", this).attr("selected", true);
                    }
                }
                j++;
                $("[name$='_adultos'] option[value='" + numTotAdultos + "']", this).attr("selected", true);
                $("[name$='_ninos'] option[value='" + numTotNinos + "']", this).attr("selected", true);
            });

            // Limpiamos
            valoresDefecto['habitaciones'] = [];
        }

        v = parseInt(c("habitaciones").val(), 10);
        j = 0;

        $(form + " .habitacionFormulario").each(function() {
            if (j < v) { $(this).addClass('visible').show(); }
            else { $(this).removeClass('visible').hide(); }
            j++;
        });
        // 07/01/2011 - Tarea 16153 Punto 5 - Mostrar el label de Hab.1 y los combos de adultos y niños.
        //        if (v <= 1) $(form + " .habitacionFormulario").addClass("simple");
        //        else $(form + " .habitacionFormulario").removeClass("simple");


        // Parche altura para la Home (problema al medir la altura del contenedor en jquery)
        if ($.fn.accordion) {
            var l = $(form + " .habitacionFormulario.visible:last");
            var f = $(form);
            var r = $(form + " .resizable");
            f.parent().height(l.offset().top + l.height() - f.offset().top + 10);
            r.height(l.offset().top + l.height() - r.offset().top + 10);
        }

        comprobarSelectNinos();
    }

    var comprobarSelectNinos = function() {
        $(form + " .habitacionFormulario").each(function() {
            var v = $(".numNinos", this).val();
            var j = 0;
            // Oculta los que no hacel falta y los deshabilita
            $(".edadNinoSelect", this).each(function() {
                if (j < v) {
                    $(this).show().attr("disabled", "");
                } else {
                    $(this).hide().attr("disabled", "disabled");
                }
                j++;
            });
            if (v == 0) {
                $(this).addClass("sinNinos");
                $(".edadNino", this).hide();
            } else {
                $(this).removeClass("sinNinos");
                $(".edadNino", this).show();
            }
        });
    }

    var comprobarCampos = function() {
        if (!bloquearDestino) {
            $(form + " select[name^='idNivel'], " + form + " select[name$='codOrigen']").each(function() {
                var lista = $("option[value]", this);
                if (lista.length < 1) {
                    limpiarLista(this.name);
                    $(this).disable();
                } // No hay options o existe solo una 1 opcion (seleccionar)
            });
        }

        if (nulo(c('codOrigen').val())) {
            c('nochesSolicitadas').disable().val('');
            c('dia').disable().val('');
            $('.datepicker-trigger', form).addClass("disabled").css({ opacity: .5 });
            $("option", c('dia')).removeAttr("selected");
            c('AnoMes').disable().val('');
            limpiarLista("AnoMes");
            limpiarLista("nochesSolicitadas");
            $(form + " .fechaSalida").text("");
            $(form + " .fechaRegreso").text("");
        } else {
            c('nochesSolicitadas').enable();
            c('dia').enable();
            c('AnoMes').enable();
            $('.datepicker-trigger', form).removeClass("disabled").css({ opacity: 1 });
        }

        comprobarSelectHabitaciones();
    }

    // Establece fecha desde el calendario
    var establecerFecha = function(e, date) {

        c('dia').val(date.getDate());
        c('AnoMes').val(date.getFullYear() + (date.getMonth() + 1 < 10 ? "0" : "") + (date.getMonth() + 1));

        seleccionFecha();

    }

    /* Funcion al seleccionar destino nivel 1 */
    var seleccionDestino1 = function(onComplete) {

        limpiarLista("idNivel2");
        limpiarLista("idNivel3");
        limpiarLista("codOrigen");
        limpiarLista("AnoMes");
        limpiarLista("nochesSolicitadas");
        limpiarLista("nochesSolicitadas");
        if (document.getElementById("destino") != null) {
            document.getElementById("destino").innerHTML = "";
            document.getElementById("salida").innerHTML = "";
            document.getElementById("regreso").innerHTML = "";
        }
        $(form + " .fechaSalida").text("");
        $(form + " .fechaRegreso").text("");
        if (nulo(c("idNivel1").val())) return;

        limpiarLista("idNivel2", true); // Muestra el mensaje 'cargando'

        loadXmlData(providers.buscador_comboDestino2, {
            idNivel1: c("idNivel1").val(),
            sesId: getSesId()
        }, function(data) {
            limpiarLista("idNivel2");
            crearLista($("ArrayOfAreaAreaSubArea", data), "idNivel2");
        });

        comprobarCampos();
        if (typeof onComplete == "function") onComplete();

    }

    /* Funcion al seleccionar destino nivel 2 */
    var seleccionDestino2 = function(onComplete) {

        limpiarLista("idNivel3");
        limpiarLista("codOrigen");
        limpiarLista("AnoMes");
        limpiarLista("nochesSolicitadas");
        if (document.getElementById("destino") != null) {
            document.getElementById("destino").innerHTML = "";
            document.getElementById("regreso").innerHTML = "";
            document.getElementById("salida").innerHTML = "";
        }
        $(form + " .fechaSalida").text("");
        $(form + " .fechaRegreso").text("");
        if (nulo(c('idNivel2').val())) return;

        limpiarLista("idNivel3", true); // Muestra el mensaje 'cargando'

        loadXmlData(providers.buscador_comboDestino3, {
            idNivel1: c('idNivel1').val(),
            idNivel2: c('idNivel2').val(),
            sesId: getSesId()
        }, function(data) {
            limpiarLista("idNivel3");
            crearLista($("ArrayOfAreaAreaSubAreaDestino", data), "idNivel3");
            comprobarCampos();
            if (typeof onComplete == "function") onComplete();
        });
        if (document.getElementById("destino") != null) {
            document.getElementById("destino").innerHTML = c("idNivel2")[0].item(c("idNivel2")[0].selectedIndex).text;
        }

    }

    /* Funcion al seleccionar destino nivel 3 */
    var seleccionDestino3 = function(onComplete) {
        limpiarLista("codOrigen");
        limpiarLista("AnoMes");
        limpiarLista("nochesSolicitadas");
        if (document.getElementById("destino") != null) {
            document.getElementById("destino").innerHTML = "";
            document.getElementById("regreso").innerHTML = "";
            document.getElementById("salida").innerHTML = "";
        }
        $(form + " .fechaSalida").text("");
        $(form + " .fechaRegreso").text("");
        if (document.getElementById("destino") != null) {
            document.getElementById("destino").innerHTML = c("idNivel2")[0].item(c("idNivel2")[0].selectedIndex).text
        }
        if (nulo(c("idNivel1").val()) || nulo(c("idNivel2").val()) || nulo(c("idNivel3").val())) {
            if (bloquearDestino) fixme("Error: No se ha definido un destino");
            return;
        }

        limpiarLista("codOrigen", true); // Cargando...

        loadXmlData(providers.buscador_comboOrigen, {
            idNivel1: c("idNivel1").val(),
            idNivel2: c("idNivel2").val(),
            idNivel3: c("idNivel3").val(),
            sesId: getSesId()
        }, function(data) {
            limpiarLista("codOrigen");
            crearLista($("DCPOrigen", data), "codOrigen");

            /* Cacheamos las fechas de salida */
            fechasSalida = [];

            $("DCPOrigen", data).each(function() {
                var o = {
                    min: $("> SalIni", this).text().substr(0, 10).split("-"), // Convierte la fecha de formato 2009-12-04T00:00:00 a un Array [Año, Mes, día]
                    max: $("> SalFin", this).text().substr(0, 10).split("-")
                }

                o.min = new Date(o.min[0], parseInt(o.min[1], 10) - 1, o.min[2]);
                o.max = new Date(o.max[0], parseInt(o.max[1], 10) - 1, o.max[2]);

                fechasSalida[$("> Cod", this).text()] = o;

            });

            comprobarCampos();

            if (typeof onComplete == "function") onComplete();
        });
        if (document.getElementById("destino") != null) {
            document.getElementById("destino").innerHTML = c("idNivel2")[0].item(c("idNivel2")[0].selectedIndex).text
            if (c("idNivel3")[0].item(c("idNivel3")[0].selectedIndex).text != literales.comboDefault) {
                document.getElementById("destino").innerHTML = c("idNivel2")[0].item(c("idNivel2")[0].selectedIndex).text + " / " + c("idNivel3")[0].item(c("idNivel3")[0].selectedIndex).text;
            }
        }
    }

    /* Funcion al seleccionar origen */
    var seleccionOrigen = function(onComplete) {

        limpiarLista("AnoMes");
        limpiarLista("nochesSolicitadas");
        $(form + " .fechaSalida").text("");
        $(form + " .fechaRegreso").text("");
        if (nulo(c("codOrigen").val())) return;
        $(form + " .fechaSalida").text("");
        $(form + " .fechaRegreso").text("");
        limpiarLista("AnoMes", true); // Mensaje 'cargando'
        limpiarLista("nochesSolicitadas", true);
        if (document.getElementById("regreso") != null) {
            document.getElementById("regreso").innerHTML = "";
            document.getElementById("salida").innerHTML = "";
        }
        loadXmlData(providers.buscador_comboEstancia, {
            idNivel1: c("idNivel1").val(),
            idNivel2: c("idNivel2").val(),
            idNivel3: c("idNivel3").val(),
            sesId: getSesId()
        }, function(data) {

            limpiarLista("AnoMes");
            limpiarLista("nochesSolicitadas");

            // Dia por defecto?
            if (valoresDefecto['dia']) {
                c("dia").val(valoresDefecto['dia']);
                $("option", c("dia")).removeAttr("selected");
                $("option[value='" + parseInt(valoresDefecto['dia'], 10) + "']", c("dia")).attr("selected", "selected");
            }

            crearLista($("Noche", data), "nochesSolicitadas", "", "", literales.noche[1], /%n/gi);

            var salida = fechasSalida[c("codOrigen").val()]; /* Recupera la fecha del listado anterior */
            var cur = new Date(salida.min.getTime());

            rangoFechas.min = new Date(salida.min.getTime());
            rangoFechas.max = new Date(salida.max.getTime());

            // Asignamos nuevo margen al datepicker
            if ($.fn.datePicker) {
                $(".datepicker-trigger", form).dpSetStartDate(rangoFechas.min);
                $(".datepicker-trigger", form).dpSetEndDate(rangoFechas.max);
            }

            var xmlMeses = "";
            var lastM = -1;

            while (cur <= salida.max) {
                if (cur.getMonth() != lastM) { // Si cambia mes
                    lastM = cur.getMonth();
                    xmlMeses += "<li><label>" + cur.format(literales.fechaCombo) + "</label><var>" + cur.format("yyyymm") + "</var></li>";
                }
                cur.setTime(cur.getTime() + 24 * 60 * 60 * 1000); // avanza 1 dia
            }

            /* Empleamos etiquetas HTML porque tienen que ser validas (para que funcione en IE */
            xmlMeses = $("<ul></ul>").html(xmlMeses);

            crearLista($("li", xmlMeses), "AnoMes", "var", "label");

            comprobarCampos();

            if (typeof onComplete == "function") onComplete();

        });
    }

    var cargarValoresDefecto = function(onComplete) {

        if (!providers.buscador_valoresDefecto) {
            // No hay valores por defecto que cargar
            if (typeof onComplete == "function") onComplete();
            return;
        }

        loadXmlData(providers.buscador_valoresDefecto, {

            sesId: getSesId()

        }, function(data) {

            var fecha = $("SalidaBusqueda", data).text().split("-");
            if (!bloquearDestino) {
                valoresDefecto['idNivel1'] = $("DestinoN1Busqueda", data).text();
                valoresDefecto['idNivel2'] = $("DestinoN2Busqueda", data).text();
                valoresDefecto['idNivel3'] = $("DestinoN3Busqueda", data).text();
            }

            valoresDefecto['dia'] = fecha[2];
            valoresDefecto['AnoMes'] = fecha[0] + fecha[1];
            valoresDefecto['codOrigen'] = $("OrigenBusqueda", data).text();
            valoresDefecto['nochesSolicitadas'] = $("NumNochesBusqueda", data).text();

            valoresDefecto['habitaciones'] = [];

            // Habitaciones
            $("Habitacion", data).each(function() {

                var o = {
                    adultos: $("Adultos", this).text(),
                    ninos: $("Ninos", this).text(),
                    edades: []
                }

                $("Edad", this).each(function() { o.edades.push($(this).text()); });

                valoresDefecto['habitaciones'].push(o);

            });

            if (typeof onComplete == "function") onComplete()

        });

    }

    /* Funcion al seleccionar fecha */
    var seleccionFecha = function() {

        soloNumeros(c("dia"));

        var dia = parseInt(c("dia").val(), 10);
        var anomes = c("AnoMes").val();
        var estancia = parseInt(c("nochesSolicitadas").val(), 10);
        if (document.getElementById("regreso") != null) {
            document.getElementById("regreso").innerHTML = "";
            document.getElementById("salida").innerHTML = "";
        }
        $(form + " .fechaSalida").html("&nbsp;");
        $(form + " .fechaRegreso").html("&nbsp;");

        if (!dia) { c("dia").val(""); return; };
        if (!anomes) return;

        var fSalida = new Date(anomes.substr(0, 4), parseInt(anomes.substr(4, 2), 10) - 1, dia);

        if (fSalida.getMonth() != parseInt(anomes.substr(4, 2), 10) - 1) {
            c("dia").val("1");
            $("option", c("dia")).removeAttr("selected");
            $("option:first", c("dia")).attr("selected", "selected");
            dia = 1;
            fSalida = new Date(anomes.substr(0, 4), parseInt(anomes.substr(4, 2), 10) - 1, dia);
        }

        $(form + " .fechaSalida").text(fSalida.format(literales.fechaFormateada));
        if (document.getElementById("salida") != null) {
            document.getElementById("salida").innerHTML = fSalida.format(literales.fechaFormateada);
        }
        if (!estancia) return;
        var fRegreso = new Date(fSalida.getFullYear(), fSalida.getMonth(), fSalida.getDate() + estancia);

        $(form + " .fechaRegreso").text(fRegreso.format(literales.fechaRegreso));
        if (document.getElementById("regreso") != null) {
            document.getElementById("regreso").innerHTML = fRegreso.format(literales.fechaFormateada);
        }
        comprobarCampos();
    }

    /* Funcion al pulsar buscar */
    var submit = function(e) {
        e.preventDefault();

        var hotel, nhab, nnin, faltaNin = false;

        /* Comprobacion de select de la edad de los niños */
        nhab = parseInt(c("habitaciones").val(), 10);
        for (var j = 1; j <= nhab; j++) {
            nnin = parseInt(c("habitacion" + j + "_ninos").val(), 10);
            if (nnin > 0) {
                //for (var k = 1; k <= nnin; k++) {
                //if (c("habitacion" + j + "_edadnino" + k).val() == "") {
                if (c("infoEdadesNinosHabitacion" + j).val() == "") {
                    faltaNin = true;
                }
                //}
            }
        }

        if (nulo(c("idNivel1").val()) ||
			nulo(c("idNivel2").val()) ||
			nulo(c("idNivel3").val()) ||
			nulo(c("codOrigen").val()) ||
			!parseInt(c("dia").val(), 10) ||
			nulo(c("AnoMes").val()) ||
			nulo(c("nochesSolicitadas").val()) ||
			faltaNin == true) {

            var faltan = [];

            /* Recopilacion de campos que faltan */
            if (nulo(c("idNivel1").val()) || nulo(c("idNivel2").val()) || nulo(c("idNivel3").val())) faltan.push(literales.campoDestino || "Destino");
            if (nulo(c("codOrigen").val())) faltan.push(literales.campoOrigen || "Origen");
            if (!parseInt(c("dia").val(), 10) || nulo(c("AnoMes").val())) faltan.push(literales.campoDiaSalida || "Día de salida");
            if (nulo(c("nochesSolicitadas").val())) faltan.push(literales.campoEstancia || "Estancia");
            if (faltaNin) faltan.push(literales.campoEdadNinos || "Edad de los niños");

            alert((literales.formIncompleto || "Faltan: %s").replace(/%s/g, faltan.join(", ")));

            return; // Formulario incompleto

        }

        // Mostramos el Loader, si está inicializado 
        if (typeof showLoader == "function") showLoader(isPopup);

        // Construccion del XML que define las habitaciones
        var setHabitacion = { Habitacion: [] }, o, n;
        nhab = parseInt(c("habitaciones").val(), 10);

        for (var j = 1; j <= nhab; j++) {
            o = {
                Adults: c("habitacion" + j + "_adultos").val(),
                Children: c("habitacion" + j + "_ninos").val(),
                EdadesNinos: { Edad: [] }
            };
            var nins = "";
            if (parseInt(o.Children, 10) > 0) {
                nins = c("infoEdadesNinosHabitacion" + j).val().split(",");
            }
            for (var k = 1; k <= parseInt(o.Children, 10); k++) {
                o.EdadesNinos.Edad.push(nins[k - 1]);
            }
            setHabitacion.Habitacion.push(o);
        }
        var resultado;
        resultado = XMLStringSinCabecera(setHabitacion, "Habitaciones", false);
        var dataOut = {

            idNivel1: c("idNivel1").val(),
            idNivel2: c("idNivel2").val(),
            idNivel3: c("idNivel3").val(),
            codOrigen: c("codOrigen").val(),
            NombreOrigen: $(":selected", c("codOrigen")).text(),
            NombreDestino: $(":selected", c("idNivel3")).text(),
            dia: (parseInt(c("dia").val(), 10) < 10 ? "0" : "") + parseInt(c("dia").val(), 10),
            AnoMes: c("AnoMes").val(),
            nochesSolicitadas: c("nochesSolicitadas").val(),
            habitaciones: XMLString(setHabitacion, "Habitaciones"),
            //habitaciones: c("" + hidden + "").val(),
            soloOfertas: $(form + " input[type=hidden][id$=ParamSoloOferta]").val() || 0,
            sesId: getSesId()

        }
        //c("" + hidden + "").val("")
        // Si es el formulario que complementa al Salto
        if (bloquearDestino) {
            if (hotel = obtenerHotelSeleccionado()) {

                dataOut.folleto = hotel.codFolleto;
                dataOut.codDCP = hotel.codDCP;
                dataOut.codPaquete = hotel.codPaquete;
                dataOut.codRegimen = hotel.codRegimen;
                dataOut.codHotel = hotel.codHotelCompletado;
                dataOut.codProveedor = hotel.codProveedor;
                dataOut.codSubzona = hotel.codSubzona;


            } else {

                fixme("No se pudo recuperar el hotel seleccionado.");

            }

        }

        /* Enviamos los datos del formulario por AJAX */
        loadData(providers.buscador_buscar, dataOut, function(data) {

            // Comprobacion de la respuesta del servidor
            if (data.substr(0, 2).toUpperCase() == "KO") {

                // Ocultamos el loader, si está inicializado 
                if (typeof hideLoader == "function") hideLoader();

                // Mensaje devuelto por el servidor
                alert(data.substr(3));

            } else if (data.substr(0, 2).toUpperCase() == "OK") {

                $(form).unbind("submit");

                // Pasamos por POST el sesId recibido
                $("input[name='sesId']", form).remove();
                $(form).append("<input name='sesId' type='hidden' value='" + data.substr(3) + "' />");

                // Realiza el submit original
                $(form).submit();

            } else {

                // Ocultamos el loader, si está inicializado 
                if (typeof hideLoader == "function") hideLoader();

                fixme("Respuesta del servidor inesperada: " + data);

            }

        });

    }

    function iniciarValoresDefecto() {

        // Selecciona el primer elemento y simula un change
        if (valoresDefecto['idNivel1']) {
            $("select[name$=idNivel1] option[value=" + valoresDefecto['idNivel1'] + "]").attr("selected", "selected");
            seleccionDestino1();
        }

    }

    // Detectores de cambios en el formulario Planear Mi Viaje
    c("habitaciones").change(comprobarSelectHabitaciones);
    $(form + " .numNinos").change(comprobarSelectNinos);

    if (!bloquearDestino) {
        c("idNivel1").change(seleccionDestino1);
        c("idNivel2").change(seleccionDestino2);
        c("idNivel3").change(seleccionDestino3);
    } else {
        c("idNivel1").disable();
        c("idNivel2").disable();
        c("idNivel3").disable();
    }
    c("codOrigen").change(seleccionOrigen);
    c("dia").change(seleccionFecha);
    c("dia").blur(soloNumeros);
    c("AnoMes").change(seleccionFecha)
    c("nochesSolicitadas").change(seleccionFecha);

    $(form).submit(submit);

    // Calendario
    if ($.fn.datePicker) {
        $(".datepicker-trigger", form).datePicker({ createButton: false }).bind('click', function() {
            var tar = $(this);
            if (tar.hasClass("disabled")) return false;
            tar.dpDisplay();
            // Pre-seleccion de la fecha escogida
            var sel = tar.dpGetSelected();
            for (var i in sel) {
                tar.dpSetSelected(sel[i].format(Date.format), false, true, false);
            }
            // Eliina literales de salida y regreso
            $(form + " .fechaSalida").html("&nbsp;");
            $(form + " .fechaRegreso").html("&nbsp;");
            // Lo restaura si cerramos
            $(this).bind("dpClosed", function() { seleccionFecha() });
            var dat = c("AnoMes").val();
            var day = c("dia").val();
            if (dat) {
                if (day) {
                    tar.dpSetSelected(new Date(parseInt(dat.substr(0, 4), 10), parseInt(dat.substr(4), 10) - 1, parseInt(day, 10)).format(Date.format), true, true, false);
                } else {
                    tar.dpSetDisplayedMonth(parseInt(dat.substr(4), 10) - 1, parseInt(dat.substr(0, 4), 10));
                }
            }

            // Boton cerrar
            $("<a class='close' href='#'><img src='" + getImagePath() + "cerrar.gif' /></a>")
				.prependTo("#dp-popup .dp-nav-next")
				.click(function(e) { e.preventDefault(); tar.dpClose() });
            tar.blur();
            return false;
        }).bind('dateSelected', establecerFecha);
    } else {
        $(".datepicker-trigger").hide();
    }

    // Primera carga automática, si está el destino bloqueado
    cargarValoresDefecto(bloquearDestino ? seleccionDestino3 : iniciarValoresDefecto)

    comprobarCampos();

}

/* Definición del popup y sus funciones */
fn.popup = function(instanceName, autodestroy, customClass, actionCerrar) {
    var visible = false;
    var instance = {};

    // Si intentamos crear uno generico y ya está definido 
    if (typeof openPopupURL == "function" && !instanceName) return;

    // IDs a manejar
    var names = {
        cortina: 'cortina' + (instanceName != "" ? '_' + instanceName : ''),
        popup: 'popup' + (instanceName != "" ? '_' + instanceName : ''),
        popupdata: 'popupData' + (instanceName != "" ? '_' + instanceName : '')
    }

    var actions = {
        cerrar: instanceName != "" ? instanceName + ".hide()" : "hidePopup()"
    }

    if (actionCerrar != null) {
        actions = {
            cerrar: instanceName != "" ? actionCerrar + instanceName + ".hide()" : "hidePopup()"
        }
    }

    var pathImagenes = "." + urlImagenesWebConfig + "/";
    if (typeof opciones != "undefined") if (opciones.pathImagenes) pathImagenes = opciones.pathImagenes;

    var popupcode = "";
    popupcode += "<div id='" + names.cortina + "' class='cortina " + customClass + "'></div>";
    popupcode += "<div id='" + names.popup + "' class='popup " + customClass + "'>";
    popupcode += "	<div class='popupTop'></div>";
    popupcode += "	<div class='popupContent'>";
    popupcode += "		<div class='popupHeader'>";
    popupcode += "			<img src='" + pathImagenes + "logoPieHome.jpg' width='40' height='20' />";
    popupcode += "			<a href='javascript:" + actions.cerrar + "'><img src='" + pathImagenes + "cerrar.gif' width='14' height='13' alt='" + (literales.cerrarVentana || "Cerrar ventana") + "'/></a>";
    popupcode += "		</div>";
    popupcode += "		<div id='" + names.popupdata + "' class='popupData'></div>";
    popupcode += "		<div class='popupFooter'>";
    popupcode += "			<a class='cerrar' href='javascript:" + actions.cerrar + "'>" + (literales.cerrarVentana || "Cerrar ventana") + "</a>";
    popupcode += "		</div>";
    popupcode += "	</div>";
    popupcode += "	<div class='popupBottom'></div>";
    popupcode += "</div>";

    $('body').append(popupcode);

    instance.intervalId = 0;
    instance.autodestroy = autodestroy;
    instance.name = instanceName;
    instance.cortina = $('#' + names.cortina);
    instance.popup = $('#' + names.popup);
    instance.popupdata = $('#' + names.popupdata);

    instance.openURL = function(url, proccess, data, smallStyle) {

        var self = this;

        var hayDatos = false;
        for (var i in data) { hayDatos = true; break; }

        if (!url.split("#").shift() || url.split("#").shift() == document.location.href) { fixme("No se ha definido una URL de contenido"); return; }

        $("#contenedor").css({ "cursor": "progress" });

        $.ajax({
            type: hayDatos ? "post" : "get",
            url: url,
            data: hayDatos ? data : undefined,
            dataType: "html",
            success: function(code) {

                if (pageTracker) {

                    if (url.search("http://") == 0) {
                        // Debemos pasar la URL a relativa
                        var urlrel = url.replace("http://", "");
                        urlrel = urlrel.substring(urlrel.search("/") + 1);
                        pageTracker._trackPageview(urlrel);
                    }
                    else pageTracker._trackPageview(url);
                }
                $("#contenedor").css({ "cursor": "default" });

                // Solo extraemos el contenido del página
                //var proc = $(document.createElement("div")).html( code );				
                var proc = $("<div>" + code + "</div>");
                if (!proc.html()) fixme("Ocurrió un error al procesar el contenido HTML");

                self.openHTML($("#contenido", proc).html(), proccess, smallStyle);

            },
            error: ajaxError
        });

    }

    instance.openHTML = function(content, onComplete, smallStyle) {

        var self = this;

        if (visible) {
            hidePopup(function() {
                self.popupdata.html(content);
                fixIE(self.popupdata);
                self.show(smallStyle);
                if (typeof onComplete == "function") onComplete();
            }, true);
        } else {
            self.popupdata.html(content);
            fixIE(self.popupdata);
            self.show(smallStyle);
            if (typeof onComplete == "function") onComplete();
        }
    }

    instance.show = function(smallStyle) {

        var self = this;

        visible = true;
        _popups.push(self);

        if (smallStyle) self.popup.addClass("small");
        else self.popup.removeClass("small");

        // position
        self.popup.css({
            left: $(window).width() / 2 - self.popup.width() / 2,
            top: Math.max($(window).scrollTop(), $(window).scrollTop() + ($(window).height() - self.popup.height()) / 2)
        });

        self.popup.stop().show();
        self.cortina.stop().show().height($(document).height()).fadeTo("fast", .5);
        self.popup.hide();
        self.popup.slideDown("fast");

    }

    instance.hide = function(onComplete, noclear) {
//debugger;
        var self = this;
        for (var i in _popups) if (_popups[i] == self) _popups.slice(i, i);

        if (!noclear) self.cortina.stop().fadeTo("fast", 0, function() { $(this).hide(); });
        self.popup.stop().fadeOut("fast", function() {
            $(this).hide();
            self.popupdata.html('');
            if (typeof onComplete == "function") onComplete();
            if (self.autodestroy) self.destroy();
        });

        visible = false;
        _NumeroAmigo=0; 
    }

    instance.destroy = function() {

        var self = this;

        if (self.intervalId) clearInterval(self.intervalId);
        self.popup.remove();
        self.cortina.remove();
        window[self.name] = null;
        self.instance = null;

    }

    if (instanceName == "") {

        /* proxies para el popup generico */
        window.openPopupURL = function() { return instance.openURL.apply(instance, arguments); }
        window.openPopupHTML = function() { return instance.openHTML.apply(instance, arguments); }
        window.showPopup = function() { return instance.show.apply(instance, arguments); }
        window.hidePopup = function() { return instance.hide.apply(instance, arguments); }

    } else {

        window[instanceName] = instance;

    }

    instance.cortina.hide().css({ opacity: 0 });

    // Ajusta la cortina a la altura del contenido en IE (revisar)
    instance.intervalId = setInterval(function() {
        instance.cortina.height($("body").height());
    }, 1000);

    return instance;

}

fn.popupLinks = function(env) {

    if (!env) env = document;

    $("a.toPopup", env).click(function(e) {
    e.preventDefault();
    e.stopImmediatePropagation();


        if (!this.href) return;
        if (!this.href.split("#").shift()) return;

        var name = "popup" + (new Date()).getTime();
        var instance = fn.popup(name, true, "contenidoEstatico popuplink");

        instance.openURL(this.href.split("#").shift(), null, null);

    });
}

aceptarHabitaciones = function() {
    /* Construccíón del xml con datos de habitaciones, numero de adultos y niños y sus edades */
    var setHabitacion = { Habitacion: [] }, o, n;
    nhab = document.getElementById("habitaciones").value;
    for (var j = 1; j <= nhab; j++) {
        o = {
            Adults: document.getElementById("habitacion" + j + "_adultos").value,
            Children: document.getElementById("habitacion" + j + "_ninos").value,
            EdadesNinos: { Edad: [] }
        };
        for (var k = 1; k <= parseInt(o.Children, 10); k++) {
            o.EdadesNinos.Edad.push(document.getElementById("habitacion" + j + "_edadnino" + k).value);
        }
        setHabitacion.Habitacion.push(o);
    }
    infoHabitacionesHidden.value = XMLStringSinCabecera(setHabitacion, "Habitaciones", true);
}

calcularDatosResumenNinos = function(edades) {
    //debugger;
    var stringNinos = "";

    for (var i = 0; i < edades.length; i++) {
        if (edades[i] != 0) {
            if (stringNinos != "") {
                stringNinos = stringNinos + ", ";
            }
            stringNinos = stringNinos + " " + edades[i] + " (" + i + " " + literales.anios + ")";
        }
    }

    return stringNinos;
}

combosHab = function(pantalla) {
    var form = "#buscador";
    if (pantalla == 2) {
        form = "#seleccionHotelBuscador";
    }

    var h = function(name) { return $(form + " select[name$='" + name + "'], " + form + " input[name$='" + name + "']"); }
    h("habitaciones").val(_Habitaciones);
    h("habitacion1_adultos").val(_Adultos);
    h("habitacion1_ninos").val(_Ninos);

}
fn.cerrarRegimenAlojamiento = function(formHome) {
//debugger;
    //var formHome = "#buscador";
    var edades = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];

    var h = function(name) { return $(formHome + " select[name$='" + name + "'], " + formHome + " input[name$='" + name + "']"); }
    h("habitaciones").val(_Totalhab);
    for (var i = 0; i < _Totalhab; i++) {
        h("habitacion" + (i + 1) + "_adultos").val(_adultosHab[i]);
        h("habitacion" + (i + 1) + "_ninos").val(_ninosHab[i]);
        h("infoEdadesNinosHabitacion" + (i + 1)).val(_edadNinosHab[i]);
        if (_ninosHab[i] > 0) {
            var aen = _edadNinosHab[i].split(",");
            for (var j = 0; j < aen.length; j++) {
                var edad = parseInt(aen[j], 10);
                edades[edad] = edades[edad] + 1;
            }
        }
    }
    if (document.getElementById("numNinios") != null) {
        document.getElementById("numNinios").innerHTML = calcularDatosResumenNinos(edades);
    }

}
fn.cancelarRegimenAlojamiento = function(formHome) {
//debugger;
    //var formHome = "#buscador";
    var h = function(name) { return $(formHome + " select[name$='" + name + "'], " + formHome + " input[name$='" + name + "']"); }
    var arrayIdx = new Array(_Totalhab);
    for (var i = 0; i < _Totalhab; i++) {
        arrayIdx[i] = h("infoEdadesNinosHabitacion" + (i + 1)).val();
        if (arrayIdx[i] == "") {
            h("habitacion" + (i + 1) + "_ninos").val(0);
        }
        else {
            var v = arrayIdx[i].split(',');
            h("habitacion" + (i + 1) + "_ninos").val(v.length);
        }
    }
}




fn.btnAceptarHabitaciones_click = function(obj) {
//debugger;
    var form = "#BusquedaNinos";
    var name = "popupBusquedaNinos";
    var h = function(id) { return $(form + " select[name$='" + id + "'], " + form + " input[name$='" + id + "']"); }
    for (var i = 0; i < _Totalhab; i++) {
        _adultosHab[i] = h("habitacion" + (i + 1) + "_adultos").val();
        _ninosHab[i] = h("habitacion" + (i + 1) + "_ninos").val();
        if (_ninosHab[i] > 0) {
            _edadNinosHab[i] = "";
            for (var j = 0; j < _ninosHab[i]; j++) {
                if (h("habitacion" + (i + 1) + "_edadnino" + (j + 1)).val() != "") {
                    if (_edadNinosHab[i] != "") {
                        _edadNinosHab[i] = _edadNinosHab[i] + ",";
                    }
                    _edadNinosHab[i] = _edadNinosHab[i] + h("habitacion" + (i + 1) + "_edadnino" + (j + 1)).val();
                }
                else {
                    //Mensaje, faltan llenar los combos de edades de los niños
                    alert("'" + literales.formIncompleto.replace(/%s/g, literales.campoEdadNinos + "'"));
                    return false;
                }
            }

        }
    }
    var formOrigen = "#" + h("formOrigen").val();
    var instance = fn.popup(name, true, "contenidoEstatico popuplink", "");
    instance.hide(fn.cerrarRegimenAlojamiento(formOrigen), true);
}



fn.registrarEventosHome = function() {
    fn.registrarEventosFormulario("#buscador");
}


//fn.registrarEventosPopupBusquedaNinios = function() {
//    fn.registrarEventosFormulario("#BusquedaNinos");
//}

fn.registrarEventosFormulario = function(formOrigen) {
//debugger;
    if (formOrigen == "#buscador") { fn.asignarEventosPopup("", formOrigen, "#"); }
    else { fn.asignarEventosPopup(formOrigen, formOrigen, ""); }

}



calcularNumeroNinos = function(prefijo, form) {
var edades = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
var h = function(id) { return $(form + " select[name$='" + id + "'], " + form + " input[name$='" + id + "']"); }
 _Totalhab = parseInt(h("habitaciones").val(), 10);
 
  for (var i = 0; i < _Totalhab; i++) {
        var numninos=parseInt(h("habitacion" + (i + 1) + "_ninos").val(),10);
        var edadesninoshab=h("infoEdadesNinosHabitacion" + (i + 1)).val();
        if (numninos > 0) {
            var aen = edadesninoshab.split(",");
            for (var j = 0; j < aen.length; j++) {
                var edad = parseInt(aen[j], 10);
                edades[edad] = edades[edad] + 1;
            }
        }
    }
    
//    $("numNinios").html(calcularDatosResumenNinos(edades));
    if (document.getElementById("numNinios") != null) {
        document.getElementById("numNinios").innerHTML = calcularDatosResumenNinos(edades);
    }


 
}

calcularNumeroAdultos = function(prefijo, formOrigen) {
    var h = function(name) { return $(prefijo + " select[name$='" + name + "'], " + prefijo + " input[name$='" + name + "']"); }
    var total = 0;
    var habitaciones = parseInt(h("habitaciones").val(), 10);
    if (habitaciones == 1) {
        total = h("habitacion1_adultos").val();
    }
    else if (habitaciones == 2) {
        total = parseInt(h("habitacion1_adultos").val(), 10) + parseInt(h("habitacion2_adultos").val(), 10);
    }
    else {
        total = parseInt(h("habitacion1_adultos").val(), 10) + parseInt(h("habitacion2_adultos").val(), 10) + parseInt(h("habitacion3_adultos").val(),10);
    }
    document.getElementById("numAdultos").innerHTML = total;
}



fn.asignarEventosPopup = function(prefijo, formOrigen, tag) {

    var h = function(name) { return $(prefijo + " select[name$='" + name + "'], " + prefijo + " input[name$='" + name + "']"); }
    //document.getElementById("seleccionHotelBuscador").getElementsByTagName("a").namedItem("id_EspecificarNinos")
    $(prefijo + " a[name$='id_EspecificarNinos']").click(function() {
        abrirPopupNumeroNinos(0, formOrigen);
    });

    h("habitaciones").change(function() {
        if (document.getElementById("numHabits") != null) {
            document.getElementById("numHabits").innerHTML = h("habitaciones").val();
        }
        if (document.getElementById("numAdultos") != null) {
            calcularNumeroAdultos(prefijo, formOrigen);
        }

        calcularNumeroNinos(prefijo, formOrigen);

    });
    h("habitacion1_adultos").change(function() {
        if (document.getElementById("numAdultos") != null) {
            calcularNumeroAdultos(prefijo, formOrigen);
        }
    });
    h("habitacion2_adultos").change(function() {
        if (document.getElementById("numAdultos") != null) {
            calcularNumeroAdultos(prefijo, formOrigen);
        }
    });
    h("habitacion3_adultos").change(function() {
        if (document.getElementById("numAdultos") != null) {
            calcularNumeroAdultos(prefijo, formOrigen);
        }
    });

    h("habitacion1_ninos").change(function() {
        abrirPopupNumeroNinos(1, formOrigen)
    });
    h("habitacion2_ninos").change(function() {
        abrirPopupNumeroNinos(2, formOrigen);
    });
    h("habitacion3_ninos").change(function() {
        abrirPopupNumeroNinos(3, formOrigen);
    });
}


abrirPopupNumeroNinos = function(idx, formHome) {
    //debugger;
    var name = "popupBusquedaNinos";
    //var formHome = "#buscador";
    var h = function(name) { return $(formHome + " select[name$='" + name + "'], " + formHome + " input[name$='" + name + "']"); }

    _Totalhab = h("habitaciones").val();
    _adultosHab = new Array(_Totalhab);
    _ninosHab = new Array(_Totalhab);
    _edadNinosHab = new Array(_Totalhab);

    for (var i = 0; i < _Totalhab; i++) {
        _adultosHab[i] = h("habitacion" + (i + 1) + "_adultos").val();
        _ninosHab[i] = h("habitacion" + (i + 1) + "_ninos").val();
        //_edadNinosHab[i] = document.getElementById("infoEdadesNinosHabitacion" + (i + 1)).value;
        _edadNinosHab[i] = h("infoEdadesNinosHabitacion" + (i + 1)).val();
    }
    if (h("habitacion" + idx + "_ninos").val() != 0 || idx == 0) {

        var url = proveedoresDatos.captura_ninios + "?formOrigen=" + formHome.substring(1);

        var instance = fn.popup(name, true, "contenidoEstatico popuplink", 'fn.cancelarRegimenAlojamiento("' + formHome + '");');
        instance.openURL(url, fn.recuperarRegimenAlojamiento, null);
    }
    else {
        h("infoEdadesNinosHabitacion" + (idx)).val("");
        fn.cerrarRegimenAlojamiento(formHome);
    }
}


fn.recuperarRegimenAlojamiento = function() {
//debugger;
    var form = "#BusquedaNinos";
    // emplenar els combos del popup amb la informació de fn.abrirPopupRegimenAlojamiento
    var h = function(id) { return $(form + " select[name$='" + id + "']"); }
    var l = function(id) { return $(form + " span[id$='" + id + "']"); }
    var s = function(id) { return $(form + " small[id$='" + id + "']"); }
    var p = function(id) { return $(form + " p[id$='" + id + "']"); }

    for (var i = 0; i < _Totalhab; i++) {
        h("habitacion" + (i + 1) + "_adultos").val(_adultosHab[i]);
        h("habitacion" + (i + 1) + "_adultos").show();

        h("habitacion" + (i + 1) + "_ninos").val(_ninosHab[i]);
        h("habitacion" + (i + 1) + "_ninos").change(function() {      
            var numHabitacion = this.id.substring(10, 11);
            //debugger;
            var numNin = h(this.id).val();
            if (numNin > 0) {
                p("e_habitacion" + numHabitacion + "_ninos").show();
                for (var j = 0; j < numNin; j++) {
                    h("habitacion" + numHabitacion + "_edadnino" + (j + 1)).show();
                    l("span_habitacion" + numHabitacion + "_edadnino" + (j + 1)).show();
                }
            }
            else {
                p("e_habitacion" + numHabitacion + "_ninos").hide();
            }
            for (var j = parseInt(numNin); j < 5; j++) {
                    h("habitacion" + numHabitacion + "_edadnino" + (j + 1)).hide();
                    l("span_habitacion" + numHabitacion + "_edadnino" + (j + 1)).hide();
            }
        });
        if (_ninosHab[i] > 0) {
            var edad = _edadNinosHab[i].split(',');
            for (var j = 0; j < parseInt(_ninosHab[i]); j++) {
                h("habitacion" + (i + 1) + "_edadnino" + (j + 1)).val(edad[j]);
                h("habitacion" + (i + 1) + "_edadnino" + (j + 1)).show();
            }
            for (var j = parseInt(_ninosHab[i]); j < 5; j++) {
                h("habitacion" + (i + 1) + "_edadnino" + (j + 1)).hide();
                l("span_habitacion" + (i + 1) + "_edadnino" + (j + 1)).hide();
            }
        }
        else {
            //Amagar els combos de les edats a busquedaNinos (display)
            p("e_habitacion" + (i + 1) + "_ninos").hide();
            for (var j = 0; j < 5; j++) {
                h("habitacion" + (i + 1) + "_edadnino" + (j + 1)).hide();
                l("span_habitacion" + (i + 1) + "_edadnino" + (j + 1)).hide();
            }
        }
    }
    for (var i = parseInt(_Totalhab); i < 3; i++) {
        h("habitacion" + (i + 1) + "_adultos").hide();
        l("span_habitacion" + (i + 1) + "_adultos").hide();
        p("p_habitacion" + (i + 1) + "_adultos").hide();

        h("habitacion" + (i + 1) + "_ninos").hide();
        l("span_habitacion" + (i + 1) + "_ninos").hide();
        s("small_habitacion" + (i + 1) + "_ninos").hide();
        p("e_habitacion" + (i + 1) + "_ninos").hide();

        for (var j = 0; j < 5; j++) {
            h("habitacion" + (i + 1) + "_edadnino" + (j + 1)).hide();
            l("span_habitacion" + (i + 1) + "_edadnino" + (j + 1)).hide();
        }
    }

}

/* Configuracion los desplegables de cabecera y pie */
fn.cabeceraPie = function() {

    var btClosed = false;
    var mouseIsOut = false;

    var close = function(top) {

        var pop = $(top ? "#popAgencias" : "#submenuPieFlotante");

        if ($.browser.msie && parseInt($.browser.version) < 7) {
            pop.hide();
        } else {
            $(".content", pop).slideUp("fast", function() {
                pop.hide();
            });
        }
    }

    var open = function(item, top) {

        var pop = $(top ? "#popAgencias" : "#submenuPieFlotante");
        var sub = $(item).parent().next("ul");

        if (!sub.size() && !top) return;

        if (!top) {
            // Copia el listado de opciones
            $("ul", pop).html(sub.html());

            // Cambia la imagen del titulo
            if ($(".titulo").size()) $(".titulo", pop).html($(item).parent().html());

            /* IE6 hover fix */
            if ($.browser.msie && parseInt($.browser.version) < 7) {
                $("li", pop).hover(function() {
                    $(item).addClass("hover");
                }, function() {
                    $(item).removeClass("hover");
                });
            }
        }

        // Calculo de la altura
        var pos = $(item).offset();
        var cssPos;

        if (top) {
            cssPos = {
                marginLeft: 0,
                left: pos.left - 132
            }
        } else {
            cssPos = {
                bottom: $($.browser.msie && parseInt($.browser.version < 7) ? document : window).height() - pos.top - 50,
                left: pos.left - 13
            }
        }

        /* Animacion */
        pop.css(cssPos).show();
        if (!$.browser.msie || parseInt($.browser.version) >= 7) {
            $(".content", pop).slideUp(0).slideDown("fast");
        }

        configurarEnlaces();
    }

    var salto = function(e) {
        e.preventDefault();

        var target = this.href.split("#")[0];
        var id = this.href.split("#")[1];

        var dataOut = {
            idMenu: id,
            sesId: getSesId()
        }

        if (target && id) sendData(target, dataOut);
    }

    var configurarEnlaces = function() {
        return; // Anulado
        $("#menuPie h2:not(.submenu) a:not(.static)").click(salto);
        $("#submenuPieFlotante ul a:not(.static)").click(salto);
        $("#submenuPieFlotante .titulo a:not(.static)").click(salto);
    }

    // Despliege acceso agencas
    $("#herramientas a[href='#popAgencias']").bind("click", function(e) {
        e.preventDefault();
        open(this, true);
    })
    $("#herramientasHome a[href='#popAgencias']").bind("click", function(e) {
        e.preventDefault();
        open(this, true);
    })
    $("#popAgencias a.cerrar, #popAgencias h2").bind("click", function(e) {
        e.preventDefault();
        close(true);
    })

    // Despliegue de submenu pie
    /*
    $("#menuPie .submenu > a").bind( "mouseover", function(e) {
    e.preventDefault();
    if (btClosed) return;
    open( this );
    });
    */
    $("#submenuPieFlotante").hover(
		function() { mouseIsOut = false; },
		function() { mouseIsOut = true; }
	);
    $("#menuPie .submenu > a").bind("click", function(e) {
        e.preventDefault();
        btClosed = false;
        mouseIsOut = false;
        open(this);
    });

    // Pliegue
    /*
    $("#contenedorCentral, #contenido, #navAyuda").bind("click", function(e) {
    e.preventDefault();
    btClosed = false;
    close();
    });
    */
    $(document).bind("click", function(e) {
        if (mouseIsOut) { btClosed = false; close(); }
    });
    $("#submenuPieFlotante .close").bind("click", function(e) {
        e.preventDefault();
        btClosed = true;
        close();
    });

    configurarEnlaces();

    /* Formulario del idioma */
    $("#formularioIdioma select").change(function() {
        $("#formularioIdioma").submit();
    });

    $("#formularioIdioma").submit(function(e) {
        if (e) e.preventDefault();
        SaltoGenerico(this.action, {
            sesId: getSesId(),
            idioma: $("select", this).val(),
            url: getValue("urlIdioma")
            /*url					: document.location.href*/
            /*codigoCarga 			: getValue("codigoCarga")*/
        }, true); // Por GET
    });

    /* Enlaces a páginas de pie */
    $("a.saltoPagina").click(salto);

    /* Formulario acceso agencias. Comprobación de campos */
    $("#popAgencias form").submit(function(e) {

        var pref = $("#agPrefijo", this).val();
        var tel = $("#agTelefono", this).val();
        var pass = $("#agPassword", this).val();

        var error = false;

        if (pref.replace(/[^0-9]/g, "").length < 2) error = true;
        if (tel.replace(/[^0-9]/g, "").length < 6) error = true;
        if (pass.length == 0) error = true;

        // Cancela si hay error
        if (error) {
            alert(literales.formAgenciasError || literales.formGenericError || "Por favor, rellene el formulario correctamente.");
            e.preventDefault();
        }

        /* Recordamos el ultimo acceso (por 1 año) */
        setCookie("form_agPrefTel", pref + "/" + tel, 365);

    });

    /* Recuperación del ultimo acceso */
    var preftel = getCookie("form_agPrefTel");
    if (preftel) {
        preftel = preftel.split("/");
        $("#agPrefijo").val(preftel[0]);
        $("#agTelefono").val(preftel[1])
    }

}

/* Configuración del popup Ficha de Hotel */
fn.fichaHotel = function(startWith) {

    var comparativaMap;

    var cargarComparativa = function() {

        actualizarListaHoteles();
        // Extraemos los <select> de los hoteles
        var sA = $("#comparadorHoteles .A select option:selected");
        var sB = $("#comparadorHoteles .B select option:selected");

        // Oculta botones 'seleccionar' si no hay un hotel seleccionado
        if (nulo(sA.val())) {
            $("#comparadorHoteles .A a.boton").css({ visibility: "hidden" });
            $("#comparadorHoteles .A .precio").html("");
        } else {
            $("#comparadorHoteles .A a.boton").css({ visibility: "visible" });
            $("#comparadorHoteles .A .precio").html((literales.moneda || "%n &euro;").replace("%n", sA.val().split("#").pop()));
        }

        if (nulo(sB.val())) {
            $("#comparadorHoteles .B a.boton").css({ visibility: "hidden" });
            $("#comparadorHoteles .B .precio").html("");
        } else {
            $("#comparadorHoteles .B a.boton").css({ visibility: "visible" });
            $("#comparadorHoteles .B .precio").html((literales.moneda || "%n &euro;").replace("%n", sB.val().split("#").pop()));
        }

        // Si A o B no tienen valor, anula la actualizacion
        if (nulo(sA.val()) || nulo(sB.val())) return;

        // Actualiza los nombres de los hoteles
        //$("#comparadorHoteles .A .nombreHotel").text( sA.text() );
        //$("#comparadorHoteles .B .nombreHotel").text( sB.text() );

        // Carga del contenido del comparador
        loadXmlData(proveedoresDatos.comparativaHotel || $("#comparadorHoteles").attr("action"), {

            codHotel1: sA.val().split("#").shift(),
            precio1: sA.val().split("#").pop(),

            codHotel2: sB.val().split("#").shift(),
            precio2: sB.val().split("#").pop(),

            sesId: getSesId()

        }, function(data) {

            // Elimina  la instancia del mapa
            if (comparativaMap) comparativaMap = null;

            // Actualiza el HTML con los datos recibidos
            $("#comparadorContenido").html($("data", data).text());

            configurarComparativa();

        });

    }

    /* Obtiene la lsita de hoteles para la comparativa desde los resultados */
    var cargarListaHoteles = function() {
        var lista = "";
        var listaB = "";
        var hotelActual, i;
        var resultados = [];
        var defaultText = $("#comparadorHoteles .A select option:first").text() || "";

        if (typeof obtenerResultadosBusqueda == "function") {

            // Extrae los resultados desde la lista de resultados
            hotelActual = obtenerUltimaSeleccion().codHotelCompletado;
            resultados = obtenerResultadosBusqueda(true);

        } else if (typeof obtenerListaOfertas == "function") {

            // Extrae los resultados desde la lista de ofertas
            hotelActual = obtenerOfertaDestacada().codHotelCompletado;
            resultados = obtenerListaOfertas();

        }

        if (resultados.length == 0) return;

        if (defaultText) lista = "<option value=''>" + defaultText + "</option>\n";

        if (defaultText) listaB = "<option value=''>" + defaultText + "</option>\n";

        for (i in resultados) {
            lista += "<option value='" + resultados[i].codHotelCompletado + "#" + resultados[i].precio + "' " + (resultados[i].codHotelCompletado == hotelActual ? "selected" : "") + ">" + resultados[i].nombre + " - " + (literales.moneda || "%n &euro;").replace("%n", resultados[i].precio) + "</option>\n";
            if (resultados[i].codHotelCompletado != hotelActual) {
                listaB += "<option value='" + resultados[i].codHotelCompletado + "#" + resultados[i].precio + "' " + ">" + resultados[i].nombre + " - " + (literales.moneda || "%n &euro;").replace("%n", resultados[i].precio) + "</option>\n";
            }
        }

        $("#comparadorHoteles .A select").html(lista);
        $("#comparadorHoteles .B select").html(listaB);
    }

    var actualizarListaHoteles = function() {
        var resultados = [];
        var hotelActualA, hotelActualB, i;
        var listaA = "";
        var listaB = "";
        var sA = $("#comparadorHoteles .A select option:selected");
        var sB = $("#comparadorHoteles .B select option:selected");
        var defaultText = ""

        if (typeof obtenerResultadosBusqueda == "function") {

            // Extrae los resultados desde la lista de resultados
            resultados = obtenerResultadosBusqueda(true);

        } else if (typeof obtenerListaOfertas == "function") {

            // Extrae los resultados desde la lista de ofertas
            resultados = obtenerListaOfertas();
        }

        hotelActualA = sA.val().split("#")[0];
        hotelActualB = sB.val().split("#")[0];

        if (hotelActualB == "") {
            defaultText = $("#comparadorHoteles .A select option:first").text() || "";
            listaA = "<option value=''>" + defaultText + "</option>\n";
            listaB = "<option value=''>" + defaultText + "</option>\n";
        }

        for (i in resultados) {
            if (resultados[i].codHotelCompletado != hotelActualB) {
                listaA += "<option value='" + resultados[i].codHotelCompletado + "#" + resultados[i].precio + "' " + (resultados[i].codHotelCompletado == hotelActualA ? "selected" : "") + ">" + resultados[i].nombre + " - " + (literales.moneda || "%n &euro;").replace("%n", resultados[i].precio) + "</option>\n";
            }
            if (resultados[i].codHotelCompletado != hotelActualA) {
                listaB += "<option value='" + resultados[i].codHotelCompletado + "#" + resultados[i].precio + "' " + (resultados[i].codHotelCompletado == hotelActualB ? "selected" : "") + ">" + resultados[i].nombre + " - " + (literales.moneda || "%n &euro;").replace("%n", resultados[i].precio) + "</option>\n";
            }
        }

        $("#comparadorHoteles .A select").html(listaA);
        $("#comparadorHoteles .B select").html(listaB);
    }

    var seleccionar = function(e) {
        e.preventDefault();

        if (typeof obtenerUltimaSeleccion == "function") { // Si estamos en la página de resultados

            // Llamamos al a funcion seleccionar() de los resutados
            seleccionarHotel(this.href, obtenerUltimaSeleccion());
            return;

        } else if (typeof obtenerOfertaDestacada == "function") { // Si estamos en la página de ofertas

            seleccionarHotel(this.href, obtenerOfertaDestacada());
            return;

        }

        fixme("Aún no implementado");
    }

    var seleccionarComparativa = function(e) {
        e.preventDefault();
        var cod = $("select", $(this).parent()).val().split("#").shift();

        if (!cod) return;
        if (typeof obtenerHotelPorCodigo != "function") {
            fixme("Aún no implementado");
            return;
        }

        seleccionarHotel(this.href, obtenerHotelPorCodigo(cod));
    }

    var configurarComparativa = function() {

        // Enlaces a popup
        fn.popupLinks("#comparadorContenido");

        // Galerias de imagenes
        $("#ficha-compararHoteles .galeria").galeriaImagenes();

        // Mapa
        var locA = getValue("geolocalizacion_A", "#ficha-compararHoteles").split(",");
        var locB = getValue("geolocalizacion_B", "#ficha-compararHoteles").split(",");

        if (locA.length > 1 || locB.length > 1) {

            comparativaMap = map.create("ficha-compararHoteles-mapa", "LOCKED");

            if (comparativaMap) {

                var bounds = {
                    maxLat: -180,
                    minLat: 180,
                    maxLng: -180,
                    minLng: 180
                }

                if (map.validCoords(locA[0], locA[1])) {

                    bounds.maxLat = Math.max(bounds.maxLat, parseFloat(locA[0]));
                    bounds.minLat = Math.min(bounds.minLat, parseFloat(locA[0]));
                    bounds.maxLng = Math.max(bounds.maxLng, parseFloat(locA[1]));
                    bounds.minLng = Math.min(bounds.minLng, parseFloat(locA[1]));
                    map.addIcon(comparativaMap, locA[0], locA[1], $("#comparadorHoteles .A select option:selected").text(), 1);

                }

                if (map.validCoords(locB[0], locB[1])) {

                    bounds.maxLat = Math.max(bounds.maxLat, parseFloat(locB[0]));
                    bounds.minLat = Math.min(bounds.minLat, parseFloat(locB[0]));
                    bounds.maxLng = Math.max(bounds.maxLng, parseFloat(locB[1]));
                    bounds.minLng = Math.min(bounds.minLng, parseFloat(locB[1]));
                    map.addIcon(comparativaMap, locB[0], locB[1], $("#comparadorHoteles .B select option:selected").text(), 2);

                }

                map.bestZoom(comparativaMap, bounds);

            }

        } else {

            // No hay mapa
            $("ficha-compararHoteles-mapa").hide();

        }

    }

    if (!parseInt(startWith)) startWith = 0;

    /* Mapa localizacion */
    var geolocalHotel = $("#popup-fichaHotel .infoHotel input[name$='geolocalizacion']");
    var locationMap = map.create("ficha-localizacion-mapa", "ZOOMMOVE");

    var bounds = {
        maxLat: -180,
        minLat: 180,
        maxLng: -180,
        minLng: 180
    }

    if (geolocalHotel.size()) {
        geolocalHotel = geolocalHotel.val().split(",");
        if (map.validCoords(geolocalHotel[0], geolocalHotel[1])) {

            map.addMarker(locationMap, parseFloat(geolocalHotel[0]), parseFloat(geolocalHotel[1]), $("#popup-fichaHotel .infoHotel h2").text(), c);

            bounds.maxLat = Math.max(bounds.maxLat, parseFloat(geolocalHotel[0]));
            bounds.minLat = Math.min(bounds.minLat, parseFloat(geolocalHotel[0]));
            bounds.maxLng = Math.max(bounds.maxLng, parseFloat(geolocalHotel[1]));
            bounds.minLng = Math.min(bounds.minLng, parseFloat(geolocalHotel[1]));
        }
    }

    var c = 1, i;

    $("#ficha-localizacion .leyenda li").each(function() {

        var coords = $("input[name$='geolocalizacion']", this);

        if (coords.size()) {

            coords = coords.val().split(",");

            if (map.validCoords(coords[0], coords[1])) {

                //if ($(this).prev().html() == null) c = 1;

                // Añadimos un marcadores en el mapa
                map.addIcon(locationMap, coords[0], coords[1], $("span", this).text(), c);

                // Obtenemos los bounds 
                bounds.maxLat = Math.max(bounds.maxLat, parseFloat(coords[0]));
                bounds.minLat = Math.min(bounds.minLat, parseFloat(coords[0]));
                bounds.maxLng = Math.max(bounds.maxLng, parseFloat(coords[1]));
                bounds.minLng = Math.min(bounds.minLng, parseFloat(coords[1]));

            }

        }

        c++;

    });

    map.bestZoom(locationMap, bounds);

    /* Galeria de imagenes */
    $("#popup-fichaHotel .fichaCabecera .galeria").galeriaImagenes();

    /* Funcion pestañas */
    $("#popup-fichaHotel .pestana").hide();
    $("#popup-fichaHotel .menu a").click(function(e) {
        e.preventDefault();
        $("#popup-fichaHotel .pestana").hide();
        $("#popup-fichaHotel .menu a").removeClass("open");
        $("#" + this.href.split("#").pop()).show();
        $(this).addClass("open");
    });

    // Enlaces a popup
    fn.popupLinks("#popup-fichaHotel");

    // Boton seleccionar
    $("#popup-fichaHotel .fichaCabecera a.boton").click(seleccionar);

    // Botones seleccionar de la comparativa
    $("#popup-fichaHotel #comparadorHoteles a.boton").click(seleccionarComparativa);

    /* Primer pestaña abierta */
    $("#popup-fichaHotel .menu a:eq(" + startWith + ")").click();

    /* Obtiene el listado de hoteles de los resultados de busqueda, si procede */
    cargarListaHoteles();

    $("#comparadorHoteles select").change(cargarComparativa);
    cargarComparativa();

}

/* Configuracion del pop Guia Destino */
fn.guiaDestino = function(startWith) {

    var form = "#guia-otrosDestinos";
    if (typeof starWith != "number" || !parseInt(startWith)) startWith = 0;

    // Ajustado del ancho de las pestañas
    var menu = $("#popup-guiaDestino .menu li:visible");
    var totalMenuItems = menu.size();
    menu.width((100 / totalMenuItems - ($.browser.msie && $.browser.version < 8 ? .4 : 0)) + "%");
    menu.removeClass("last").filter(":last").addClass("last");

    // Parrafos con imagen
    //$("#popup-guiaDestino div:has(>img.left) p").addClass("conImagen");

    // Atajo a campo
    var c = function(name) { return $(form + " select[name$='" + name + "']"); }

    var limpiarLista = function(combo, loading) {
        if (typeof (combo) == "string") combo = $(form + " select[name$='" + combo + "']");

        // Limpiamos el select
        $("option", combo.disable()).remove();

        if (loading) $(combo).append("<option>" + (literales.comboLoading || "Cargando...") + "</option>");
    }

    /* Funcion al seleccionar origen */
    var crearLista = function(lista, combo, dataAttr, labelAttr, customLabel, customReg, customDef) {

        if (typeof (combo) == "string") combo = $(form + " select[name$='" + combo + "']");

        // Tags que leera para asignar el valor y la etiqueta de la opción del select.
        // Puede especificarse en el 3er y 4o parámetro en cada llamada a la funcion 'crearLista()'
        dataAttr = dataAttr != null ? dataAttr : "> Cod";
        labelAttr = labelAttr != null ? labelAttr : "> Nom";

        // Primera opción sin valor y por defecto
        combo.append("<option value=''>" + (customDef || literales.comboDefault) + "</option>");

        // Añadimos los elementos
        lista.each(function() {
            var data = dataAttr ? $(dataAttr, this).text() : $(this).text();
            var label = labelAttr ? $(labelAttr, this).text() : data;
            if (customLabel && customReg) label = customLabel.replace(customReg, label);

            combo.append("<option value='" + data + "'>" + label + "</option>");
        });

        combo.enable();
    }

    var comprobarCampos = function() {
        if ($("option", c("nivel2")).size() <= 1) c("nivel2").disable();
        if ($("option", c("nivel3")).size() <= 1) c("nivel3").disable();
    }

    /* Funcion al seleccionar destino nivel 1 */
    var seleccionDestino1 = function() {
        limpiarLista("nivel2");
        limpiarLista("nivel3");

        if (nulo(c("nivel1").val())) return;

        limpiarLista("nivel2", true); // Muestra el mensaje 'cargando'

        loadXmlData(proveedoresDatos.guiaDestinos_comboDestino2, {
            idNivel1: c("nivel1").val(),
            sesId: getSesId()
        }, function(data) {
            limpiarLista("nivel2");
            crearLista($("ArrayOfAreaAreaSubArea", data), "nivel2");
            comprobarCampos();
        });

    }

    /* Funcion al seleccionar destino nivel 2 */

    var seleccionDestino2 = function() {
        limpiarLista("nivel3");

        if (nulo(c('nivel2').val())) return;

        limpiarLista("nivel3", true); // Muestra el mensaje 'cargando'

        loadXmlData(proveedoresDatos.guiaDestinos_comboDestino3, {
            idNivel1: c('nivel1').val(),
            idNivel2: c('nivel2').val(),
            sesId: getSesId()
        }, function(data) {
            limpiarLista("nivel3");
            crearLista($("ArrayOfAreaAreaSubAreaDestino", data), "nivel3", null, null, null, null, literales.comboTodos);
            comprobarCampos();
        });

    }

    var submitDestino = function(e) {
        e.preventDefault();

        if (nulo(c("nivel1").val()) || nulo(c("nivel2").val())) return;

        openPopupURL($(form).attr("action"), fn.guiaDestino, {
            sesId: getSesId(),
            DestinoNivel1: c('nivel1').val(),
            DestinoNivel2: c('nivel2').val(),
            DestinoNivel3: c('nivel3').val()
        });
    }

    /* Mapa localizacion */
    var locationMap = map.create("guia-practica-mapa", "ZOOMMOVE");

    if (locationMap) {

        var bounds = {
            maxLat: -180,
            minLat: 180,
            maxLng: -180,
            minLng: 180
        }

        var k = 1, i;

        $("#guia-practica .cabeceraPestana li").each(function() {

            var coords = $("input[name$='geolocalizacion']", this).val().split(",");

            if ($(this).prev().html() == null) k = 1;

            if (map.validCoords(coords[0], coords[1])) {

                // Añadimos un marcadores en el mapa
                map.addIcon(locationMap, coords[0], coords[1], $("span", this).text(), k);

                // Obtenemos los bounds 
                bounds.maxLat = Math.max(bounds.maxLat, parseFloat(coords[0]));
                bounds.minLat = Math.min(bounds.minLat, parseFloat(coords[0]));
                bounds.maxLng = Math.max(bounds.maxLng, parseFloat(coords[1]));
                bounds.minLng = Math.min(bounds.minLng, parseFloat(coords[1]));

            }

            k++;
        });

        map.bestZoom(locationMap, bounds);
        locationMap.setZoom(7);

    }

    // Enlaces a popup
    fn.popupLinks("#popup-guiaDestino");

    /* Galeria de imagenes */
    $("#guia-inicio .galeria").galeriaImagenes(null, null, {
        controlsItem: "#guia-inicio .indiceFotos"
    });

    $("#guia-inicio .indiceFotos").parent().addClass("galeriaImagenes");

    $("#popup-guiaDestino .pestana").hide();

    /* Funcion pestañas */
    $("#popup-guiaDestino .menu a").click(function(e) {
        e.preventDefault();
        $("#popup-guiaDestino .contenido > .pestana").hide();
        $("#popup-guiaDestino .menu a").removeClass("open");
        $("#" + this.href.split("#").pop()).show();
        $(this).addClass("open");
    });

    $("#guia-sugerencias .submenu a").click(function(e) {
        e.preventDefault();
        $("#guia-sugerencias .pestana").hide();
        $("#guia-sugerencias .submenu a").removeClass("open");
        $("#" + this.href.split("#").pop()).show();
        $(this).addClass("open");
    });

    $("#guia-excursiones .submenu a").click(function(e) {
        e.preventDefault();
        $("#guia-excursiones .pestana").hide();
        $("#guia-excursiones .submenu a").removeClass("open");
        $("#" + this.href.split("#").pop()).show();
        $(this).addClass("open");
    });

    /* Primer pestaña abierta */
    $("#popup-guiaDestino .menu a:eq(" + startWith + ")").click();
    $("#guia-sugerencias .submenu a:eq(0)").click();
    $("#guia-excursiones .submenu a:eq(0)").click();

    /* Formulario otros destinos */
    c("nivel1").change(seleccionDestino1);
    c("nivel2").change(seleccionDestino2);
    $(form).submit(submitDestino);

    comprobarCampos();

}

/* Funciones para el manejo de Google Maps */
fn.GMaps = function() {

    var error = false;

    if (typeof (GMap2) === "undefined") { alert("Google API no disponible!"); error = true; }
    else if (!GBrowserIsCompatible()) { error = true; }

    if (error) {
        window.map = {
            create: function() { },
            center: function() { },
            addMarker: function() { return null; },
            addIcon: function() { return null; },
            addEvent: function() { return null; },
            addMarkerEvent: function() { return null; },
            removeMarker: function() { },
            clearMarkers: function() { },
            bestZoom: function() { },
            validCoords: function() { },
            normalize: function() { },
            normalizeLat: function() { },
            normalizeLng: function() { }
        }
        return;
    }

    // Objeto que contiene todos los metodos para el manejo de mapas
    window.map = {

        create: function(container, ui, width, height) {

            if ($("#" + container).size() == 0) { return null; }

            var opt = {}
            if (width && height) opt.size = new GSize(width, height);

            var gmap = new GMap2(document.getElementById(container), opt);

            switch (ui) {

                case "ZOOM":
                    // Mapa pequeño con controles
                    gmap.addControl(new GSmallZoomControl());
                    break;

                case "ZOOMMOVEHYBRID":
                    gmap.setMapType(G_HYBRID_MAP);
                case "ZOOMMOVE":
                    // Mapa grande con controles
                    gmap.addControl(new GLargeMapControl3D());
                    gmap.addControl(new GMapTypeControl());
                    gmap.enableScrollWheelZoom();
                    break;

                case "LOCKED":
                    // Mapa bloqueado sin controles
                    gmap.disableDragging();
                    break;

                case "LOCKEDEXT":
                    // Mapa pequeño con botón para ampliar
                    gmap.disableDragging();
                    gmap.addControl(new map.classes.ZoomControl());
                    break;

            }

            return gmap;
        },

        center: function(instance, lat, lng, zoom) {
            if (!instance) return;

            var coords = map.normalize({ lat: lat, lng: lng });
            instance.setCenter(new GLatLng(coords.lat, coords.lng), zoom);
        },

        pan: function(instance, lat, lng, sx, sy) {
            if (!instance) return;

            var coords = map.normalize({ lat: lat, lng: lng });
            coords = new GLatLng(coords.lat, coords.lng);

            if (sx || sy) {

                var z = instance.getZoom();
                var proj = instance.getCurrentMapType().getProjection();
                var px = proj.fromLatLngToPixel(coords, z);

                var sePx = new GPoint(px.x + sx, px.y + sy);

                coords = proj.fromPixelToLatLng(sePx, z);
            }

            instance.panTo(coords);

        },

        addEvent: function(map, event, action) {
            return GEvent.addListener(map, event, action);
        },

        addMarkerEvent: function(marker, event, action) {

            return GEvent.addListener(marker, event, function(latlng) {

                action({
                    latlng: latlng,
                    marker: marker
                });

            });

        },

        addMarker: function(instance, lat, lng, title, onClick) {
            if (!instance) return;

            var coords = map.normalize({ lat: lat, lng: lng });

            var markerOptions = {
                title: title
            }
            var marker = new GMarker(new GLatLng(coords.lat, coords.lng), markerOptions);

            instance.addOverlay(marker);

            if (typeof onClick == "function") map.addMarkerEvent(marker, "click", onClick);

            return marker;
        },

        addOverlay: function(instance, type) {

            if (!instance) return;

            var o;

            if (typeof type == "function") o = new type();
            else if (typeof type == "object") o = type;
            else return;

            instance.addOverlay(o);

            return o;

        },

        removeOverlay: function(instance, obj) {

            if (!instance || !obj) return;
            instance.removeOverlay(obj);

        },

        addIcon: function(instance, lat, lng, title, img, onClick, options) {
            if (!instance) return;

            var coords = map.normalize({ lat: lat, lng: lng });

            if (!options) options = {}
            if (!img) img = 0;
            if (typeof img == "number") img = "gmapIcon_" + img + ".png";

            /* Propiedades del icono */
            var icon = new GIcon(G_DEFAULT_ICON);
            icon.image = "." + urlImagenesWebConfig + "/" + img;
            if (typeof opciones == "object") if (opciones.gmap_pathIconos) icon.image = opciones.gmap_pathIconos + img;
            icon.iconSize = new GSize(options.width || 14, options.height || 14);
            icon.iconAnchor = new GPoint(options.midx || 7, options.midy || 7);
            icon.shadow = options.shadow || "";
            var markerOptions = {
                icon: icon,
                title: title
            }
            var marker = new GMarker(new GLatLng(coords.lat, coords.lng), markerOptions);

            instance.addOverlay(marker);

            if (typeof onClick == "function") map.addMarkerEvent(marker, "click", onClick);

            return marker;
        },

        removeMarker: function(instance, marker) {
            if (!instance) return;
            instance.removeOverlay(marker);
        },

        clearMarkers: function(instance) {
            if (!instance) return;
            instance.clearOverlays();
        },

        normalize: function(coords) {
            if (!coords) return;
            if (typeof coords.lat == "undefined" && typeof coords.lng == "undefined") return;
            if (typeof coords.lat == "undefined") return map.normalizeLng(coords.lng);
            if (typeof coords.lng == "undefined") return map.normalizeLat(coords.lat);

            coords.lat = parseFloat(coords.lat);
            coords.lng = parseFloat(coords.lng);

            var inv = Math.floor((coords.lat + 90) / 180);
            inv = inv / 2 != Math.floor(inv / 2);

            coords.lat = map.normalizeLat(coords.lat);
            coords.lng = map.normalizeLng(coords.lng, inv);

            return coords;
        },

        validCoords: function(lat, lng) {
            lat = parseFloat(lat);
            lng = parseFloat(lng);
            if (lat > -90 && lat < 90 && lng > -180 && lng < 180 && lat != 0 && lng != 0) return true;
            return false;
        },

        normalizeLat: function(coord) { /* Rango válido -180 > 180 */
            coord = parseFloat(coord);
            var inv = Math.floor((coord + 90) / 180);
            inv = inv / 2 != Math.floor(inv / 2);
            var base = coord < 0 ? -Math.ceil(Math.abs(coord - 90) / 180) * 180 + 180 : Math.floor(Math.abs(coord + 90) / 180) * 180;
            return (coord - base) * (inv ? -1 : 1);
        },

        normalizeLng: function(coord, inv) { /* Rango válido -180 > 180 */
            coord = parseFloat(coord);
            if (inv) coord *= -1;
            var base = coord < 0 ? -Math.ceil(Math.abs(coord - 180) / 360) * 360 + 360 : Math.floor(Math.abs(coord + 180) / 360) * 360;
            return coord - base;
        },

        bestZoom: function(instance, bounds) {
            if (!instance) return;

            var max = map.normalize({ lat: bounds.maxLat, lng: bounds.maxLng });
            var min = map.normalize({ lat: bounds.minLat, lng: bounds.minLng });

            // Margen del 5% como minimo
            min.lat -= (max.lat - min.lat) * .02;
            max.lat += (max.lat - min.lat) * .02;
            min.lng -= (max.lng - min.lng) * .02;
            max.lng += (max.lng - min.lng) * .02;

            var size = instance.getSize();
            var Gbounds = new GLatLngBounds(new GLatLng(min.lat, min.lng),
											 new GLatLng(max.lat, max.lng))

            var zoom = Math.min(13, instance.getBoundsZoomLevel(Gbounds, size));

            map.center(instance, (max.lat + min.lat) / 2, (max.lng + min.lng) / 2, zoom)

        },

        /* Controles personalizados (declaración) */
        classes: {
            ZoomControl: function() { },
            InfoBox: function() { }
        }

    }

    // Control boton ampliar
    map.classes.ZoomControl.prototype = new GControl();
    map.classes.ZoomControl.prototype.initialize = function(target) {
        var icon = "." + urlImagenesWebConfig + "/gmapZoom.gif";
        if (typeof opciones == "object") if (opciones.gmap_pathIconos) icon = opciones.gmap_pathIconos + "gmapZoom.gif";

        var container = document.createElement("div");
        //Miquel: Comentado para deshabilitar temporalmente el mapa ampliado.
        container.innerHTML = "<a href='#'><img src='" + icon + "' width='27' height='27' /></a>";
        container.style.position = "relative";

        GEvent.addDomListener(container, "click", function() {
            GEvent.trigger(target, "zoomclick");
        });

        target.getContainer().appendChild(container);
        return container;
    }
    map.classes.ZoomControl.prototype.getDefaultPosition = function() {
        return new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(5, 5));
    }

    // Caja de información
    map.classes.InfoBox.prototype = new GOverlay();
    map.classes.InfoBox.prototype.initialize = function(target) {

        this.lat = 0;
        this.lng = 0;

        var container = document.createElement("div");
        target.getContainer().appendChild(container);

        this.box = null;
        this.container = container;
        this.instance = target;

        container.style.position = "absolute";
        container.style.left = "0";
        container.style.top = "0";

        return container;
    }
    map.classes.InfoBox.prototype.redraw = function() {
        var pos = this.instance.fromLatLngToContainerPixel(new GLatLng(this.lat, this.lng));
        var tar = this.box;

        if (!tar) return;
        tar.css({ left: pos.x, top: pos.y });

    }
    map.classes.InfoBox.prototype.setContent = function($content, lat, lng) {
        if (!this.container) return;

        this.removeContent();

        $(this.container).append($content);
        this.box = $(">div:first", this.container);
        this.lat = lat;
        this.lng = lng;

        $(".resultado .destinoTxt", this.container).checkTextOverflow();
        $(".resultado .nombre strong", this.container).checkTextOverflow(2);
        $(".resultadoOferta h4 a", this.container).checkTextOverflow();

        this.redraw();
    }
    map.classes.InfoBox.prototype.removeContent = function() {
        if (!this.container || !this.box) return;
        $(this.container).html('');
        this.box = null;
    }
    map.classes.InfoBox.prototype.remove = function() {
        if (!this.target) return;
        this.target.getContainer().removeChild(this.container);
    }

}

/* Pantalla de espera */
fn.espera = function() {

    if (typeof showLoader == "function") return;  // Ya está cargado

    var customstyle = "";
    /*if (literales.imagenPantallaEspera) customstyle = "style='background-image:url("+literales.imagenPantallaEspera+");'";*/

    // Añade el contenedor
    $("body").append('<div id="espera"><div class="cortinaEspera"></div><div class="logo" ' + customstyle + '></div></div>');

    // Funciones de control 
    window.showLoader = function(fullsize, customText) {
        $("#espera .logo").text(customText || literales.pantallaEspera || "");
        $("#espera").show().css({ top: 0, height: $(document).height() - 105 });
        $("#espera .cortinaEspera").css({ top: fullsize ? 0 : $("#contenido").offset().top });
    }
    window.hideLoader = function() { $("#espera").hide(); }

    $("#espera .cortinaEspera").css({ opacity: .85, top: 0 });

    showLoader();

}

/* Pantalla de espera */
fn.espera2 = function(Text) {

    if (typeof showLoader == "function") {  // Ya está cargado

    }
    else {
        var customstyle = "";
        /*if (literales.imagenPantallaEspera) customstyle = "style='background-image:url("+literales.imagenPantallaEspera+");'";*/

        // Añade el contenedor
        $("body").append('<div id="espera"><div class="cortinaEspera"></div><div class="logo" ' + customstyle + '></div></div>');
    }
    // Funciones de control 
    window.showLoader = function(fullsize, customText) {
        $("#espera .logo").text(customText || Text || "");
        $("#espera").show().css({ top: -105, height: $(document).height() - 105 });
        $("#espera .cortinaEspera").css({ top: fullsize ? 0 : $("#contenido").offset().top });
    }
    window.hideLoader = function() { $("#espera").hide(); }

    $("#espera .cortinaEspera").css({ opacity: .85, top: -105 });
    parent.scroll(1, 1);
    showLoader();
}

/* Páginas estáticas */
fn.estaticas = function() {

    /* Enlaces submenu páginas del pie de página */
    $("div.lateralEstatico:not(.static)").each(function() {

        var menu = this;

        $("ul li a:not(.static), h2 a:not(.static)", menu).click(function(e) {
            if (!this.href) return;
            e.preventDefault();
            $("ul li", menu).removeClass("seleccion");
            $(this).parent().addClass("seleccion");
            $("#contenedor").css({ "cursor": "progress" });
            $("#contenidoEstatico").load(this.href, null, function() {
                $("#contenedor").css({ "cursor": "default" });
                fixIE("#contenidoEstatico");
            });
        });

        if ($("ul li.seleccion", menu).size() > 0) {
            $("ul li.seleccion:eq(0) a:not(.static)", menu).click();
        } else {
            $("h2 a:not(.static)", menu).click();
        }
    });

    /* Boton imprimir */
    $(".imprimir").click(imprimir);

    /* Lateral altura maxima */
    function resizeLateralEstatico() { $(".lateralEstatico").height(Math.max($("#contenidoEstatico").height(), 400)); }
    resizeLateralEstatico();
    setInterval(resizeLateralEstatico, 500);

}

/* Inicia la captura de eventos del teclado */
fn.keys = function() {

    $(document).keydown(function(e) {

        switch (e.keyCode) {
            /* Cierre popups */ 
            case 27: if (_popups.length > 0) _popups.pop().hide();
        }

    });

}

/* Métodos para la validación de formularios */
fn.formValidator = function(selector, env) {

    var defaultSelector = "form.validate";
    var checkForm = genericFormValidator;
    var targets = $(selector ? selector : defaultSelector, env ? env : document);

    targets.bind("submit", checkForm);
}

function genericFormValidator(e, extContext) {
    var emailPattern = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;
    var phonePattern = /^[\+\d|\s|\-]{9,}$/;
    var dniPattern = /^\s*[KLMXYZ\d]\d{7}[\s-]*[TRWAGMYFPDXBNJZSQVHLCKET]\s*/i;

    var defaultContext = this;
    var context = $(extContext ? extContext : defaultContext);

    var error = new Array();
    var fecha = new Date();
    //$("input, textarea, select", context).removeClass("error");
    $("input, label, span, textarea, select", context).removeClass("error");

    // Required
    $("input.required, textarea.required, select.required", context).each(function() {
        if (($(this).val() == "") || ($(this).attr("type") == "checkbox" && !$(this).attr("checked")))
            error.push({ type: "required", target: this })
    });

    // Card
    $("input.card", context).each(function() {
        if ($(this).val().length != 4)
            error.push({ type: "card", target: this })
    });

    // cvv
    $("input.cvv", context).each(function() {
        if ($(this).val().length != 3)
            error.push({ type: "cvv", target: this })
    });

    // Email 
    $("input.email", context).each(function() {
        if (!emailPattern.test($(this).val())) error.push({ type: "email", target: this })
    });

    // Telefono
    $("input.phone", context).each(function() {
        if (!phonePattern.test($(this).val())) error.push({ type: "phone", target: this })
    });

    // Valores iguales
    var sameval = "";
    $("input.samevalue", context).each(function() {
        if (!sameval) sameval = $(this).val();
        else if (sameval != $(this).val()) error.push({ type: "samevalue", target: this });
    });

    // Card Expires año
    $("select.year", context).each(function() {
        if ($(this).val() == fecha.getFullYear()) {
            //Card Expires mes
            $("select.month", context).each(function() {
                if ($(this).val() < fecha.getMonth() + 1) {
                    //caducada
                    error.push({ type: "cardExpires", target: this })
                }
            });
        }
    });


    // NIF/NIE
    var sameval = "";
    $("input.dni", context).each(function() {
        var dni = $(this).val().toUpperCase();
        if (!dni) return;
        if (!dniPattern.test(dni)) {
            error.push({ type: "dni", target: this });
        } else {
            // Extranjero
            var ext = "";
            if (/^[XYZ]/.test(dni)) {
                switch (dni.substr(0, 1)) {
                    case "X": pre = "0"; break;
                    case "Y": pre = "1"; break;
                    case "Z": pre = "2"; break;
                }
            }

            // Calculo letra
            var num = parseInt(ext + dni.replace(/[^\d]+/, ''), 10);
            var let = dni.substr(dni.length - 1).toUpperCase();
            var letOk = "TRWAGMYFPDXBNJZSQVHLCKET".substr(num % 23, 1);

            if (let != letOk) error.push({ type: "dni", target: this });
        }
    });

    // personalizado
    $("input.pattern", context).each(function() {
        var pattern = new RegExp($(this).attr("pattern"));
        if (pattern.test($(this).val())) error.push({ type: "pattern", target: this, pattern: pattern });
    });

    if (error.length > 0) {
        if (e) {
            e.preventDefault();
            e.stopImmediatePropagation();
        }
        var output = "";
        for (var i in error) {
            if (error[i].target.type == "checkbox" || error[i].target.type == "radio") {
                $(error[i].target).parent().addClass("error");
            } else {
                $(error[i].target).addClass("error");
            }
        }

        alert(literales.formularioGenericError || "Por favor, rellene correctamente los campos obligatorios (marcados en rojo)");
        if (typeof window.hideLoader == "function") hideLoader();

        console.log(error);

        return false;
    }
    return true;
}

/* Banner de ofertas HTML/JS */
fn.bannerOfertas = function(target) {

    if (!target) target = ".bannerOfertas";

    var buttons = {
        slow: $("<a class='bSlow'><span>-</span></a>"),
        fast: $("<a class='bFast'><span>+</span></a>"),
        prev: $("<a class='bPrev'><span>&lt;</span></a>"),
        next: $("<a class='bNext'><span>&gt;</span></a>"),
        startstop: $("<a class='bPlay'><span>|&gt;</span></a>"),
        index: $("<span class='index'>...</span>")
    }

    var banner = $(target).carousel({
        leftControl: '',
        rightControl: '',
        itemHeight: $(target).height(),
        autoplay: getValue("bannerAutoPlay") || opciones.bannerAutoPlay || 0,
        loop: true,
        onChange: function(o) {

            buttons.index.text(literales.indiceBanner.replace("$1", o.current + 1).replace("$2", o.total));

            if (o.playing == true) {
                buttons.startstop.removeClass("bStop").addClass("bPlay");
                buttons.fast.show();
                buttons.slow.show();
            } else {
                buttons.startstop.removeClass("bPlay").addClass("bStop");
                buttons.fast.hide();
                buttons.slow.hide();
            }

            if (typeof actualizarDescripcionBanner != "function") return;
            actualizarDescripcionBanner($("p", o.item).html());
        }
    }).get(0);

    // Reformato HTML/CSS
    $(target).show();
    $(target + ' li a').each(function() {

        $(this).css({ background: "url(" + $("img", this).attr("src") + ") center center no-repeat" });

        // Ordenamos el HTML
        var reorder = $("<div></div>");
        reorder.append($("> em", this));
        reorder.append($("> strong", this));
        reorder.append($("> small", this));
        reorder.append($("> span", this));
        reorder.append($("> p", this));

        $(this).html(reorder.html());

        var precio = readNumber($("> span", this).text());

        var dec = Math.round(precio % 1 * 100);
        $("> span", this).html(formatNumber(Math.floor(precio)) + "<sup>'" + (dec < 10 ? "0" : "") + dec + "</sup>" + "<sub>&euro;</sub>");

        var w = Math.max($("> strong", this).width(), $("> em", this).width(), $("> span", this).width());
        $("> strong, > em, > span", this).width(w);
    });

    var botonera = $("<div class='botoneraBanner'></div>");
    botonera.append(buttons.slow, buttons.fast, buttons.prev, buttons.index, buttons.startstop, buttons.next);

    // Eventos
    buttons.next.click(banner.next);
    buttons.prev.click(banner.prev);
    buttons.fast.click(function() { banner.setTimeout(Math.max(banner.getTimeout() - 500, 1500)); });
    buttons.slow.click(function() { banner.setTimeout(Math.min(banner.getTimeout() + 500, 10000)); });
    buttons.startstop.click(function() {
        if (banner.isPlaying()) banner.stop();
        else banner.start();
    });

    // Efecto pulsado
    $("a", botonera).mousedown(function(e) { $(this).addClass("down"); return false; })
    $(document).mouseup(function(e) { $("a", botonera).removeClass("down"); });

    $(target).append(botonera).disableTextSelect();

}


/* Accion de imprimir */
function imprimir(e) {
    e.preventDefault();

    var contenido = $("#" + this.target).html();
    if (!contenido.size()) { alert("No hay contenido que imprimir"); return; }

    var VistaImpresion = window.open(this.href, "VistaImpresion");

    var checkInterval = setInterval(function() {

        // Copia el contenido en la nueva ventana	
        if (VistaImpresion.document.getElementById("contenedor") != null) {
            clearInterval(checkInterval);

            VistaImpresion.document.getElementById("contenedor").innerHTML = contenido;
            VistaImpresion.focus();
            VistaImpresion.print();
            VistaImpresion.close();
        }

    }, 500);

}

/* Plegar / Desplegar 'Datos de facturacion' */
var toggle = function(divTarget) {
    divTarget.toggleClass("oculto");
}

$(document).ready(function() {
    if ($("fieldset.pay-data div.bill-data").length) {
        $("fieldset.pay-data div.bill-data").find("a.down").removeClass("down").addClass("up");
        $("fieldset.pay-data div.bill-data").find(".form-bill-data").addClass("oculto");

        $("fieldset.pay-data div.bill-data").find("a").click(function() {
            var _div = $("fieldset.pay-data div.bill-data div.form-bill-data")
            var _a = $("fieldset.pay-data div.bill-data a");
            if (_div.hasClass("oculto")) {
                _div.removeClass("oculto");
                _a.removeClass("up").addClass("down");
            } else {
                _div.addClass("oculto");
                _a.removeClass("down").addClass("up");
            }
            return false;
        })
    }
})


Number.prototype.fix = function(dig) {
    // dig specifies how many digits
    // Invalid values default to 0.
    if ((dig < 0) || (dig == null) || (isNaN(dig))) dig = 0
    var power = Math.pow(10, dig)
    return Math.round(this.valueOf() * power) / power;
}


function setCookie(name, value, expires, path, domain, secure) {
    // set time, it's in milliseconds
    var today = new Date();
    today.setTime(today.getTime());

    /*
    if the expires variable is set, make the correct
    expires time, the current script below will set
    it for x number of days, to make it for hours,
    delete * 24, for minutes, delete * 60 * 24
    */
    if (expires) expires = expires * 1000 * 60 * 60 * 24;
    var expires_date = new Date(today.getTime() + (expires));

    document.cookie = name + "=" + escape(value) +
	((expires) ? ";expires=" + expires_date.toGMTString() : "") +
	((path) ? ";path=" + path : "") +
	((domain) ? ";domain=" + domain : "") +
	((secure) ? ";secure" : "");
}

// this fixes an issue with the old method, ambiguous values
// with this test document.cookie.indexOf( name + "=" );
function getCookie(check_name) {
    // first we'll split this cookie up into name/value pairs
    // note: document.cookie only returns name=value, not the other components
    var a_all_cookies = document.cookie.split(';');
    var a_temp_cookie = '';
    var cookie_name = '';
    var cookie_value = '';
    var b_cookie_found = false; // set boolean t/f default f

    for (i = 0; i < a_all_cookies.length; i++) {
        // now we'll split apart each name=value pair
        a_temp_cookie = a_all_cookies[i].split('=');


        // and trim left/right whitespace while we're at it
        cookie_name = a_temp_cookie[0].replace(/^\s+|\s+$/g, '');

        // if the extracted name matches passed check_name
        if (cookie_name == check_name) {
            b_cookie_found = true;
            // we need to handle case where cookie has no value but exists (no = sign, that is):
            if (a_temp_cookie.length > 1) {
                cookie_value = unescape(a_temp_cookie[1].replace(/^\s+|\s+$/g, ''));
            }
            // note that in cases where cookie is initialized but no value, null is returned
            return cookie_value;
            break;
        }
        a_temp_cookie = null;
        cookie_name = '';
    }
    if (!b_cookie_found) return null;

}

/*
* Date Format 1.2.3
* (c) 2007-2009 Steven Levithan <stevenlevithan.com>
* MIT license
*
* Includes enhancements by Scott Trenda <scott.trenda.net>
* and Kris Kowal <cixar.com/~kris.kowal/>
*
* Accepts a date, a mask, or a date and a mask.
* Returns a formatted version of the given date.
* The date defaults to the current date/time.
* The mask defaults to dateFormat.masks.default.
*/

var dateFormat = function() {
    var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g,
		timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,
		timezoneClip = /[^-+\dA-Z]/g,
		pad = function(val, len) {
		    val = String(val);
		    len = len || 2;
		    while (val.length < len) val = "0" + val;
		    return val;
		};

    // Regexes and supporting functions are cached through closure
    return function(date, mask, utc) {
        var dF = dateFormat;

        // You can't provide utc if you skip other args (use the "UTC:" mask prefix)
        if (arguments.length == 1 && Object.prototype.toString.call(date) == "[object String]" && !/\d/.test(date)) {
            mask = date;
            date = undefined;
        }

        // Passing date through Date applies Date.parse, if necessary
        date = date ? new Date(date) : new Date;
        if (isNaN(date)) throw SyntaxError("invalid date");

        mask = String(dF.masks[mask] || mask || dF.masks["default"]);

        // Allow setting the utc argument via the mask
        if (mask.slice(0, 4) == "UTC:") {
            mask = mask.slice(4);
            utc = true;
        }

        var _ = utc ? "getUTC" : "get",
			d = date[_ + "Date"](),
			D = date[_ + "Day"](),
			m = date[_ + "Month"](),
			y = date[_ + "FullYear"](),
			H = date[_ + "Hours"](),
			M = date[_ + "Minutes"](),
			s = date[_ + "Seconds"](),
			L = date[_ + "Milliseconds"](),
			o = utc ? 0 : date.getTimezoneOffset(),
			flags = {
			    d: d,
			    dd: pad(d),
			    ddd: dF.i18n.dayNames[D],
			    dddd: dF.i18n.dayNames[D + 7],
			    m: m + 1,
			    mm: pad(m + 1),
			    mmm: dF.i18n.monthNames[m],
			    mmmm: dF.i18n.monthNames[m + 12],
			    yy: String(y).slice(2),
			    yyyy: y,
			    h: H % 12 || 12,
			    hh: pad(H % 12 || 12),
			    H: H,
			    HH: pad(H),
			    M: M,
			    MM: pad(M),
			    s: s,
			    ss: pad(s),
			    l: pad(L, 3),
			    L: pad(L > 99 ? Math.round(L / 10) : L),
			    t: H < 12 ? "a" : "p",
			    tt: H < 12 ? "am" : "pm",
			    T: H < 12 ? "A" : "P",
			    TT: H < 12 ? "AM" : "PM",
			    Z: utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""),
			    o: (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4),
			    S: ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10]
			};

        return mask.replace(token, function($0) {
            return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);
        });
    };
} ();

// Some common format strings
dateFormat.masks = {
    "default": "ddd mmm dd yyyy HH:MM:ss",
    shortDate: "m/d/yy",
    mediumDate: "mmm d, yyyy",
    longDate: "mmmm d, yyyy",
    fullDate: "dddd, mmmm d, yyyy",
    shortTime: "h:MM TT",
    mediumTime: "h:MM:ss TT",
    longTime: "h:MM:ss TT Z",
    isoDate: "yyyy-mm-dd",
    isoTime: "HH:MM:ss",
    isoDateTime: "yyyy-mm-dd'T'HH:MM:ss",
    isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'"
};

// Internationalization strings
dateFormat.i18n = {
    dayNames: [
		"Dom", "Lun", "Mar", "Mie", "Jue", "Vie", "Sab",
		"Domingo", "Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado"
	],
    monthNames: [
		"Ene", "Feb", "Mar", "Abr", "May", "Jun", "Jul", "Ago", "Sep", "Oct", "Nov", "Dic",
		"Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Augosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"
	]
};

// For convenience...
Date.prototype.format = function(mask, utc) {
    return dateFormat(this, mask, utc);
};


