/**
 * Requiere AvailabilityWrapper.js
 */

/**
 * cliente rpc
 */
var jsonrpc = new JSONRpcClient("/x/JSON-RPC");

/**
 * Comisión para un comprador
 * @param {Number} id identificador
 * @param {String} descripcion descripcion del mercado
 */

var Mercado = function(id, descripcion){
	this.id = id;
	this.descripcion = descripcion;
}
/**
 * Parámetros del vendedor
 * @param {Boolean} trasNoche indica si los servicios del vendedor trascienden la noche
 * @param {Boolean} entradasFijas indica si los servicios del vendedor se prestan en fechas de entrada fija
 * @param {Number} minCantNoches indica la cantidad de noches mínimas a reservar
 */
var Params = function(trasNoche, entradasFijas, minCantNoches, cutOff){
	this.trasNoche = trasNoche;
	this.entradasFijas = entradasFijas;
	this.minCantNoches = minCantNoches;
	this.cutOff = cutOff;
}
/**
 * Rubro de vendedor
 * @param {Number} id identificador
 * @param {String} descripcion descripcion del rubro
 */
var RubroVendedor = function(id, descripcion){
	this.id = id;
	this.descripcion = descripcion;
}
/**
 * Tipo de vendedor
 * @param {Number} id identificador
 * @param {RubroVendedor} rubro descripcion del rubro
 */
var TypeVendedor = function(id, descripcion, rubro){
	this.id = id;
	this.rubro = rubro;
	this.descripcion = descripcion;
}

var Availability = function(buyerId, vendor, checkIn, checkOut){
	this.availables = getAvailabilityByDayWrapper(buyerId, vendor.id, checkIn, checkOut);
	this._STRUCTURE_CHECKIN = checkIn;
	this._STRUCTURE_CHECKOUT = checkOut;
	this.availablesByMercadoTypeRoom = null;
	this._STRUCTURE_CHECKIN_TYPEROOM = checkIn;
	this._STRUCTURE_CHECKOUT_TYPEROOM = checkOut;
	this.buyerId = buyerId;
	this.cantPersonas = null;
	this.mercadoId = null;
	this.typeRoomId = null;
	this.checkIn = null;
	this.checkOut = null;
	this.vendedor = vendor;
	
	this.observers = new Array();
	
	this.that = null;
	
	this.TYPE_FULL = "FULL";
	this.TYPE_PARTIAL = "PARTIAL";
	this.TYPE_NULL = "NULL";
	
	this.STYLE_TYPE_FULL = "full";
	this.STYLE_TYPE_PARTIAL = "partial";
	this.STYLE_TYPE_NULL = "null";
	
	/**
	 * Verifica que la estructura que mantiene la disponibilidad contenga información de la
	 * fecha solicitada
	 * @param {String} date
	 * @param {Number} typeRoom (si es undefined o null se verifica para la estructura que no lo tiene en cuenta)
	 */
	this.ifNotPresentRetrieve = function(date, typeRoom){
		if ((typeRoom == undefined)||(typeRoom = null)) {
			if (before(strToDate(date), strToDate(this._STRUCTURE_CHECKOUT))) 
				return;
			var newStructureCheckOut = dateToStr(shiftDate(strToDate(this._STRUCTURE_CHECKOUT), 365));
			getAvailabilityByDayWrapper(this.buyerId, this.vendedor.id, this._STRUCTURE_CHECKOUT, newStructureCheckOut, this.availables);
			this._STRUCTURE_CHECKOUT = newStructureCheckOut;
		}else{
			if (before(strToDate(date), strToDate(this._STRUCTURE_CHECKOUT_TYPEROOM))) 
				return;
			var newStructureCheckOut = dateToStr(shiftDate(strToDate(this._STRUCTURE_CHECKOUT_TYPEROOM), 365));
			getAvailabilityByMarketTypeRoomDayWrapper(this.buyerId, this.vendedor.id, this._STRUCTURE_CHECKOUT_TYPEROOM, newStructureCheckOut, this.availablesByMercadoTypeRoom);
			this._STRUCTURE_CHECKOUT_TYPEROOM = newStructureCheckOut;
		}
	}
	
	/**
	 * Devuelve la estructura de disponibilidad a usar, si se especifica tipo de habitación
	 * se usa la que discrimina mercado y tipo de hab, sino la que discrimina sólo mercado
	 */
	this.getEstructuraDisponibilidad = function(){
		if(this.typeRoomId==null)
			return this.availables;
		return this.availablesByMercadoTypeRoom;
	}
	
	/**
	 * Agrega observadores, cuando cambie algún parámetro de disponibilidad
	 * se invocará al método update(this) del observador
	 * @param {Object} objeto observador
	 */
	 this.addObserver = function(observer){
	 	this.observers.push(observer);
	 }
	 
	 /**
	 * Elimina observadores
	 * @param {Object} objeto observador
	 */
	 this.delObserver = function(observer){
	 	var i = 0;
	 	while((i<this.observers.length)&&(this.observers[i]!=observer))
	 		i++;
	 	if((i<this.observers.length)&&(this.observers[i]==observer)){
	 		/*for(j=i; j<this.observers.length-1; j++){
	 			this.observers[j]=this.observers[j+1];
	 		}
		 	this.observers.length = this.observers.length - 1;*/
		 	this.observers[i]=null;
	 	}
	 }
	 
	 /**
	  * Notifica a los observadores de un cambio en los parámetros de la disponibilidad
	  */
	 this.notifyChange = function(){
	 	for(i in this.observers){
	 		try{	
	 			this.observers[i].update(this);
	 		}catch(e){
	 		}
	 	}
	 }
	 
	/**
	 * Setea la cantidad de personas
	 * @param {Number} cantidad de personas para las que se busca disponibilidad
	 */
	this.setCantPersonas = function(cantPersonas){
		this.cantPersonas = cantPersonas;
		this.notifyChange();
	}
	
	/**
	 * Setea el identificador de mercado
	 * @param {Number} identificador del mercado para el que se busca disponibilidad
	 */
	this.setMercadoId = function(mercadoId){
		this.mercadoId = mercadoId;
		this.notifyChange();
	}
	
	/**
	 * Setea el identificador de tipo de habitación
	 * @param {Number} identificador del tipo de habitación para el que se busca disponibilidad
	 */
	this.setTypeRoomId = function(typeRoomId){
		if(this.typeRoomId==null)
			this.availablesByMercadoTypeRoom = getAvailabilityByMarketTypeRoomDayWrapper(buyerId, vendor.id, checkIn, checkOut);
		this.typeRoomId = typeRoomId;
		this.notifyChange();
	}
	
	/**
	 * Setea la fecha de check in
	 * @param {String} fecha de check in para el que se busca disponibilidad
	 */
	this.setCheckIn = function(checkIn){
		this.checkIn = checkIn;
		this.notifyChange();
	}

	/**
	 * Setea la fecha de check out
	 * @param {String} fecha de check out para el que se busca disponibilidad
	 */
	this.setCheckOut = function(checkOut){
		this.checkOut = checkOut;
		this.notifyChange();
	}
	
	/**
	 * Verifica el tipo de disponibilidad para cierta cantidad de personas en un rango de fechas dado
	 * @return [TYPE_FULL|TYPE_PARTIAL|TYPE_NULL]
	 */
	this.typeAvailability = function(mercadoId, cantPersonas, checkIn, checkOut, vendedor, idTypeRoom){
		if(mercadoId==undefined)
			mercadoId = this.mercadoId;
		if(cantPersonas==undefined)
			cantPersonas = this.cantPersonas;
		if(checkIn==undefined)
			checkIn = this.checkIn;
		if(checkOut==undefined)
			checkOut = this.checkOut;
		if(vendedor==undefined)
			vendedor = this.vendedor;
			
		this.ifNotPresentRetrieve(checkOut, idTypeRoom);//Verifica que esté en la estructura
			
		var byDay = null;
		if((idTypeRoom==undefined)||(idTypeRoom==null)||(idTypeRoom.length==0))
			byDay = this.availables.map[mercadoId];
		else
			byDay = this.availablesByMercadoTypeRoom.map[mercadoId].map[idTypeRoom];
		
		if((byDay==undefined)||(byDay==null))
			return this.TYPE_NULL;
		
		hayDispo = 0;
		noHayDispo = 0;
		act = strToDate(checkIn);
		fin = strToDate(checkOut);
		if(differenceDays(fin, act)<0)
			return false;
		
		try {	
			if(vendedor.params.entradasFijas){
				//Si el vendedor tiene seteado entradas fijas => necesariamente la fecha de check-in debe coincidir con una EF
				if(vendedor.efByIn[checkIn] == null || vendedor.efByIn[checkIn] == undefined){
					return this.TYPE_PARTIAL;
				
				} else {
					//Validar que la fecha de check-out se corresponde a la EF del check-in seleccionado
					var efs = vendedor.efByIn[checkIn].list;
					var encontrado = false;
					for(k in efs){
						var ef = efs[k];
						if(ef.checkOut == checkOut){
							encontrado = true;
							break;
						}
					}
					if(!encontrado){
						return this.TYPE_PARTIAL;
					}
					
				}
			} else {
				//Si algunas de las fechas de check-in y check-out están dentro de una EF => no son fechas seleccionables
				if((vendedor.efBetween[checkIn]!= null && vendedor.efBetween[checkIn] != undefined) ||
					(vendedor.efBetween[checkOut] != null && vendedor.efBetween[checkOut] != undefined)){
					
					return this.TYPE_PARTIAL;
				}
				
				//Si la fecha de check-in corresponde al check-in de una EF, entonces necesariamente la fecha de check-out debe coincidir
				if(vendedor.efByIn[checkIn]!= null || vendedor.efByIn[checkIn] != undefined){
					
					//Validar que la fecha de check-out se corresponde a la EF del check-in seleccionado
					var efs = vendedor.efByIn[checkIn].list;
					var encontrado = false;
					for(k in efs){
						var ef = efs[k];
						if(ef.checkOut == checkOut){
							encontrado = true;
							break;
						}
					}
					if(!encontrado){
						return this.TYPE_PARTIAL;
					}
					
				} else {
					//En este caso se corresponde con una entrada libre, por lo tanto, tanto la fecha de check-out también debe ser libre
					
					//Si la fecha de check-out coincide con la fecha de check-in de una EF debo asegurarme que sea EL
					if((vendedor.efByIn[checkOut]!=null)&&(vendedor.efByIn[checkOut]!=undefined)){
							var ayerStr = dateToStr(shiftDate(strToDate(checkOut), -1));
							if((vendedor.efByIn[ayerStr] != null && vendedor.efByIn[ayerStr]!=undefined) ||
							   (vendedor.efBetween[ayerStr]!= null && vendedor.efBetween[ayerStr]!=undefined)) {
								return this.TYPE_PARTIAL;
							}
					} else
						//Si la fecha de check-out coincide con la fecha de check-out de una EF debo asegurarme que sea EL
						if((this.vendedor.efByOut[checkOut]!=null)&&(vendedor.efByOut[checkOut]!=undefined)){
							var manianaStr = dateToStr(shiftDate(strToDate(checkOut), 1));
							if((vendedor.efByOut[manianaStr] != null && vendedor.efByOut[manianaStr]!=undefined) ||
							   (vendedor.efBetween[manianaStr]!= null && vendedor.efBetween[manianaStr]!=undefined)) {
								return this.TYPE_PARTIAL;
							} 
						}
				}
				
			} 
		} catch(e){
			
		}	
			
		while(differenceDays(act, fin)!=0){
			actStr = dateToStr(act);
			if((byDay.map[actStr]<cantPersonas)||(byDay.map[actStr]==undefined)||(byDay.map[actStr]==null))
				noHayDispo++;
			else
				hayDispo++;
			act = shiftDate(act, 1);
		}
		if(hayDispo==0)
			return this.TYPE_NULL;
		else if(noHayDispo==0)
			return this.TYPE_FULL;
		else
			return this.TYPE_PARTIAL;
	}
	
	/**
	 * Verifica el tipo de disponibilidad para cierta cantidad de personas para una fecha dada
	 * @return [TYPE_FULL|TYPE_PARTIAL|TYPE_NULL]
	 */
	/*this.dayTypeAvailability = function(mercadoId, cantPersonas, day){
		var porMercado = this.availables.map[mercadoId];
		
		
		if((porMercado==undefined)||(porMercado==null)){
			return this.TYPE_NULL;
		}
		if((porMercado.map[day]==undefined)||(porMercado.map[day]==null)){
			return this.TYPE_NULL;
		}
		if(porMercado.map[day]==0){
			return this.TYPE_NULL;
		}
		if((porMercado.map[day]<that.cantPersonas)&&(porMercado.map[day]>0)){
			return this.TYPE_PARTIAL;
		}
		return this.TYPE_FULL;
	}*/
	
	/**
	 * Devuelve un estilo para un tipo de disponibilidad
	 * @return 
	 * 	TYPE_FULL => STYLE_TYPE_FULL 
	 * 	TYPE_PARTIAL => STYLE_TYPE_PARTIAL
	 * 	TYPE_NULL => STYLE_TYPE_NULL
	 */
	this.typeToStyle = function(typeAvail){
		if(typeAvail == this.TYPE_FULL)
			return this.STYLE_TYPE_FULL;
		if(typeAvail == this.TYPE_PARTIAL)
			return this.STYLE_TYPE_PARTIAL;
		if(typeAvail == this.TYPE_NULL)
			return this.STYLE_TYPE_NULL;
		return "";
	}
	
	/**
	 * Verifica si hay disponibilidad para cierta cantidad de personas en un rango de fechas dado
	 */
	/*this.isAvailable = function(cantPersonas, mercadoId, checkIn, checkOut){
		porMercado = this.availables.map[mercadoId];
		if((porMercado==undefined)||(porMercado==null))
			return false;
		act = strToDate(checkIn);
		fin = strToDate(checkOut);
		while(differenceDays(act, fin)!=0){
			actStr = dateToStr(act);
			if((porMercado.map[actStr]<cantPersonas)||(porMercado.map[actStr]==undefined)||(porMercado.map[actStr]==null))
				return false;
			act = shiftDate(act, 1);
		}
		return true;
	}*/
	
	/**
	 * Verifica la disponibilidad para un día, lo utiliza el componente calendario 
	 * para habilitar/deshabilitar una fecha
	 */
	this.isNotAvailableForCalendar = function(date, y, m, d){
		var that = Availability.that;
		this.ifNotPresentRetrieve(dateToStr(date), that.typeRoomId);//Verifica que esté en la estructura
		
		var byDay = null;
		if(that.typeRoomId==null)
			byDay = this.availables.map[that.mercadoId];
		else
			byDay = this.availablesByMercadoTypeRoom.map[that.mercadoId].map[that.typeRoomId];
		
		if((byDay==undefined)||(byDay==null)){
			return this.STYLE_TYPE_NULL;
		}
		var day = dateToStr(date);
		if((byDay.map[day]==undefined)||(byDay.map[day]==null)){
			return this.STYLE_TYPE_NULL;
		}
		if(byDay.map[day]==0){
			return this.STYLE_TYPE_NULL;
		}
		if((byDay.map[day]<that.cantPersonas)&&(byDay.map[day]>0)){
			return this.STYLE_TYPE_PARTIAL;
		}
		return this.STYLE_TYPE_FULL;
	}
	
	this.calendario = function(input, orDate, nextIn, disparador, control){
		Availability.that = this;
	    Calendar.setup({
	       inputField : input, // id del campo de texto
	       orDate : orDate, // fecha para inicializar
		   nextIn : nextIn, // id del siguiente input a actualizar automaticamente
		   ifFormat : "%d/%m/%Y", // formato de la fecha que se escriba en el campo de texto, dia(nro), mes(nro), anio(nro), mes(nombre)
	       button : disparador , // el id del bot?n que lanzar? el calendario
	       controlSelect : control,
	       dateStatusFunc: this.isNotAvailableForCalendar
	     }, input, orDate, nextIn, disparador);
	};
	
	/**
	 * Devuelve una lista de tipos de habitaciones disponibles
	 * Cada posición de la lista contiene
	 * 			Long id identificador del tipo de habitación;
	 *			String denomination descripción del tipo de habitación;
	 *			int capacity capacidad del tipo de habitación (en cantidad de personas);
	 *			int cantidad cantidad de habitaciones disponibles de ese tipo;
	 *			Double averageCost costo promedio por habitación;
	 *			boolean semiAvailable indica si se debe realizar un cambio de habitación en el período solicitado por falta de disponibilidad;
	 * @param vendorId identificador del vendedor
	 * @param buyerId identificador del comprador
	 * @param checkIn checkIn (opcional, si no se especifica se toma el valor seteado en la instancia)
	 * @param checkOut checkOut (opcional, si no se especifica se toma el valor seteado en la instancia)
	 * @param cantAdultos (opcional, si no se especifica se toma el valor seteado en la instancia, cantidad de personas )
	 * @param cantMenores (opcional, si no se especifica se toma el valor 0)
	 * @param idMercado (opcional, si no se especifica se toma el valor seteado en la instancia)
	 */
	this.getAvailableRooms = function(vendorId, buyerId, checkIn, checkOut, cantAdultos, cantMenores, idMercado, cantHabitaciones, idWebParam){
		if((checkIn == null)||(checkIn == undefined))
			checkIn = this.checkIn;
		if((checkOut == null)||(checkOut == undefined))
			checkOut = this.checkOut;
		if((cantAdultos == null)||(cantAdultos==undefined))
			cantAdultos = this.cantPersonas;
		if((cantMenores==null)||(cantMenores==undefined))
			cantMenores = 0;
		if((idMercado==null)||(idMercado==undefined))
			idMercado = this.mercadoId;
		if((idMercado==null)||(idMercado==undefined)){
			cantHabitaciones = 1;
		}	
		return jsonrpc.JsonVendedor.getAvailableRoomsForWeb(vendorId, buyerId, checkIn, checkOut, cantAdultos, cantMenores, idMercado, cantHabitaciones, idWebParam);
	}

	this.getAvailableRoomsTravelAgency = function(vendorId, buyerId, travelAgencyId, checkIn, checkOut, cantAdultos, cantMenores, idMercado, cantHabitaciones, idWebParam){
		if((checkIn == null)||(checkIn == undefined))
			checkIn = this.checkIn;
		if((checkOut == null)||(checkOut == undefined))
			checkOut = this.checkOut;
		if((cantAdultos == null)||(cantAdultos==undefined))
			cantAdultos = this.cantPersonas;
		if((cantMenores==null)||(cantMenores==undefined))
			cantMenores = 0;
		if((idMercado==null)||(idMercado==undefined))
			idMercado = this.mercadoId;
		if((idMercado==null)||(idMercado==undefined)){
			cantHabitaciones = 1;
		}	
		return jsonrpc.JsonVendedor.getAvailableRoomsForWebTravelAgency(vendorId, buyerId, travelAgencyId, checkIn, checkOut, cantAdultos, cantMenores, idMercado, cantHabitaciones, idWebParam);
	}	
	
	
	/**
	 * Devuelve una lista de tipos de habitaciones disponibles para la reserva por destino
	 * Cada posición de la lista contiene
	 * 			Long id identificador del tipo de habitación;
	 *			String denomination descripción del tipo de habitación;
	 *			int capacity capacidad del tipo de habitación (en cantidad de personas);
	 *			int cantidad cantidad de habitaciones disponibles de ese tipo;
	 *			Double averageCost costo promedio por habitación;
	 *			boolean semiAvailable indica si se debe realizar un cambio de habitación en el período solicitado por falta de disponibilidad;
	 * @param vendorId identificador del vendedor
	 * @param buyerId identificador del comprador
	 * @param checkIn checkIn (opcional, si no se especifica se toma el valor seteado en la instancia)
	 * @param checkOut checkOut (opcional, si no se especifica se toma el valor seteado en la instancia)
	 * @param cantAdultos (opcional, si no se especifica se toma el valor seteado en la instancia, cantidad de personas )
	 * @param cantMenores (opcional, si no se especifica se toma el valor 0)
	 * @param idMercado (opcional, si no se especifica se toma el valor seteado en la instancia)
	 */
	this.getAvailableRoomsForLocationReserve = function(vendorId, buyerId, checkIn, checkOut, cantAdultos, cantMenores, idMercado){
		if((checkIn == null)||(checkIn == undefined))
			checkIn = this.checkIn;
		if((checkOut == null)||(checkOut == undefined))
			checkOut = this.checkOut;
		if((cantAdultos == null)||(cantAdultos==undefined))
			cantAdultos = this.cantPersonas;
		if((cantMenores==null)||(cantMenores==undefined))
			cantMenores = 0;
		if((idMercado==null)||(idMercado==undefined))
			idMercado = this.mercadoId;
		if((idMercado==null)||(idMercado==undefined)){
			cantHabitaciones = 1;
		}	
		return jsonrpc.JsonVendedor.getAvailableRoomsForLocationReserve(vendorId, buyerId, checkIn, checkOut, cantAdultos, cantMenores, idMercado);
	}
}

/**
 * @param {Number} id identificador del vendedor
 * @param {String} nombre del vendedor
 * @param {String} destino lugar donde actúa el vendedor
 * @param {TypeVendedor} tipo tipo de vendedor
 * @param {Params} params parámetros del vendedor
 */
var Vendedor = function(id, name, destino, tipo, params){
	this.id = id;
	this.name = name;
	this.destino = destino;
	this.tipo = tipo;
	this.params = params;
	this.mercados= new Array();
	this.webMarket = null;
	this.availability = null;
	this.that = null;
	this.descripcion = null;
	
	this.efByIn = null;
	this.efByOut = null;
	this.efBetween = null;
	
	this.tmpCheckIn = null;

	this.urlImg1 = null;
	
	this.typeRooms = null;
	
	this.cantNoches = null;
	
	
	this.setCantidadNoches = function(cantNoches){
		this.cantNoches = cantNoches;
	}
	/**
	 * Obtiene la url de la primer imagen del vendedor
	 */
	this.getUrlImg1 = function (){
		if(this.urlImg1==null)
			this.urlImg1 = jsonrpc.JsonVendedor.getVendorImg(this.id);
		return this.urlImg1;
	}
	
	/**
	 * Obtiene la descripcion del vendedor
	 */
	this.getDescripcionVendedor = function(){
		if (this.descripcion==null)
			this.descripcion = jsonrpc.JsonVendedor.getDescripcionVendedor(this.id);
		return this.descripcion;
	}
	/**
	 * Agrega una comision al vendedor
	 * @param {Number} id identificador del mercado
	 * @param {String} descripcion descripcion del mercado
	 */
	this.addMercado = function(id, descripcion){
		this.mercados.push(new Mercado(id, descripcion));
	}
	/**
	 * Setea el mercado web asignado por el vendedor que está transaccionando para el 
	 * vendedor
	 * @param {Mercado} webMarket
	 */
	this.setWebMarket = function(webMarket){
		if((webMarket!=null)&&(webMarket!=undefined))
			this.webMarket = webMarket;
		else
			this.webMarket = null;
	}
	
	/**
	 * Obtiene la disponibilidad desde el servidor en caso de no haberla calculado
	 * @param {Number} buyerId identificador del comprador
	 * @param {Number} mercadoId identificador del mercado
	 * @param {String} checkIn fecha de inicio
	 * @param {String} checkOut fecha de fin
	 */
	this.retrieveAvailability = function(buyerId, checkIn, checkOut){
		this.availability = new Availability(buyerId, this, checkIn, checkOut);
	}
	
	/**
	 * Obtiene la disponibilidad desde el servidor en caso de no haberla calculado
	 * @param {Number} buyerId identificador del comprador
	 * @return {List<TypeRoomDTO>} lista de typeRooms del vendedor
	 */
	this.getTypeRooms = function(){
		if(this.typeRooms === null)
			this.typeRooms = jsonrpc.JsonVendedor.getTypeRooms(this.id).list;
		return this.typeRooms;
	}
	
	/**
	 * Obtiene las entradas fijas para un vendedor
	 */
	this.getEntradasFijas = function(from, to, idComprador){
		//alert(this.id + '-' idComprador + '-' from + '' + to + '' + this.cantNoches);
		var ef = true;
		if(this.params.entradasFijas == null ||this.params.entradasFijas ==  undefined ){
			ef = false;
		}
		
		var result = jsonrpc.JsonVendedor.getEntradasFijas(this.id, idComprador, from, to, ef, this.cantNoches);
		this.efByIn = result.entradasFijasPorIn.map;
		this.efByOut = result.entradasFijasPorOut.map;
		this.efBetween = result.daysBetween.map;
		return result.entradasFijas.list;
	}
	
	/**
	 * Verifica si la fecha de checkIn es válida (si no es una fecha dentro de un período de ef)
	 * @param {String} checkIn
	 */
	this.isValidCheckIn = function(checkIn){
		if(this.params.entradasFijas){
			if((this.efBetween[checkIn]!=null)&&(this.efBetween[checkIn]!=undefined)){
				return false;
			}
			if(((this.efByOut[checkIn]!=null)&&(this.efByOut[checkIn]!=undefined))&&((this.efByIn[checkIn]==null)||(this.efByIn[checkIn]==undefined))){
				return false;
			}
		} else {
			if((this.efByIn[checkIn]!=null)&&(this.efByIn[checkIn]!=undefined)){
				return true;
			}
			
			if((this.efBetween[checkIn]!=null)&&(this.efBetween[checkIn]!=undefined)){
				return false;
			}
			
			if((this.efByOut[checkIn]!=null)&&(this.efByOut[checkIn]!=undefined)) {
				var manianaStr = dateToStr(shiftDate(strToDate(checkIn), 1));
				if((this.efByOut[manianaStr] == null || this.efByOut[manianaStr]==undefined) &&
				   (this.efBetween[manianaStr]== null || this.efBetween[manianaStr]==undefined)) {
					return true;
				} else {
					return false;
				}
			}	
		}	
		
		return true;
	}
	
	/**
	 * Verifica si la fecha de checkOut es válida 
	 * @param {String} checkIn
	 * @param {String} checkOut
	 * @return 
	 * 			Si checkIn es de ef y checkOut no es checkout de esa ef => false
	 * 			Si checkIn es libre y checkOut es libre => true
	 * 			Si checkOut está dentro de un período de ef => false
	 */
	this.isValidCheckOut = function(checkIn, checkOut){
		//siempre que caiga dentro de una EF no es valido el check-out
		if((this.efBetween[checkOut]!=null)||(this.efBetween[checkOut]!=undefined)){
				return false;
		}
		
		//siempre que la fecha de check-in corresponda a una EF, necesariamente la fecha de check-out de la EF debe coincidir con la seteada
		if((this.efByIn[checkIn]!=null)&&(this.efByIn[checkIn]!=undefined)){
			var tmpEntradasFijas = this.efByIn[checkIn].list;
			for(i in tmpEntradasFijas){
				if(tmpEntradasFijas[i].checkOut==checkOut)
					return true;
			}
			return false;
		}
		
		if(!this.params.entradasFijas){
			//si la fecha de check-out coincide con la fecha de check-in de una EF debo asegurarme que sea EL
			if((this.efByIn[checkOut]!=null)&&(this.efByIn[checkOut]!=undefined)){
				var ayerStr = dateToStr(shiftDate(strToDate(checkOut), -1));
				if((this.efByIn[ayerStr] == null || this.efByIn[ayerStr]==undefined) &&
				   (this.efBetween[ayerStr]== null || this.efBetween[ayerStr]==undefined)) {
					return true;
				} else {
					return false;
				}
			}
			
			//Si la fecha de check-out coincide con la fecha de check-in de una EF debo asegurarme que sea EL
			if((this.efByOut[checkOut]!=null)&&(this.efByOut[checkOut]!=undefined)){
				var manianaStr = dateToStr(shiftDate(strToDate(checkOut), 1));
				if((this.efByOut[manianaStr] == null || this.efByOut[manianaStr]==undefined) &&
				   (this.efBetween[manianaStr]== null || this.efBetween[manianaStr]==undefined)) {
					return true;
				} else {
					return false;
				}
			}
		}
			
		
		return true;
	}
	
	/**
	 * Obtiene una fecha de checkOut por defecto para una entrada de checkIn
	 * Si checkIn es una ef, selecciona el primer checkOut para la fecha
	 * Si no trasciende noche, selecciona checkOut = checkIn + 1
	 * Si es libre selecciona checkOut = checkIn
	 * @param {String} checkIn
	 */
	this.getDefaultCheckOut = function(checkIn){
    	if((this.efByIn[checkIn]!=null)&&(this.efByIn[checkIn]!=undefined)){
	    	/*Si es una entrada fija*/
    		var tmpEntradasFijas = vendedor.efByIn[checkIn].list;
    		var ef = null;
    		for(i in tmpEntradasFijas){
    			ef = tmpEntradasFijas[i];
    			break;
    		}
    		return ef.checkOut;
    	}else if(!vendedor.params.trasNoche){/*Si el servicio no trasciende la noche*/
    		return dateToStr(shiftDate(strToDate(checkIn), 1));
    	}else{ /*Si es entrada libre*/
    		return checkIn;
    	}
	}
	
	/**
	 * Verifica la validez de un día para ser seleccionado como check in, lo utiliza el componente calendario 
	 * para habilitar/deshabilitar una fecha
	 */
	this.checkInStatus = function(date, y, m, d){
		var that = Vendedor.that;
		var strDay = dateToStr(date);
		var today = strToDate(dateToStr(new Date()));
		if(differenceDays(date, today)<0)
			return true;
		//Si es checkIn de EF se debe habilitar si hay disponibilidad en algún período de las ef
		if((that.efByIn[strDay]!=null)&&(that.efByIn[strDay]!=undefined)){
			var efs = that.efByIn[strDay].list;
			for(i in efs){
				var ef = efs[i];
				if(that.availability!=null){
					var typeAvail = that.availability.typeAvailability(undefined, undefined, ef.checkIn, ef.checkOut,that);
					return that.availability.typeToStyle(typeAvail);
				}else
					return false; //Si es entrada fija y no tengo el cálculo de dispo, muestro sólo habilitado
			}
		}
		//Si es un checkOut de EF se debe inhabilitar
		if((that.efByOut[strDay]!=null)&&(that.efByOut[strDay]!=undefined)) {
			if(that.params.entradasFijas){
				return true;	
			} else {
				//Si el siguiente día no está dentro de los vectores de check-out ni en between entonces se trata de una entrada libre
				var manianaStr = dateToStr(shiftDate(date, 1));
				if((that.efByOut[manianaStr] == null || that.efByOut[manianaStr]==undefined) &&
				   (that.efBetween[manianaStr]== null || that.efBetween[manianaStr]==undefined)) {
					if(that.availability!=null){
						Availability.that = that.availability;
						return that.availability.isNotAvailableForCalendar(date, y, m, d);
					} else {
						return false;
					}
					
				} else {
					return true;
				}
				
			}
		}
			
		//Si está dentro de un período de EF se debe inhabilitar
		if((that.efBetween[strDay]!=null)&&(that.efBetween[strDay]!=undefined))
			return true;
		
		if(that.params.entradasFijas){
			return true;
		}	
		
		if(that.availability!=null){
			Availability.that = that.availability;
			return that.availability.isNotAvailableForCalendar(date, y, m, d);
		}
		return false;
	}
	
	/**
	 * Verifica la validez de un día para ser seleccionado como check in, lo utiliza el componente calendario 
	 * para habilitar/deshabilitar una fecha
	 */
	this.checkOutStatus = function(date, y, m, d){
		var that = Vendedor.that;
		var strDay = dateToStr(date);
		var today = strToDate(dateToStr(new Date()));
		if(differenceDays(date, today)<0)
			return true;
		var checkIn = that.tmpCheckIn;
		//Si es checkIn de EF se debe habilitar si hay disponibilidad en algún período de las ef
		if((that.efByIn[checkIn]!=null)&&(that.efByIn[checkIn]!=undefined)){
			var efs = that.efByIn[checkIn].list;
			for(i in efs){
				var ef = efs[i];
				if(ef.checkOut == strDay)
					return false;
			}
			//Si eligió una entrada fija sólo puede seleccionar una salida de entrada fija
			return true;
		}
		//Si es un checkOut de EF se debe inhabilitar
		if((that.efByOut[strDay]!=null)&&(that.efByOut[strDay]!=undefined)){
			if(that.params.entradasFijas){
				return true;	
			} else {
				//Si el siguiente día no está dentro de los vectores de check-out ni en between entonces se trata de una entrada libre
				var manianaStr = dateToStr(shiftDate(date, 1));
				if((that.efByOut[manianaStr] == null || that.efByOut[manianaStr]==undefined) &&
				   (that.efBetween[manianaStr]== null || that.efBetween[manianaStr]==undefined)) {
					if(that.availability!=null){
						Availability.that = that.availability;
						return that.availability.isNotAvailableForCalendar(date, y, m, d);
					} else {
						return false;
					}
					
				} else {
					return true;
				}
				
			}
		}
			
		//Si es un checkIn de EF se debe inhabilitar
		if((that.efByIn[strDay]!=null)&&(that.efByIn[strDay]!=undefined)) {
			if(that.params.entradasFijas){
				return true;	
			} else {
				//Si el día anterior no está dentro de los vectores de check-in ni en between entonces se trata de una entrada libre
				var ayerStr = dateToStr(shiftDate(date, -1));
				if((that.efByIn[ayerStr] == null || that.efByIn[ayerStr]==undefined) &&
				   (that.efBetween[ayerStr]== null || that.efBetween[ayerStr]==undefined)) {
					if(that.availability!=null){
						Availability.that = that.availability;
						return that.availability.isNotAvailableForCalendar(date, y, m, d);
					} else {
						return false;
					}
					
				} else {
					return true;
				}
				
			}
			
		}
			
		//Si está dentro de un período de EF se debe inhabilitar
		if((that.efBetween[strDay]!=null)&&(that.efBetween[strDay]!=undefined))
			return true;
		
		if(that.params.entradasFijas){
			return true;
		}
		
		if(that.availability!=null){
			Availability.that = that.availability;
			return that.availability.isNotAvailableForCalendar(date, y, m, d);
		}
		return false;
	}

	/**
	 * Despliega el calendario para checkIn del vendedor
	 */
	this.checkInCalendar = function(input, orDate, nextIn, disparador, control){
		Vendedor.that = this;
	    Calendar.setup({
	       inputField : input, // id del campo de texto
	       orDate : orDate, // fecha para inicializar
		   nextIn : nextIn, // id del siguiente input a actualizar automaticamente
		   ifFormat : "%d/%m/%Y", // formato de la fecha que se escriba en el campo de texto, dia(nro), mes(nro), anio(nro), mes(nombre)
	       button : disparador , // el id del bot?n que lanzar? el calendario
	       controlSelect : control,
	       dateStatusFunc: this.checkInStatus
	     }, input, orDate, nextIn, disparador);
	};
	
	/**
	 * Despliega el calendario para checkOut del vendedor
	 * @param {String} checkIn string con la fecha de checkIn
	 */
	this.checkOutCalendar = function(input, orDate, nextIn, disparador, control, checkIn){
		Vendedor.that = this;
		this.tmpCheckIn = checkIn;
	    Calendar.setup({
	       inputField : input, // id del campo de texto
	       orDate : orDate, // fecha para inicializar
		   nextIn : nextIn, // id del siguiente input a actualizar automaticamente
		   ifFormat : "%d/%m/%Y", // formato de la fecha que se escriba en el campo de texto, dia(nro), mes(nro), anio(nro), mes(nombre)
	       button : disparador , // el id del bot?n que lanzar? el calendario
	       controlSelect : control,
	       dateStatusFunc: this.checkOutStatus
	     }, input, orDate, nextIn, disparador);
	};
	
	//Para calendario donde se muestra checkIn y checkOut simultáneamente
	this.checkInInput = null;
	this.checkOutInput = null;
	this.checkInValue = '';
	this.checkOutValue = '';
	this.calendar = null;
	
	this.onchangecheckin = null;
	this.onchangecheckout = null;
	
	/**
	 * Verifica la validez de un día para ser seleccionado como check in y checkOut, lo utiliza el componente calendario 
	 * para habilitar/deshabilitar una fecha y mostrar un período seleccionado
	 */
	this.checkInOutStatus = function(date, y, m, d){
		var that = Vendedor.that;
		//No eligió nada, o eligió las dos fechas
		if(that.checkInValue == ''){
			return that.checkInStatus(date, y, m, d);
		}
		//Sólo eligió checkIn
		if ((that.checkInValue != '')&&(that.checkOutValue=='')){
			that.tmpCheckIn = that.checkInValue;
			return that.checkOutStatus(date, y, m, d);
		}
		//Eligió checkin y checkOut
		var cin = strToDate(that.checkInValue);
		var cout = strToDate(that.checkOutValue);
		var filteredDate = strToDate(dateToStr(date));
		var dif1 = differenceDays(cin, filteredDate);
		var dif2 = differenceDays(cout, filteredDate);
		if((dif1<=0)&&(dif2>=0)){
			return "selperiod";		}
		return that.checkInStatus(date, y, m, d);
	}
	
	/**
	 * Atiende el evento de seleccionar una fecha en el calendario
	 * Si no se seleccionó ningún checkIn, se trata de checkIn
	 * Si se seleccionó sólo checkIn, se trata de checkOut
	 * Si se seleccionaron los dos, se trata de checkIn
	 * Si sólo se seleccionó checkIn, y se selecciona otro checkIn, se trata de otro checkIn
	 */
	this.selectDateInOut= function (cal) {
		if(cal.dateClicked){
			var that = Vendedor.that;
			if((that.checkInValue == '')||((that.checkInValue != '')&&(that.checkOutValue!=''))){
				that.checkInValue = dateToStr(cal.date);
				that.checkOutValue = '';
				if(that.checkOutInput!=null)
					that.checkOutInput.value = that.checkOutValue;
				if(that.checkInInput!=null){
					that.checkInInput.value = that.checkInValue;
					if(that.onchangecheckin!=null)
						that.onchangecheckin();
				}
			}
			else{
				var cin = strToDate(that.checkInValue);
				var diff = differenceDays(cin, strToDate(dateToStr(cal.date)));
				if(diff<0)
					that.checkOutValue = dateToStr(cal.date);
				else
					that.checkInValue = dateToStr(cal.date);
					
				if(that.checkOutInput!=null){
					that.checkOutInput.value = that.checkOutValue;
					if(that.onchangecheckout!=null)
						that.onchangecheckout();
				}	
			}
			cal.refresh(); //Para que se redibuje
		}
		return true;
	};
	
	/**
	 * Muestra el calendario para checkIn y checkOut del vendedor en alguna porción de html (div, td, span....)
	 * @param {String} inputIn string con el id del input para ingresar el checkIn cuando lo seleccione el usuario (puede ser null)
	 * @param {String} inputOut string con el id del input para ingresar el checkOut cuando lo seleccione el usuario (puede ser null)
	 * @param {Boolean} control true si se valida no ingresar fechas anteriores a la actual
	 * @param {String} container identificador del html que contendrá el calendario
	 * @param {Date} defaultDay fecha que debe aparecer seleccionada
	 */
	this.checkInOutCalendar = function(inputIn, inputOut, control, container, defaultDay){
		if(inputIn!=null)
			this.checkInInput = document.getElementById(inputIn);
		if(inputOut!=null)
			this.checkOutInput = document.getElementById(inputOut);
		Vendedor.that = this;
	    this.calendar = Calendar.setup({
	       dateStatusFunc: this.checkInOutStatus,
	       flat: container,
	       onSelect: this.selectDateInOut,
	       electric: false,
	       date:defaultDay
	     });
	};
	
	/**
	 * Oculta el calendario
	 */
	this.hideCalendar = function(){
		this.calendar.hide();
	}
}

/**
 * Obtiene un vendedor desde el servidor
 * @param buyerId identificador del comprador
 * @param vendorId identificador del vendedor
 * @return {Vendedor} vendedor asociado
 */
function retrieveVendedor(buyerId, vendorId){
	var vendorDto = null;
	if(buyerId!=null)
		vendorDto = jsonrpc.JsonVendedor.retrieveVendorAssociated(buyerId, vendorId);
	else
		vendorDto = jsonrpc.JsonVendedor.retrieveVendor(vendorId);
	
	var tipo = new TypeVendedor(vendorDto.tipoVendedor.id, vendorDto.tipoVendedor.descripcion, new RubroVendedor(vendorDto.tipoVendedor.rubro.id, vendorDto.tipoVendedor.rubro.descripcion));
	var params = new Params(vendorDto.params.trasNoche, vendorDto.params.entradasFijas, vendorDto.params.minCantNoches, vendorDto.params.cutOff);
	var vendedor = new Vendedor(vendorDto.id, vendorDto.name, vendorDto.destino, tipo, params);
	for(i in vendorDto.mercados.list)
		vendedor.addMercado(vendorDto.mercados.list[i].id, vendorDto.mercados.list[i].descripcion);
	vendedor.setWebMarket(vendorDto.webMarket);
	vendedor.getEntradasFijas(dateToStr(new Date()), dateToStr(shiftDate(new Date(), 940)), buyerId);
	return vendedor;
}

/**
 * Devuelve el importe para la solicitud de servicios (sólo para reservas web, ya que tiene en cuenta reseller, travelAgency y factores web)
 * @param idTypeRoom identificador de tipo de habitación
 * @param checkIn fecha de entrada
 * @param checkOut fecha de salida
 * @param cantGreaters cantidad de adultos
 * @param cantMinors cantidad de menores
 * @param cantHabitaciones cantidad de habitaciones
 * @param idMercado identificador de mercado
 * @return importe total
 */
function getRoomRateForWeb(idTypeRoom, checkIn, checkOut, cantGreaters, cantMinors, cantHabitaciones, idMercado, idWebParam){
	return jsonrpc.JsonVendedor.doWebTariff(idTypeRoom, checkIn, checkOut, cantGreaters, cantMinors, cantHabitaciones,idMercado, idWebParam);
}

function getRoomRateForWebTravelAgency(idTravelAgency, idTypeRoom, checkIn, checkOut, cantGreaters, cantMinors, cantHabitaciones, idMercado, idWebParam){
	return jsonrpc.JsonVendedor.doWebTariffTravelAgency(idTravelAgency, idTypeRoom, checkIn, checkOut, cantGreaters, cantMinors, cantHabitaciones,idMercado, idWebParam);
}

/**
 * Devuelve un arreglo con las url de las imágenes del tipo de habitación indicado
 */
_TYPEROOM_IMGS = new Array();
function getTypeRoomImgs(idTypeRoom){
	if((_TYPEROOM_IMGS[idTypeRoom]==null)||(_TYPEROOM_IMGS[idTypeRoom]==undefined))
		_TYPEROOM_IMGS[idTypeRoom] = jsonrpc.JsonVendedor.getTypeRoomImgs(idTypeRoom).list;
	return _TYPEROOM_IMGS[idTypeRoom];
}

/**
 * Devuelve la url del logo del vendedor
 */
 _LOGOS_VENDEDOR = new Array();
function getLogoVendedor(idVendedor){
	if((_LOGOS_VENDEDOR[idVendedor]==null)||(_LOGOS_VENDEDOR[idVendedor]==undefined))
		_LOGOS_VENDEDOR[idVendedor] = jsonrpc.JsonVendedor.getVendorLogo(idVendedor);
	return _LOGOS_VENDEDOR[idVendedor];
}