var fn = {}; 
var busy = {};
var _hotelSeleccionado = {}
var _popups = [];

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 || [];
	
	// 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" )
		} );
	} );
	
	/* IE CSS Fixes */
	if ($.browser.msie) {
		if (parseInt($.browser.version) < 7) {
			$(">li:first, >tr:first, >td:first", $("ul, ol, table, thead, tbody, tr")).addClass("first-child");
			$(">li:last, >tr:last, >td:last", $("ul, ol, table, thead, tbody, tr")).addClass("last-child");
		}
		$("table tr:even").addClass("even");
		$("table tr:odd").addClass("odd");
	}
	
	/* Cajas de evento Hover */
	$(".hoverBox").prepend("<div class='selectBox'><span></span></div>");
	
	/* Preloaders en formularios */
	
	
	/* 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]:[] );	
			
}

// 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[type=hidden][id$="+id+"]:eq(0), input[type=hidden][name$="+id+"]:eq(0)", context);
	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();
	busy = {};
}
function ajaxTimeout() {
	fixme("Timeout!");
}

// 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;
}

// 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 ... si un texto no cabe en su contenedor
$.fn.checkTextOverflow = function() { return this.each( function() { 

	if (typeof $.fn.textOverflow != "function") return;

	var o_display = $(this).css("display");
	$(this).css({ display:"block" }).textOverflow({ titleAttr:true }).css({display:"", position:"relative", zIndex:1});

} ) }

// 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");	
	});
}

// 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 = 15000;
	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);
	
	$.ajax({	
		type	: "post",
		url		: url,
		data	: serializeData(params),
		dataType: ($.browser.msie) ? "text" : "xml",
		contentType: "application/json; charset=utf-8",
		success	: function(xmlData) {
		
			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);

	$.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) {
		
			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] );
	
	form.submit();
}

/* 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,
		codPaquete 	: hotel.codPaquete,
		codDCP 		: hotel.codDCP,
		sesId 		: getSesId()
	}, extraParams );
	
	/* Fecha de hotel, si procede */
	if (!dataOut.fechaGraf && typeof obtenerFechaGrafico == "function") dataOut.fechaGraf = obtenerFechaGrafico();
	
	if (esSalto()) {
	
		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.buscador( ["#seleccionHotelBuscador", proveedoresDatos_popup ] );
		}, dataOut );
	
	} else {
	
		// Pantalla de espera, si se ha cargado
		if (typeof showLoader == "function") showLoader();
	
		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() } );
			
			}
		
		});
		
	}
		
}

/* Definición del buscador */
fn.buscador = function( params ) {

	var form = params[0] || "#buscador";
	var providers = params[1] || proveedoresDatos;
	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+"']"); }
	
	// 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") combo = $(form+" select[name$='"+combo+"']");
	
		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;
				}
			}
		
			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;

		// 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) {
						$("[name$='_adultos'] option", this).removeAttr("selected");
						$("[name$='_adultos'] option[value='"+h.adultos+"']", this).attr("selected", true);
					}
					if (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++;
			} );
			
			// 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++;
		});
		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");
		
		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 (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();
		});
	}
	
	/* Funcion al seleccionar destino nivel 3 */
	var seleccionDestino3 = function( onComplete ) {
	
		limpiarLista("codOrigen");
		limpiarLista("AnoMes");		
		limpiarLista("nochesSolicitadas");
		
		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();
		});
	}
	
	/* Funcion al seleccionar origen */
	var seleccionOrigen = function( onComplete ) {	
		
		limpiarLista("AnoMes");	
		limpiarLista("nochesSolicitadas");
		if (nulo(c("codOrigen").val())) return;
		
		limpiarLista("AnoMes", true); // Mensaje 'cargando'
		limpiarLista("nochesSolicitadas", true);
		
		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);
		
		$(form + " .fechaSalida").text("");
		$(form + " .fechaRegreso").text("");		
		
		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.fechaSalida ) );		
		
		if (!estancia) return;
		var fRegreso = new Date( fSalida.getFullYear(), fSalida.getMonth(), fSalida.getDate() + estancia );
			
		$(form + " .fechaRegreso").text( fRegreso.format( literales.fechaRegreso ) );
		
		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);
			for (var k=1; k<=nnin; k++) {
				if ( c("habitacion"+j+"_edadnino"+k).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 : [] }
			};
			for (var k=1; k<=parseInt(o.Children, 10); k++) {
				o.EdadesNinos.Edad.push( c("habitacion"+j+"_edadnino"+k).val() );
			}
			setHabitacion.Habitacion.push( o );
		}
		
		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"),
			
			soloOfertas			: $(form + " input[type=hidden][id$=ParamSoloOferta]").val() || 0,
			sesId				: getSesId()
			
		}

		// 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;
				
			}  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() {
			if ($(this).hasClass("disabled")) return false;
			$(this).dpDisplay();
			this.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 ) {

	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()"
	}
	
	var pathImagenes = "./contenidos/ibj_b2c/imagenes/";
	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; }
		
		$.ajax({
			type: hayDatos ? "post" : "get",
			url: url,
			data: hayDatos ? data : undefined,
			dataType: "html",
			success: function( code ) { 			
			
				// 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 );
				self.show( smallStyle );
				if (typeof onComplete == "function") onComplete();
			}, true );
		} else {
			self.popupdata.html( content );
			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 ) {
	
		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;
		
	}
	
	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();
		
		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);
		
	});

}

/* 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 - 130
			}					
		} 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 );
	} )
	$("#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 corréctamente.");
			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() {
	
		// 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 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";
		
		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";
		}
		
		$("#comparadorHoteles .A select").html( lista );
		$("#comparadorHoteles .B select").html( lista.replace(/ selected>/, '>') );		
		
	}
	
	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 "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);
		},
		
		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 = "./contenidos/ibj_b2c/imagenes/"+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) * .05;
			max.lat += (max.lat - min.lat) * .05;
			min.lng -= (max.lng - min.lng) * .05;
			max.lng += (max.lng - min.lng) * .05;
					
			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 = "./contenidos/ibj_b2c/imagenes/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;
		
		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 = $(".resultado", this.container);
		this.lat = lat;
		this.lng = lng;
		
		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();

}

/* 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) {
			e.preventDefault();
			$("ul li", menu).removeClass("seleccion");
			$(this).parent().addClass("seleccion");
			$("#contenidoEstatico").load( this.href );
		});
		
		if ($("ul li.seleccion", menu).size()>0) {
			$("ul li.seleccion:eq(0) a:not(.static)", menu).each( function() {
				$("#contenidoEstatico").load( this.href );
			} );
		} else {
			$("h2 a:not(.static)", menu).each( function() {
				if (!this.href) return;
				if (!this.href.split("#").shift()) return;
				if (this.href.split("#").shift() == document.location.href) return
				$("#contenidoEstatico").load( this.href );
			});
		}
	});

	/* 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 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 checkForm = function(e) {
		
		var error = new Array();
		$( "input, textarea, select", this ).removeClass("error");
		
		// Required
		$("input.required, textarea.required, select.required", this).each( function() {
			if ($(this).val() == "") error.push({ type: "required", target: this })
		} );
		
		// Email 
		$("input.email", this).each( function() {
			if ( !emailPattern.test( $(this).val() )) error.push({ type: "email", target: this })
		} );
		
		// Telefono
		$("input.phone", this).each( function() {
			if ( !phonePattern.test( $(this).val() )) error.push({ type: "phone", target: this })
		} );
		
		// Valores iguales
		var sameval = "";
		$("input.samevalue", this).each( function() {
			if (!sameval) sameval = $(this).val();
			else if (sameval != $(this).val()) error.push({ type: "samevalue", target: this });
		} );
		
		// NIF/NIE
		var sameval = "";
		$("input.dni", this).each( function() { 
		
			var dni = $(this).val().toUpperCase();
						
			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", this).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) { 
			e.preventDefault();
			e.stopImmediatePropagation();
			
			var output = "";
			for (var i in error) {				
				$( error[i].target ).addClass("error");
			}
			
			alert( literales.formularioGenericError || "Por favor, rellene los campos corréctamente" ); 
			if (typeof window.hideLoader == "function") hideLoader();
			
			console.log(error);
			
			return false;
		}
		
	}

	var targets = $( selector?selector:defaultSelector, env?env:document );	
	targets.bind( "submit", checkForm );

}

/* 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);
};