﻿var optype = {LOW_COST:0,NATIONAL_CARRIER:1,ONLINE_TRAVEL_AGENT:2,WEB_FARES_AIRLINE:3,TRAINS:4,BUSES:5,FERRIES:6,OTHER:7};
var transport = {AIR:'1',TRAIN:'2',BUS:'3',FERRY:'4'};
var server_time = (document['SERVER_TIME'] ? document['SERVER_TIME'] : SEARCH_TIME);
var add_timeout = 500;
var other_op_code = '$X';
var multiple_op_code = 'XX';
var msPerDay = (1000 * 60 * 60 * 24);
var hashVal = (window.location && window.location.hash ? window.location.hash : null);
var ccFeesIsTotal = (TXT_PLUS_CARD_FEES.toLowerCase() == TXT_FINAL_PRICE.toLowerCase());

var getElement = function(id){ return (document.all ? document.all[id] : document.getElementById(id)); };

var toggleDisplay = function(elem, id, onCss, offCss, forceClosed){
	if(typeof(elem) == 'string'){ elem = getElement(elem); }
	var panel = $('#' + id);
	var open = (panel.css('display') == 'none');
	if(open && !forceClosed){
		panel.slideDown(200);
		if(elem){elem.className = offCss;}
	} else{
		panel.slideUp(200);
		if(elem){elem.className = onCss;}
	}
	return open;
};

var formatCurrency = function(num, thou, dec, format){
	if(isNaN(num)){ return ""; }
	num = Math.floor(num * 100 + 0.50000000001);
	cents = num % 100;
	num = Math.floor(num / 100).toString();
	if(cents < 10){ cents = "0" + cents; }
	for(var i = 0; i < Math.floor((num.length - (1 + i)) / 3); i++){
		num = num.substring(0, num.length - (4 * i + 3)) + thou + num.substring(num.length - (4 * i + 3));
	}
	return format.replace('%1', num + dec + cents);
};

var formatCurrencyFromSettings = function(num){
	if(searchSettings.thousandSeparator && searchSettings.decimalSeparator && searchSettings.currencyFormat){
		return formatCurrency(num, searchSettings.thousandSeparator, searchSettings.decimalSeparator, searchSettings.currencyFormat);
	}
};

var templates = {
	addTemplate: function(id){
		var tpl = templateFromElement(id);
		if(tpl){ this[id] = tpl; }
		return tpl;
	},
	getTemplate: function(id){
		if(this[id]){ return this[id]; }
		else{ return this.addTemplate(id); }
	}
};

var lbox = {
	lboxID: 'lboxContent',
	lboxFadeID: 'lboxFade',
	showLightBox: function(popHtml, popWidth, modal){
		var lboxElem = $('#' + this.lboxID);
		if(lboxElem.length == 0){
			lboxElem = $('<div id="' + this.lboxID + '">' + popHtml + '</div>');
			$('body').append(lboxElem);
		} else{ lboxElem.html(popHtml); }
		lboxElem.fadeIn().css({ 'width': Number(popWidth) }).prepend('<div class="pop_close" onclick="lbox.hideLightBox()"></div>');
		var popMargTop = (lboxElem.height() + 100) / 2;
		var popMargLeft = (lboxElem.width() + 80) / 2;
		lboxElem.css({ 'margin-top': -popMargTop, 'margin-left': -popMargLeft });
		var darkBox = '<div id="' + this.lboxFadeID + '" ' + (!modal ? 'onclick="lbox.hideLightBox()"' : '') + '></div>';
		$('body').append(darkBox);
		$('#' + this.lboxFadeID).css({ 'filter': 'alpha(opacity=50)' }).fadeIn();
		this.setIE6DropdownVisibility("hidden");
		$(document).bind('keypress', lbox.checkForESC);
		return false;
	},
	hideLightBox: function(){
		var lboxIDs = '#' + this.lboxFadeID + ', #' + this.lboxID;
		$(lboxIDs).fadeOut(function(){ $(lboxIDs).remove(); });
		this.setIE6DropdownVisibility("visible");
		$(document).unbind('keypress', lbox.checkForESC);
		hashVal = null;
		return false;
	},
	clearLightBox: function(){
		var lboxIDs = '#' + this.lboxFadeID + ', #' + this.lboxID;
		$(lboxIDs).remove();
		this.setIE6DropdownVisibility("visible");
		$(document).unbind('keypress', lbox.checkForESC);
		return false;
	},
	checkForESC: function(e){
		if(e.keyCode == 27){ lbox.hideLightBox(); }
	},
	setIE6DropdownVisibility: function(val){
		if($.browser.msie && $.browser.version <= 6){
			var selects = document.getElementsByTagName("SELECT");
			for(var i = 0, len = selects.length; i < len; i++){
				selects[i].style.visibility = val;
			}
		}
	}
};

Array.prototype.insert = function(pos, newValue){
	if(pos > -1 && pos < this.length){ this.splice(pos, 0, newValue); }
	else{this.push(newValue);}
};
Array.prototype.removeWhere = function(propName, val, fullArray){
	for(var i = this.length; i--;){
		if(this[i][propName] == val){
			this.splice(i, 1);
			if(!fullArray){ break; }
		}
	}
};
Array.prototype.duffArray = function(obj, func){
	var len = this.length;
	var iterations = Math.floor(len / 8);
	var leftover = len % 8;
	var i = 0;

	if(leftover > 0){
		do{
			obj[func](this[i++]);
		} while (--leftover > 0);
	}

	if(iterations > 0){
		do{
			obj[func](this[i++]);
			obj[func](this[i++]);
			obj[func](this[i++]);
			obj[func](this[i++]);
			obj[func](this[i++]);
			obj[func](this[i++]);
			obj[func](this[i++]);
			obj[func](this[i++]);
		} while (--iterations > 0);
	}
};
Array.prototype.binarySearch = function(item, sorter){
	sorter = (typeof(sorter) == 'function' ?{comparer:sorter} : sorter);
	var hi = this.length, lo = -1, mid;
	while(hi - lo > 1){
		if(sorter.comparer(this[mid = hi + lo >> 1],item) < 0){ lo = mid; }
		else{ hi = mid; }
	}
	return hi;
};
Array.prototype.binaryInsert = function(item, sorter){
	var index = this.binarySearch(item, sorter);
	this.insert(index, item);
	return index;
};
if(!Array.indexOf){
	Array.prototype.indexOf = function(obj){
		for(var i = 0, len = this.length; i < len; i++){
			if(this[i] == obj){ return i; }
		}
		return -1;
	};
}

Date.constructor.prototype.parseDate = function(dateString, format){
	if(!dateString || dateString.length == 0){ return null; }
	if(!format || format.length == 0){ format = 'dd/MM/yyyy hh:mm'; }
	var regxSplit = /[\/|\-| |\:|\.|\,]/g;
	var day = 1, month = 1, year = 1, hour = 0, minute = 0;
	var dateParts = dateString.split(regxSplit);
	var fmtParts = format.split(regxSplit);
	var dateLen = dateParts.length;
	var fmtLen = fmtParts.length;
	for(var i = 0; i < fmtLen && i < dateLen; i++){
		switch(fmtParts[i]){
			case 'd':
			case 'dd':
				day = parseInt(dateParts[i], 10); break;
			case 'M':
			case 'MM':
				month = parseInt(dateParts[i], 10) - 1; break;
			case 'yyyy':
			case 'yy':
				year = parseInt(dateParts[i], 10); break;
			case 'h':
			case 'hh':
				hour = parseInt(dateParts[i], 10); break;
			case 'mm':
				minute = parseInt(dateParts[i], 10); break;
		}
	}
	return new Date(year, month, day, hour, minute, 0);
};

Date.prototype.compareDate = function(dateTime){
	return (this.getDate() == dateTime.getDate() && this.getMonth() == dateTime.getMonth() && this.getYear() == dateTime.getYear());
};

Date.prototype.subtractTime = function(dateTime){
	var timeSpan = this.getTime() - dateTime.getTime();
	var d = (timeSpan < 0 ? 0 : Math.floor(timeSpan/86400000));
	var h = (timeSpan < 0 ? 0 : Math.floor((timeSpan-(d*86400000))/3600000));
	var m = (timeSpan < 0 ? 0 : Math.floor((timeSpan-((d*86400000)+(h*3600000)))/60000));
	return{days:d,hours:h,minutes:m,span:timeSpan};
};

var DayNames = [TXT_SUNDAY,TXT_MONDAY,TXT_TUESDAY,TXT_WEDNESDAY,TXT_THURSDAY,TXT_FRIDAY,TXT_SATURDAY];
var DayAbbr = [TXT_SUN,TXT_MON,TXT_TUE,TXT_WED,TXT_THU,TXT_FRI,TXT_SAT];
var MonthNames = [TXT_JANUARY,TXT_FEBRUARY,TXT_MARCH,TXT_APRIL,TXT_MAY,TXT_JUNE,TXT_JULY,TXT_AUGUST,TXT_SEPTEMBER,TXT_OCTOBER,TXT_NOVEMBER,TXT_DECEMBER];
var MonthAbbr = [TXT_JAN,TXT_FEB,TXT_MAR,TXT_APR,TXT_MAY_SHORT,TXT_JUN,TXT_JUL,TXT_AUG,TXT_SEP,TXT_OCT,TXT_NOV,TXT_DEC];

Date.prototype.formatString = function(format){
	var regxSplit = /[\/|\-| |\:|\.|\,]/g;
	var parts = format.split(regxSplit);
	for(var i = 0, len = parts.length; i < len; i++){
		if(parts[i] == null || parts[i].length == 0){ continue; }
		var part = parts[i];
		var val = null;
		if(part == 'd' || part == 'dd'){
			var day = this.getDate();
			val = (part == 'dd' && day < 10 ? '0' + day : day);
		}
		else if(part == 'ddd' || part == 'dddd'){
			val = (part == 'ddd' ? DayAbbr[this.getDay()] : DayNames[this.getDay()]);
		}
		else if(part == 'M' || part == 'MM'){
			var month = this.getMonth() + 1;
			val = (part == 'MM' && month < 10 ? '0' + month : month);
		}
		else if(part == 'MMM' || part == 'MMMM'){
			val = (part == 'MMM' ? MonthAbbr[this.getMonth()] : MonthNames[this.getMonth()]);
		}
		else if(part == 'yy' || part == 'yyyy'){
			val = this.getFullYear();
		}
		else if(part == 'h' || part == 'hh'){
			var hour = this.getHours();
			val = (part == 'hh' && hour < 10 ? '0' + hour : hour);
		}
		else if(part == 'mm'){
			var minute = this.getMinutes();
			val = (minute < 10 ? '0' + minute : minute);
		}
		if(val){ format = format.replace(part, val); }
	}
	return format;
};

var sortManager = $.Class.create({
	sorters:null,
	field:null,
	comparer:null,
	asc:true,
	imgAsc:'sortAsc',
	imgDesc:'sortDesc',
	init: function(sorters){
		this.field = 'value';
		this.comparer = this.compareValue;
		this.sorters = sorters;
	},
	renderSorter: function(sorters){
		var elements = (sorters ? sorters : this.sorters);
		for(var prop in elements){
			if(elements[prop]){
				var elem = getElement(elements[prop]);
				if(elem){
					if(this.field != prop){ elem.className = ''; }
					else{ elem.className = (this.asc ? this.imgAsc : this.imgDesc); }
				}
			}
		}
	},
	doSort: function(field, mgr, sorters){
		if(!mgr){ return; }
		if(this.field == field){ this.asc = !this.asc; }
		else{ this.field = field; this.asc = true; }
		this.renderSorter(sorters);
		this.comparer = this.getComparer(field);
		this.sort(mgr);
	},
	sort: function(mgr){
		if(this.comparer){
			var sorter = this;
			if(mgr.isGroup){
				for(var i = mgr.unfiltered.length; i--;){
					var group = mgr.unfiltered[i];
					if(group.flights.length > 1){
						group.filtered.sort(function(a,b){ return sorter.comparer(a,b); });
					}
				}
				if(mgr.filtered){
					mgr.filtered.sort(function(a,b){ return sorter.comparer(a,b); });
				}
			}
			else{
				if(mgr.flights){
					mgr.flights.sort(function(a,b){ return sorter.comparer(a,b); });
				}
				if(mgr.filteredResults){
					mgr.filteredResults.sort(function(a,b){ return sorter.comparer(a,b); });
				}
			}
		}
	},
	compare: function(a,b,equal){
		var equalVal = (equal ? equal : 0);
		var x = (this.asc ? a : b);
		var y = (this.asc ? b : a);
		return ((x < y) ? -1 : ((x > y) ? 1 : equalVal));
	},
	compareValue: function(a,b){
		var x = (a.isGroup ? a.filtered[0] : a);
		var y = (b.isGroup ? b.filtered[0] : b);
		var equal = (x.cpc < y.cpc ? 1 : (x.cpc > y.cpc ? -1 : 0));
		return this.compare(x.value, y.value, equal);
	},
	compareAirline: function(a,b){
		var x = (a.isGroup ? a.filtered[0] : a);
		var y = (b.isGroup ? b.filtered[0] : b);
		var equal = 0;
		if(x.inbound && x.inbound.airline && y.inbound && y.inbound.airline){ equal = this.compare(x.inbound.airline.toLowerCase(), y.inbound.airline.toLowerCase(), 0); }
		if(equal == 0){ equal = ((x.value < y.value) ? -1 : ((x.value > y.value) ? 1 : 0)); }
		if(x.outbound && x.outbound.airline && y.outbound && y.outbound.airline){ return this.compare(x.outbound.airline.toLowerCase(), y.outbound.airline.toLowerCase(), equal); }
		else{ return this.compare(x.airline.toLowerCase(), y.airline.toLowerCase()); }
	},
	compareDepart: function(a,b){
		var x = (a.isGroup ? a.filtered[0] : a);
		var y = (b.isGroup ? b.filtered[0] : b);
		var equal = ((x.value < y.value) ? -1 : ((x.value > y.value) ? 1 : 0));
		return this.compare(x.outbound.time, y.outbound.time, (x.inbound && y.inbound ? this.compare(x.inbound.time, y.inbound.time, equal) : equal));
	},
	compareArrive: function(a,b){
		var x = (a.isGroup ? a.filtered[0] : a);
		var y = (b.isGroup ? b.filtered[0] : b);
		var equal = ((x.value < y.value) ? -1 : ((x.value > y.value) ? 1 : 0));
		return this.compare(x.outbound.arrive, y.outbound.arrive, (x.inbound && y.inbound ? this.compare(x.inbound.arrive, y.inbound.arrive, equal) : equal));
	},
	compareStops: function(a,b){
		var x = (a.isGroup ? a.filtered[0] : a);
		var y = (b.isGroup ? b.filtered[0] : b);
		var equal = 0;
		if(x.inbound && x.inbound.stops && y.inbound && y.inbound.stops){ equal = this.compare(x.inbound.stops, y.inbound.stops, 0); }
		if(equal == 0){ equal = ((x.value < y.value) ? -1 : ((x.value > y.value) ? 1 : 0)); }
		return (x.outbound.stops && y.outbound.stops ? this.compare(x.outbound.stops, y.outbound.stops, equal) : equal);
	},
	compareOperator: function(a,b){
		var x = (a.isGroup ? a.filtered[0] : a);
		var y = (b.isGroup ? b.filtered[0] : b);
		var equal = ((x.value < y.value) ? -1 : ((x.value > y.value) ? 1 : 0));
		return this.compare(x.operator.name.toLowerCase(), y.operator.name.toLowerCase(), equal);
	},
	compareDuration: function(a,b){
		var x = (a.isGroup ? a.filtered[0] : a).totalDuration;
		var y = (b.isGroup ? b.filtered[0] : b).totalDuration;
		if(x == null){ return 1; }
		else if(y == null){ return -1; }
		else{ return this.compare(x, y, 0); }
	},
	getComparer: function(x){
		switch(x){
			case 'value':
				return this.compareValue;
			case 'airline':
				return this.compareAirline;
			case 'depart':
				return this.compareDepart;
			case 'arrive':
				return this.compareArrive;
			case 'stops':
				return this.compareStops;
			case 'operator':
				return this.compareOperator;
			case 'duration':
				return this.compareDuration;
			default:
				return this.compareValue;
		}
	}
});

var viewManager = $.Class.create({
	activeView: null,
	items: null,
	onResultsAdded: null,
	init: function(o){
		this.items = {};
	},
	addView: function(view, active){
		if(view && view.id){
			this.items[view.id] = view;
			if(active){
				this.activeView = view;
				this.activeView.setVisibility(true);
			}
		}
	},
	getView: function(viewId){
		if(this.items[viewId]){
			return this.items[viewId];
		}
	},
	showView: function(viewId, redraw){
		if(viewId){
			if(redraw || this.activeView != this.getView(viewId)){
				if(this.activeView){ this.activeView.hideView(); }
			}
			this.activeView = this.getView(viewId);
			if(this.activeView){ this.activeView.showView(); }
		}
	},
	addResults: function(viewId, result, inbound){
		var view = this.getView(viewId);
		if(view && result){
			view.addResults(result, inbound);
			if(this.onResultsAdded){ this.onResultsAdded(result); }
			if(this.activeView && this.activeView.id == view.id){ this.activeView.refresh(add_timeout); }
		}
	},
	updateResults: function(viewId, result, inbound){
		var view = this.getView(viewId);
		if(view && result){ view.updateResults(result, inbound); }
	},
	redraw: function(){
		if(this.activeView && this.activeView.redraw){
			this.activeView.redraw();
		}
	},
	refresh: function(){
		if(this.activeView){
			this.activeView.refresh();
			this.activeView.refreshSliders();
		}
	},
	update: function(){
		if(this.activeView){ this.activeView.update(); }
	},
	refreshSliders: function(){
		if(this.activeView){ this.activeView.refreshSliders(); }
	},
	sort: function(field, inbound){
		pageManager.showLoadingScreen(true);
		var mgr = this;
		if(this.activeView){
			setTimeout(function(){
				var view = mgr.activeView;
				view.sort(field, inbound, true);
				pageManager.showLoadingScreen(false);
				mgr = null;
			}, 250);
		}
	},
	timesChanged: function(id, hnd, val){
		if(id[0] != '#'){ id = '#' + id; }
		if(this.activeView){
			this.activeView.timesChanged(id, hnd, val);
			this.activeView.refresh();
		}
	},
	changeSlider: function(type, id, hnd, val){
		if(id[0] != '#'){ id = '#' + id; }
		if(this.activeView){
			this.activeView.changeSlider(type, id, hnd, val);
			this.activeView.refresh();
		}
	},
	setFilter: function(type, id, checked, inbound, redraw, suppressUpdate){
		if(this.activeView){ this.activeView.setFilter(type, id, checked, inbound, redraw, suppressUpdate); }
	},
	setPageNumber: function(num, inbound){
		if(this.activeView){ this.activeView.setPageNumber(num, inbound); }
	},
	setPageSize: function(size, inbound){
		if(this.activeView){ this.activeView.setPageSize(parseInt(size, 10), inbound); }
	},
	getResultsCount: function(viewId){
		var view = this.getView(viewId);
		if(view && view.outboundMgr){
			return view.outboundMgr.flights.length;
		}
		return 0;
	},
	attachEvents: function(o){
		if(o.onResultsAdded){ this.onResultsAdded = o.onResultsAdded; }
	},
	toggleFilter: function(inbound){
		if(this.activeView){ return this.activeView.toggleFilter(inbound); }
	},
	showFullDetails: function(id, inbound){
		if(this.activeView){ this.activeView.showFullDetails(id, inbound); }
	},
	emailOffer: function(id, inbound){
		if(this.activeView){ this.activeView.emailOffer(id, inbound); }
	},
	showMultiBook: function(id, inbound){
		if(this.activeView){ this.activeView.showMultiBook(id, inbound); }
		return false;
	},
	setSelectedOption: function(id, opt, inbound, isOutLeg){
		if(this.activeView){ this.activeView.setSelectedOption(id, opt, inbound, isOutLeg); }
	},
	openOptions: function(id, inbound){
		if(this.activeView){ this.activeView.openOptions(id, inbound); }
	}
});

var pageView = $.Class.create({
	id: null,
	panels: null,
	tab: null,
	outboundMgr: null,
	inboundMgr: null,
	sorters:{},
	onflightsadded: null,
	onshow: null,
	onafterrender: null,
	properties:{},
	renderOverride: null,
	onFilter: null,
	isGrouped: false,
	firstView: true,
	init: function(o){
		this.id = o.id;
		this.panels = o.panels;
		this.tab = o.tab;
		if(o.isGrouped){ this.isGrouped = o.isGrouped; }
		if(o.outboundMgr && !this.outboundMgr){ this.outboundMgr = new flightsManager(o.outboundMgr, this); }
		if(o.inboundMgr && !this.inboundMgr){ this.inboundMgr = new flightsManager(o.inboundMgr, this, true); }
		if(o.properties){ this.properties = o.properties; }
		if(o.onflightsadded){ this.onflightsadded = o.onflightsadded; }
		if(o.onshow){ this.onshow = o.onshow; }
		if(o.onafterrender){ this.onafterrender = o.onafterrender; }
		if(o.renderOverride){ this.renderOverride = o.renderOverride; }
		if(o.onfilter){ this.onFilter = o.onfilter; }
		if(o.sorters){
			this.sorters = o.sorters;
			if(this.outboundMgr && o.sorters.outbound){ this.outboundMgr.setSorters(o.sorters.outbound); }
			if(this.inboundMgr && o.sorters.inbound){ this.inboundMgr.setSorters(o.sorters.inbound); }
		}
	},
	showView: function(norefresh){
		this.setVisibility(true);
		if(this.outboundMgr){
			this.outboundMgr.view = this;
			this.outboundMgr.renderOverride = this.renderOverride;
			if(this.outboundMgr.sorter){
				var sorters = (this.sorters ? this.sorters.outbound : null);
				this.outboundMgr.sorter.renderSorter(sorters);
			}
			if(this.outboundMgr.resultsElement){ this.outboundMgr.setResultsHtml('<div class="ResultDiv">&nbsp;</div>'); }
			this.outboundMgr.showFilter();
			this.outboundMgr.setPageSizeSelect();
		}
		if(this.inboundMgr){
			this.inboundMgr.view = this;
			this.inboundMgr.renderOverride = this.renderOverride;
			if(this.inboundMgr.sorter){
				var sorters = (this.sorters ? this.sorters.inbound : null);
				this.inboundMgr.sorter.renderSorter(sorters);
			}
			if(this.inboundMgr.resultsElement){ this.inboundMgr.setResultsHtml('<div class="ResultDiv">&nbsp;</div>'); }
			this.inboundMgr.showFilter();
			this.inboundMgr.setPageSizeSelect();
		}
		if(this.tab){ $(this.tab).attr('class', 'selectedTab'); }
		$.each(this.panels, function(index, value){ $(value).css('display', ''); });
		this.refreshSliders();
		if(!norefresh){ this.refresh(); }
		if(this.onshow){ this.onshow(this); }
		this.firstView = false;
	},
	hideView: function(){
		this.setVisibility(false);
		if(this.tab){ $(this.tab).attr('class', 'unselectedTab'); }
		$.each(this.panels, function(index, value){ $(value).css('display', 'none'); });
	},
	setVisibility: function(visible){
		if(this.outboundMgr){ this.outboundMgr.visible = visible; }
		if(this.inboundMgr){ this.inboundMgr.visible = visible; }
	},
	addResults: function(result, inbound){
		if(!inbound && this.outboundMgr){
			this.outboundMgr.addResults(result);
			this.outboundMgr.refreshSliders();
		}
		else if(inbound && this.inboundMgr){
			this.inboundMgr.addResults(result);
			this.inboundMgr.refreshSliders();
		}
		if(this.onflightsadded){ this.onflightsadded(this); }
		if(this.tab){ $(this.tab).css('display', ''); }
	},
	updateResults: function(result, inbound){
		if(!inbound && this.outboundMgr){ this.outboundMgr.updateResults(result); }
		else if(inbound && this.inboundMgr){ this.inboundMgr.updateResults(result); }
	},
	refreshSliders: function(){
		if(this.outboundMgr){ this.outboundMgr.refreshSliders(); }
		if(this.inboundMgr){ this.inboundMgr.refreshSliders(); }
	},
	timesChanged: function(id, hnd, val){
		if(this.outboundMgr){ this.outboundMgr.timesChanged(id, hnd, val); }
		if(this.inboundMgr){ this.inboundMgr.timesChanged(id, hnd, val); }
	},
	changeSlider: function(type, id, hnd, val){
		if(this.outboundMgr){ this.outboundMgr.changeSlider(type, id, hnd, val); }
		if(this.inboundMgr){ this.inboundMgr.changeSlider(type, id, hnd, val); }
	},
	sort: function(field, inbound, render){
		if(!inbound && this.outboundMgr){
			var sorters = (this.sorters ? this.sorters.outbound : null);
			this.outboundMgr.sort(field, render, sorters);
		}
		else if(this.inboundMgr){
			var sorters = (this.sorters ? this.sorters.inbound : null);
			this.inboundMgr.sort(field, render, sorters);
		}
	},
	redraw: function(){
		if(this.outboundMgr){ this.outboundMgr.refresh(); }
		if(this.inboundMgr){ this.inboundMgr.refresh(); }
	},
	refresh: function(timeout){
		if(this.outboundMgr){ this.outboundMgr.startRender(timeout); }
		if(this.inboundMgr){ this.inboundMgr.startRender(timeout); }
	},
	update: function(){
		if(this.outboundMgr){ this.outboundMgr.update(); }
		if(this.inboundMgr){ this.inboundMgr.update(); }
	},
	setFilter: function(type, id, checked, inbound, redraw, suppressUpdate){
		if(!inbound && this.outboundMgr){ this.outboundMgr.setFilter(type, id, checked, redraw, suppressUpdate); }
		else if(this.inboundMgr){ this.inboundMgr.setFilter(type, id, checked, redraw, suppressUpdate); }
	},
	setPageNumber: function(num, inbound){
		if(!inbound && this.outboundMgr){
			this.outboundMgr.setPageNumber(num);
			window.scrollTo(0, 0);
			this.outboundMgr.startRender();
		}
		else if(this.inboundMgr){
			this.inboundMgr.setPageNumber(num);
			window.scrollTo(0, 0);
			this.inboundMgr.startRender();
		}
	},
	setPageSize: function(size, inbound){
		if(!inbound && this.outboundMgr){
			this.outboundMgr.setPageSize(size);
			window.scrollTo(0, 0);
			this.outboundMgr.startRender();
		}
		else if(this.inboundMgr){
			this.inboundMgr.setPageSize(size);
			window.scrollTo(0, 0);
			this.inboundMgr.startRender();
		}
	},
	hasFlights: function(){
		if(this.outboundMgr && this.outboundMgr.flights.length > 0){ return true; }
		else if(this.inboundMgr && this.inboundMgr.flights.length > 0){ return true; }
		else{ return false; }
	},
	getCheapestItem: function(){
		var cheapestItem = null;
		if(this.outboundMgr && this.outboundMgr.cheapestItem){
			cheapestItem = this.outboundMgr.cheapestItem;
		}
		if(this.inboundMgr && this.inboundMgr.cheapestItem){
			if(cheapestItem == null || this.inboundMgr.cheapestItem.value < cheapestItem.value){
				cheapestItem = this.inboundMgr.cheapestItem;
			}
		}
		return cheapestItem;
	},
	toggleFilter: function(inbound){
		if(!inbound && this.outboundMgr){ return this.outboundMgr.toggleFilter(); }
		else if(this.inboundMgr){ return this.inboundMgr.toggleFilter(); }
	},
	showFullDetails: function(id, inbound){
		if(!inbound && this.outboundMgr){ return this.outboundMgr.showFullDetails(id); }
		else if(this.inboundMgr){ return this.inboundMgr.showFullDetails(id); }
	},
	emailOffer: function(id, inbound){
		if(!inbound && this.outboundMgr){ return this.outboundMgr.emailOffer(id); }
		else if(this.inboundMgr){ return this.inboundMgr.emailOffer(id); }
	},
	showMultiBook: function(id, inbound){
		if(!inbound && this.outboundMgr){ return this.outboundMgr.showMultiBook(id); }
		else if(this.inboundMgr){ return this.outboundMgr.showMultiBook(id); }
	},
	setSelectedOption: function(id, opt, inbound, isOutLeg){
		if(!inbound && this.outboundMgr){ return this.outboundMgr.setSelectedOption(id, opt, isOutLeg); }
		else if(this.inboundMgr){ return this.inboundMgr.setSelectedOption(id, opt, isOutLeg); }
	},
	openOptions: function(id, inbound){
		if(!inbound && this.outboundMgr){ return this.outboundMgr.openOptions(id); }
		else if(this.inboundMgr){ return this.inboundMgr.openOptions(id); }
	}
});

var mapPageView = pageView.extend({
	useView: null,
	map: null,
	accessor: null,
	isDeparture: false,
	iata: null,
	onEndpointChanged: null,
	init: function (o) {
		this._super(o);
		if (o.useView) {
			this.useView = o.useView;
			this.outboundMgr = this.useView.outboundMgr;
			this.inboundMgr = this.useView.inboundMgr;
		}
		if (o.map) { this.map = o.map; }
		if (o.accessor) { this.accessor = o.accessor; }
		if (o.onEndpointChanged) { this.onEndpointChanged = o.onEndpointChanged; }
	},
	showView: function () {
		this.iata = null;
		this._super();
	},
	showDepartures: function () {
		this.isDeparture = true;
		this.iata = null;
		this.map.renderBoundsGroup('dep');
		if (this.onEndpointChanged) { this.onEndpointChanged(this, false); }
		viewMgr.showView(this.id, true);
	},
	showDestinations: function () {
		this.isDeparture = false;
		this.iata = null;
		if (this.onEndpointChanged) { this.onEndpointChanged(this, false); }
		this.map.renderBoundsGroup('dest');
		viewMgr.showView(this.id, true);
	},
	showAirport: function (iata, isDep) {
		if (this.iata != iata) {
			this.iata = iata;
			this.isDeparture = isDep;
			if (this.onEndpointChanged) { this.onEndpointChanged(this, false); }
		}
		if (this.outboundMgr) { this.outboundMgr.setPageNumber(1); }
		if (this.inboundMgr) { this.inboundMgr.setPageNumber(1); }
		this.refresh();
	},
	onFilter: function (inbound) {
		this.updateMarkers(inbound);
	},
	updateMarkers: function (inbound) {
		if (!this.map) { return; }
		if (!inbound && this.outboundMgr) {
			this.createMarkers(this.outboundMgr);
		}
		else if (this.inboundMgr) {
			this.createMarkers(this.inboundMgr);
		}
	},
	createMarkers: function (mgr) {
		if (!this.map) { return; }
		if (mgr && mgr.render) {
			this.addMarkers(mgr, 'dep');
			this.addMarkers(mgr, 'dest');
		}
	},
	addMarkers: function (mgr, group) {
		var arr = mgr.getAirports(group);
		this.map.clearGroup(group);
		for (var i = arr.length; i--; ) {
			var marker = arr[i];
			var code = marker.item.id;
			var apt = mgr.getAirport(code);
			var dataItem = (searchSettings.mapOverallCheapest ? marker.item.cheapestOverall : marker.item.mapItem);
			if (dataItem) {
				var isVisible = (searchSettings.mapOverallCheapest ? true : marker.item.check());
				var pin = (dataItem ? mgr.render.getPinImage(apt.type) : null);
				var shadow = mgr.render.getShadowImage();
				var itemTitle = mgr.getAptName(code) + (dataItem ? ' - ' + dataItem.price : '');
				this.map.updateMarkers({
					id: code, img: (pin ? pin.icon : null), width: (pin ? pin.width : 0),
					height: (pin ? pin.height : 0), lat: apt.lat, lon: apt.lon,
					html: this.getMapHtml(dataItem, mgr, marker.isDep),
					title: itemTitle, visible: isVisible, shadow: shadow, boundsGroup: group
				});
			}
			else { this.map.deleteMarker(code); }
		}
	},
	getMapHtml: function (item, mgr, isDep) {
		var html = '<div class="mapResult">';
		if (item && mgr && mgr.render) {
			var render = mgr.render;
			var iata = (isDep ? item.dep : item.dest);
			var txt = TXT_FROM_TO;
			txt = txt.replace('%1', mgr.getAptName(item.dep));
			txt = txt.replace('%2', mgr.getAptName(item.dest));
			html += '<div class="mapText">' + txt + '</div>';
			html += render.getShortHtml(item, mgr);
			html += '<div style="padding-top:4px;">';
			html += '<a class="blueText" href="' + render.getRedirect(item) + '" target="_blank">';
			html += TXT_VERIFY_AVAILABILITY;
			html += '</a></div>';
			html += '<div style="padding-top:4px;">';
			html += '<a class="GreenLink" onclick="' + this.accessor + '.showAirport(\'' + iata + '\',' + isDep + ')">';
			html += (isDep ? TXT_MORE_FLIGHTS_FROM : TXT_MORE_FLIGHTS_TO);
			html += '</a></div>';
		}
		html += '</div>';
		return html;
	}
});

var flexiblePageView = pageView.extend({
	init: function(o){
		if(o.outboundMgr){ this.outboundMgr = new flexiFlightsManager(o.outboundMgr, this); o.outboundMgr = null; }
		if(o.inboundMgr){ this.inboundMgr = new flexiFlightsManager(o.inboundMgr, this, true); o.inboundMgr = null; }
		this._super(o);
	},
	showView: function(){
		var norefresh = false;
		this.setVisibility(true);
		if(this.outboundMgr && this.outboundMgr.flights.length == 0){
			this.outboundMgr.loadResults();
			norefresh = true;
		}
		if(this.inboundMgr && this.inboundMgr.flights.length == 0){
			this.inboundMgr.loadResults();
			norefresh = true;
		}
		this._super(norefresh);
	}
});

var renderer = $.Class.create({
	getTax: function (val) {
		var taxHtml = '';
		var strCss = 'txtOrange';
		if (!val) { taxHtml = TXT_TAX_EXCLUDED; }
		else if (val == '0') { taxHtml = TXT_TAX_EXCLUDED; }
		else if (val == '1') { taxHtml = TXT_PLUS_CARD_FEES; strCss = (ccFeesIsTotal ? 'txtGreen' : strCss); }
		else if (val == '2') { taxHtml = TXT_EXCLUDING_TICKET_EMISSION; }
		else if (val == '3') { taxHtml = TXT_APPROX_PRICE; }
		else { taxHtml = TXT_FINAL_PRICE; strCss = 'txtGreen'; }

		if (taxHtml != '') { taxHtml = '<span class="' + strCss + '">' + taxHtml + '</span>'; }
		return taxHtml;
	},
	getDateTime: function (leg, isArrival) {
		var time = (isArrival ? leg.arrive : leg.time);
		var date = (isArrival ? leg.dateArriveValue : leg.dateValue);
		var dateString = '';
		if (date) { dateString = date.formatString('d MMM yyyy') + ', '; }
		return dateString + time;
	},
	getRedirect: function (item) {
		if (item.opid != searchSettings.combinationsOpid) {
			var outIATA = (item.operator.dep ? item.operator.dep : item.dep);
			var inIATA = (item.operator.dest ? item.operator.dest : item.dest);
			var outDate = (item.outbound ? item.outbound.date : '');
			var inDate = (item.inbound ? item.inbound.date : '');
			return this.getBookUrl(item.opid, outIATA, inIATA, outDate, inDate, item.url);
		}
		else { return "#"; }
	},
	getRedirectOnClick: function (item, mgr) {
		if (item.opid == searchSettings.combinationsOpid) {
			return "viewMgr.showMultiBook('" + item.uniqueId + "'," + (mgr.inbound ? "true" : "false") + ");";
		}
		else { return ""; }
	},
	getRedirectTarget: function (item) {
		if (item.opid != searchSettings.combinationsOpid) { return "_blank"; }
		else { return "_self"; }
	},
	getBookUrl: function (opid, outIATA, inIATA, outDate, inDate, bookUrl) {
		var url = REDIRECT_PATH;
		url += '?opid=' + opid;
		url += '&DepartAirport=' + outIATA;
		url += '&DestinationAirport=' + inIATA;
		url += '&Adults=' + searchSettings.adults;
		url += '&Children=' + searchSettings.children;
		url += '&Infants=' + searchSettings.infants;
		url += '&DepartureDate=' + (outDate ? encodeURIComponent(outDate) : '');
		url += '&ReturnDate=' + (inDate ? encodeURIComponent(inDate) : '');
		if (searchSettings.flightClass != "Economy") { url += '&BusinessClass=true'; }
		url += '&url=' + (bookUrl ? encodeURIComponent(bookUrl) : '');
		return url;
	},
	getLastUpdated: function (item) {
		var html = ''; var style;
		try {
			if (item.tax == 3) {
				style = 'background:url(' + IMG_ROOT + 'i/warning.gif) no-repeat left center;height:16px;line-height:16px;padding:0 0 0 16px;white-space:nowrap;';
				html = '<div style="' + style + '">' + TXT_TO_BE_VERIFIED + '</div>';
			}
			else if (item.updated != null && server_time != null) {
				var timeSpan = server_time.subtractTime(item.updated);
				var updatedText = TXT_LAST_UPDATED + ': ';
				var updatedImg = (searchSettings.icons && searchSettings.icons.clock ? searchSettings.icons.clock : IMG_ROOT + 'i/clock3.gif');

				if (timeSpan.days > 0) { updatedText += '<span class="updatedText">' + TXT_DAYS_AGO.replace('%1', timeSpan.days) + '</span>'; }
				else if (timeSpan.hours > 0) { updatedText += '<span class="updatedText">' + TXT_HOURS_AGO.replace('%1', timeSpan.hours) + '</span>'; }
				else if (timeSpan.minutes > 0) { updatedText += '<span class="updatedText">' + TXT_MINS_AGO.replace('%1', timeSpan.minutes) + '</span>'; }
				else { updatedText = TXT_VERIFIED_AVAILABILITY; updatedImg = IMG_ROOT + 'i/tick-green.gif'; }

				style = 'background:url(' + updatedImg + ') no-repeat left center;height:16px;line-height:16px;padding:3px 0 2px 17px;white-space:nowrap;';
				html = '<div style="' + style + '">' + updatedText + '</div>';
			}
			else {
				style = 'background:url(' + IMG_ROOT + 'i/tick-green.gif) no-repeat left center;height:16px;line-height:16px;padding:3px 0 2px 17px;white-space:nowrap;';
				html = '<div style="' + style + '">' + TXT_VERIFIED_AVAILABILITY + '</div>';
			}
		} catch (ex) { }
		return html;
	},
	getConvertedInfo: function (item) {
		var html = '';
		if (item.opprice && item.opcurrency) {
			var txt = TXT_CONVERTED_FROM.replace('%1', item.opcurrency).replace('%2', '<b>' + item.opprice + ' ' + item.opcurrency + '</b>');
			html = '<img src="' + IMG_ROOT + 'i/asterix.gif" width=12 height=11> ' + txt;
			if (TXT_CONVERTED_INFO && TXT_CONVERTED_INFO.length > 0) {
				html += '&nbsp;&nbsp;<img src="' + IMG_ROOT + 'i/info4.gif" width=11 height=11 onclick="showInfoBalloon(this,event,\'<b>' + item.opcurrency + '</b>\')">';
			}
		}
		return html;
	},
	getOriginalPrice: function (item) {
		if (item.opprice) { return '<span class="origPrice">' + item.opprice + '</span>'; }
		return '';
	},
	formatDate: function (dt, format) {
		var dateString = '';
		if (dt) {
			var dateFormat = (format ? format : 'd MMM');
			dateString = Date.parseDate(dt).formatString(dateFormat);
		}
		return dateString;
	},
	getDate: function (item, format) {
		var html = '';
		if (item && item.outbound) {
			var dep = this.formatDate(item.outbound.date, format);
			var ret = (item.inbound ? this.formatDate(item.inbound.date, format) : null);
			html = dep + (ret ? ' - ' + ret : '');
		}
		return html;
	},
	getResultCounts: function (filteredCount, totalCount, operatorsCount) {
		var html = TXT_RESULTS;
		html = html.replace('%1', '<b>' + filteredCount + '</b>');
		html = html.replace('%2', '<b>' + totalCount + '</b>');
		html = html.replace('%3', '<b>' + operatorsCount + '</b>');
		return '<div class=FilterCounts>' + html + '</div>';
	},
	renderOperators: function (mgr, filter) {
		var ids = filter.ids;
		ids.sort(function (a, b) {
			var aName = mgr.getOperator(a).toLowerCase();
			var bName = mgr.getOperator(b).toLowerCase();
			return ((aName < bName) ? -1 : ((aName > bName) ? 1 : 0));
		});
		var html = '<table class="opFilter" width="100%">';
		var func = "viewMgr.setFilter('op',this.value,this.checked," + (mgr.inbound ? "true" : "false") + ")";
		for (var i = 0, len = ids.length; i < len; i++) {
			var id = ids[i];
			var item = filter.items[id];
			if (item && item.visible) {
				var redirect = (item.cheapestItem ? this.getRedirect(item.cheapestItem) : null);
				var labelcss = (item.cheapestItem || searchSettings.filterLabelOff ? 'opNameLabel' : 'filterLabelOff');
				var opName = mgr.getOperator(id);
				var opLink = (redirect ? '<a target="_blank" href="' + redirect + '">' + opName + '</a>' : '<a>' + opName + '</a>');
				html += '<tr><td width="22" valign="middle">' +
					'<input type="checkbox" class="styled" value="' + id + '" ' + (item.enabled ? 'checked' : '') + ' onclick="' + func + '"/>' +
					'</td><td valign="middle" class="' + labelcss + '">' + opLink +
					'</td><td valign="middle" align="right" nowrap>' + this.renderPriceLink(item.cheapestItem) + '</td></tr>';
			}
		}
		html += '</table>';
		filter.writeHtml(html);
	},
	renderAirports: function (mgr, filter, isDep) {
		if (!isDep && mgr.view.renderDestAirports) { return mgr.view.renderDestAirports(mgr, filter); }
		else {
			var depLocation = (!mgr.inbound ? searchSettings.dep : searchSettings.dest);
			var destLocation = (!mgr.inbound ? searchSettings.dest : searchSettings.dep);
			var lat = (isDep ? depLocation.lat : destLocation.lat);
			var lon = (isDep ? depLocation.lon : destLocation.lon);
			var ids = filter.ids;
			ids.sort(function (a, b) {
				var aptA = mgr.airports[a], aptB = mgr.airports[b];
				if (aptA == null || aptA.lat == null || aptB == null || aptB.lat == null) { return 0; }
				var aDist = mgr.getDistance(aptA.lat, aptA.lon, lat, lon);
				var bDist = mgr.getDistance(aptB.lat, aptB.lon, lat, lon);
				return ((aDist < bDist) ? -1 : ((aDist > bDist) ? 1 : 0));
			});
			var html = '<table class="aptFilter" width="100%">';
			var func = "viewMgr.setFilter('" + (isDep ? "dep" : "dest") + "',this.value,this.checked," + (mgr.inbound ? "true" : "false") + ")";
			for (var i = 0, len = ids.length; i < len; i++) {
				var id = ids[i];
				var item = filter.items[id];
				var apt = mgr.getAirport(id);
				if (item && item.visible && apt) {
					var dist = mgr.getDistance(apt.lat, apt.lon, lat, lon);
					var labelcss = (item.cheapestItem || searchSettings.filterLabelOff ? 'opNameLabel' : 'filterLabelOff');
					html += '<tr><td width="22" valign="middle">' +
						'<input type="checkbox" class="styled" value="' + id + '" ' + (item.enabled ? 'checked' : '') + ' onclick="' + func + '"/>' +
						'</td><td valign="middle" class="' + labelcss + '" title="' + mgr.getAptName(id) + '">' +
						this.getAirportHtml(mgr, apt, dist) + '</td></tr>';
				}
			}
			html += '</table>';
			filter.writeHtml(html);
		}
	},
	renderAirlines: function (mgr, filter) {
		var ids = filter.ids;
		ids.sort(function (a, b) {
			var aName = mgr.getAirlineFilterName(a).toLowerCase();
			var bName = mgr.getAirlineFilterName(b).toLowerCase();
			return ((aName < bName) ? -1 : ((aName > bName) ? 1 : 0));
		});
		var html = '<table class="opFilter" width="100%">';
		var func = "viewMgr.setFilter('airline',this.value,this.checked," + (mgr.inbound ? "true" : "false") + ")";
		for (var i = 0, len = ids.length; i < len; i++) {
			var id = ids[i];
			var item = filter.items[id];
			if (item && item.visible) {
				var labelcss = (item.cheapestItem || searchSettings.filterLabelOff ? 'opNameLabel' : 'filterLabelOff');
				var nameFunc = "viewMgr.setFilter('airline','" + id + "','toggle'," + (mgr.inbound ? "true" : "false") + ",true)";
				html += '<tr><td width="22" valign="middle">' +
					'<input type="checkbox" class="styled" value="' + id + '" ' + (item.enabled ? 'checked' : '') + ' onclick="' + func + '"/>' +
					'</td><td valign="middle" class="' + labelcss + '">' +
					'<a onclick="' + nameFunc + '">' + mgr.getAirlineFilterName(id) + '</a>' +
					'</td></tr>';
			}
		}
		html += '</table>';
		filter.writeHtml(html);
	},
	getAirportHtml: function (mgr, apt, dist) {
		if (apt.type == transport.TRAIN) { return mgr.getAptName(apt.code) + ' (' + TXT_TRAIN_ST + ')'; }
		else if (apt.type == transport.BUS) { return mgr.getAptName(apt.code) + ' (' + TXT_BUS_ST + ')'; }
		else if (apt.type == transport.FERRY) { return mgr.getAptName(apt.code) + ' (' + TXT_FERRY_ST + ')'; }
		else { return apt.city + ' (' + apt.code + ')' + (dist > 0 ? '<br/>' + dist + ' KM' : ''); }
	},
	getAirport: function (mgr, code) {
		var apt = mgr.getAirport(code);
		var txt = code;
		if (apt) {
			if (apt.type == transport.TRAIN) { txt = mgr.getAptName(apt.code); }
			else if (apt.type == transport.BUS) { txt = mgr.getAptName(apt.code); }
			else if (apt.type == transport.FERRY) { txt = mgr.getAptName(apt.code); }
			else { txt = code; }
		}
		return txt;
	},
	renderDates: function (mgr, filter) {
		var ids = filter.ids;
		ids.sort(function (a, b) { return ((a < b) ? -1 : ((a > b) ? 1 : 0)); });
		var html = '<table class="dateFilter" width="100%">';
		var func = "viewMgr.setFilter('date',this.value,this.checked," + (mgr.inbound ? "true" : "false") + ")";
		for (var i = 0, len = ids.length; i < len; i++) {
			var id = ids[i];
			var item = filter.items[id];
			if (item && item.visible) {
				var labelcss = (item.cheapestItem || searchSettings.filterLabelOff ? 'opNameLabel' : 'filterLabelOff');
				var priceCss = (filter.isCheapestElement(id) ? 'hilite' : null);
				html += '<tr><td width="22" valign="middle">' +
					'<input type="checkbox" class="styled" value="' + id + '" ' + (item.enabled ? 'checked' : '') + ' onclick="' + func + '"/>' +
					'</td><td valign="middle" class="' + labelcss + '">' +
					(item.properties.enabled ? '<b>' : '') + item.properties.dep.formatString('d MMM') +
					(item.properties.ret ? ' - ' + item.properties.ret.formatString('d MMM') : '') +
					(item.properties.enabled ? '</b>' : '') +
					'</td><td valign="middle" align="right" nowrap>' + this.renderPriceLink(item.cheapestItem, priceCss) + '</td></tr>';
			}
		}
		html += '</table>';
		filter.writeHtml(html);
	},
	renderPriceLink: function (item, spanCss) {
		var html = '';
		if (item) {
			var css = (spanCss == null ? '' : ' class="' + spanCss + '"');
			html = '<a target="_blank" href="' + this.getRedirect(item) + '"><span' + css + '>' + item.price + '</span></a>';
		}
		return html;
	},
	renderPaging: function (mgr, count) {
		if (mgr.pagingElement) {
			var elem = $(mgr.pagingElement);
			if (elem.get(0) == document) { return; }
			var filteredArray = mgr.getFilteredResults();
			var numResults = (count ? count : filteredArray.length);
			var html = '';
			var clickFunc = '';
			var pages = Math.ceil(numResults / mgr.pagesize);
			var minPage = Math.max(Math.min(mgr.page - 5, pages - 9), 1);
			for (var i = minPage; i <= minPage + 9 && i <= pages; i++) {
				if (mgr.page == i) {
					html += '<span class="ChangePageSelected"><b>' + i + '</b></span>';
				}
				else {
					var func = "viewMgr.setPageNumber(" + i + "," + (mgr.inbound ? "true" : "false") + ")";
					html += '<a class="ChangePage" onclick="' + func + '"><span>' + i + '</span></a>';
				}
			}

			var goBack = "";
			var goForward = "";
			if (searchSettings.pageNextPrev) {
				var dots = '<span class="PagingDots">....</span>';
				clickFunc = (mgr.page > 1 ? "viewMgr.setPageNumber(" + (mgr.page - 1) + "," + (mgr.inbound ? "true" : "false") + ")" : "");
				goBack = '<a class="ChangePagePrev" onclick="' + clickFunc + '">&nbsp;</a>';
				if (mgr.page > 6 && pages > 10) {
					clickFunc = "viewMgr.setPageNumber(1," + (mgr.inbound ? "true" : "false") + ")";
					goBack += '<a class="ChangePage" onclick="' + clickFunc + '"><span>1</span></a>' + (mgr.page > 7 ? dots : '');
				}

				if (mgr.page < pages - 4 && pages > 10) {
					clickFunc = "viewMgr.setPageNumber(" + pages + "," + (mgr.inbound ? "true" : "false") + ")";
					goForward = (mgr.page < pages - 5 ? dots : '') + '<a class="ChangePage" onclick="' + clickFunc + '"><span>' + pages + '</span></a>';
				}
				clickFunc = (mgr.page < pages ? "viewMgr.setPageNumber(" + (mgr.page + 1) + "," + (mgr.inbound ? "true" : "false") + ")" : "");
				goForward += '<a class="ChangePageNext" onclick="' + clickFunc + '">&nbsp;</a>';
			}
			else {
				clickFunc = "viewMgr.setPageNumber(1," + (mgr.inbound ? "true" : "false") + ")";
				goBack = mgr.page > 6 && pages > 11 ? '<a class="ChangePage" onclick="' + clickFunc + '">' + TXT_FIRST + '</a>' : '';

				clickFunc = "viewMgr.setPageNumber(" + pages + "," + (mgr.inbound ? "true" : "false") + ")";
				goForward = mgr.page < pages - 10 ? '<a class="ChangePage" onclick="' + clickFunc + '">' + TXT_LAST + '</a>' : '';
			}

			elem.html(goBack + html + goForward);
		}
	},
	renderTransport: function (mgr, filter) {
		var ids = filter.ids;
		ids.sort(function (a, b) { return ((a < b) ? -1 : ((a > b) ? 1 : 0)); });
		var html = '<table class="transportFilter" width="100%">';
		var func = "viewMgr.setFilter('transport',this.value,this.checked," + (mgr.inbound ? "true" : "false") + ")";
		for (var i = 0, len = ids.length; i < len; i++) {
			var id = ids[i];
			var item = filter.items[id];
			if (item && item.visible) {
				html += '<tr><td width="22" valign="middle">' +
					'<input type="checkbox" class="styled" value="' + id + '" ' + (item.enabled ? 'checked' : '') + ' onclick="' + func + '"/>' +
					'</td><td width="18" valign="middle">' +
					'<img height="16" width="16" src="' + this.getTransportIcon(id) + '"/></td>' +
					'<td valign="middle">' + this.getTransportName(id) + '</td></tr>';
			}
		}
		html += '</table>';
		filter.writeHtml(html);
	},
	renderMapHeader: function (mgr, item, isDep) {
		var iata = (isDep ? item.dep : item.dest);
		var apt = mgr.getAirport(iata);
		var lat = (isDep && !mgr.inbound ? searchSettings.dep.lat : searchSettings.dest.lat);
		var lon = (isDep && !mgr.inbound ? searchSettings.dep.lon : searchSettings.dest.lon);
		var city = (isDep && !mgr.inbound ? searchSettings.dep.city : searchSettings.dest.city);
		var dist = mgr.getDistance(apt.lat, apt.lon, lat, lon);
		var rightText = '';
		var aptName = mgr.getAptName(iata) + ", " + apt.country;
		if (apt.type == transport.AIR) { aptName += " (" + iata.toUpperCase() + ")"; }
		var html = '<table width="100%" class="mapHeader"><tr><td><div class="mapHeaderInner"><div class="mapHeadLeft2">';
		if (!searchSettings.hidePinOnMapHeader) {
			var pin = this.getPinImage(apt.type, true);
			if (pin) { html += '<img hspace="4" height="' + pin.height + '" width="' + pin.width + '" align="absmiddle" src="' + pin.icon + '"/>'; }
		}
		html += aptName + '</div>';
		if (dist >= 0) {
			rightText = TXT_APPROX_FROM;
			rightText = rightText.replace('%1', '<b>' + dist + 'km</b>');
			rightText = rightText.replace('%2', '<b>' + city + '</b>');
		}
		if (rightText != '') { html += '<div class="mapHeadRight2">' + rightText + '</div>'; }
		html += '</div></td></tr></table>';
		return html;
	},
	getTransportName: function (type) {
		if (type == transport.TRAIN) { return TXT_TRAIN; }
		else if (type == transport.BUS) { return TXT_BUS; }
		else if (type == transport.FERRY) { return TXT_FERRY; }
		else { return TXT_FLIGHTS; }
	},
	getTransportIcon: function (type) {
		var icons = searchSettings.icons;
		var path = IMG_ROOT + 'i/transport/';
		if (type == transport.TRAIN) { return (icons && icons.train ? icons.train : path + 'rail-sm.gif'); }
		else if (type == transport.BUS) { return (icons && icons.bus ? icons.bus : path + 'bus-sm.gif'); }
		else if (type == transport.FERRY) { return (icons && icons.ferry ? icons.ferry : path + 'ferry-sm.gif'); }
		else { return (icons && icons.plane ? icons.plane : path + 'plane-sm.gif'); }
	},
	getShadowImage: function () {
		var icons = (searchSettings.icons ? searchSettings.icons : null);
		return (icons ? icons.pinShadow : null);
	},
	getPinImage: function (type, small) {
		var path = IMG_ROOT + 'i/map/';
		var icons = (searchSettings.icons ? searchSettings.icons : null);
		var img = null;
		if (type == transport.TRAIN) {
			if (small) { img = { icon: path + 'rail_sml.gif', width: 12, height: 18 }; }
			else { img = (icons && icons.trainPin ? icons.trainPin : { icon: path + 'rail.png', width: 20, height: 34 }); }
		}
		else if (type == transport.BUS) {
			if (small) { img = { icon: path + 'bus_sml.gif', width: 12, height: 18 }; }
			else { img = (icons && icons.busPin ? icons.busPin : { icon: path + 'bus.png', width: 20, height: 34 }); }
		}
		else if (type == transport.FERRY) {
			if (small) { img = { icon: path + 'ferry_sml.gif', width: 12, height: 18 }; }
			else { img = (icons && icons.ferryPin ? icons.ferryPin : { icon: path + 'ferry.png', width: 20, height: 34 }); }
		}
		else {
			if (small) { img = { icon: path + 'apt_sml.gif', width: 12, height: 18 }; }
			else { img = (icons && icons.aptPin ? icons.aptPin : { icon: path + 'apt.png', width: 20, height: 34 }); }
		}
		return img;
	},
	getIconImage: function (mgr, code, out) {
		var path = IMG_ROOT + 'i/grouping/';
		var apt = mgr.getAirport(code);
		if (apt.type == transport.TRAIN) { path += (out ? 'train_out.gif' : 'train_in.gif'); }
		else if (apt.type == transport.BUS) { path += (out ? 'bus_out.gif' : 'bus_in.gif'); }
		else if (apt.type == transport.FERRY) { path += (out ? 'ferry_out.gif' : 'ferry_in.gif'); }
		else { path += (out ? 'out.gif' : 'ret.gif'); }
		return '<img src="' + path + '" width="25" height="25" />';
	},
	getShortHtml: function (item, mgr) {
		var logo = '<img src="' + mgr.getFintail(item.opid) + '" border=0>';
		var redirect = this.getRedirect(item);
		var apts = (mgr.getTransportType(item.operator) == transport.AIR ? item.dep + ' >> ' + item.dest : '&nbsp;');
		var html = '<table width="100%" align=center cellpadding=0 border=0>' +
			'<tr><td width="50%" valign="middle">' +
			'<a href="' + redirect + '" class="ResultPrice" target="_blank">' + item.price + '</a><br>' + this.getTax(item) + '</td>' +
			'<td width="50%" align="center"><a href="' + redirect + '" target="_blank">' + logo + '</a></td></tr>' +
			'<tr><td>' + apts + '</td>' +
			'<td align="center"><a href="' + redirect + '" target="_blank">' + item.operator.name + '</a></td></tr>' +
			'<tr><td>' + this.formatDate(item.outbound.date, 'd MMM yyyy') + '</td>' +
			'<td align="center">' + item.outbound.time + ' >> ' + item.outbound.arrive + '</td></tr>';
		if (item.way == 2 && item.inbound) {
			html += '<tr><td>' + this.formatDate(item.inbound.date, 'd MMM yyyy') + '</td>' +
				'<td align="center">' + item.inbound.time + ' >> ' + item.inbound.arrive + '</td></tr>';
		}
		html += '<tr><td colspan="2"><div style="padding-top:4px;">' + this.getLastUpdated(item) + '</div></td></tr></table>';
		return html;
	},
	getUpdateLink: function (item, mgr) {
		var html = '';
		try {
			var timeSpan = server_time.subtractTime(item.updated);
			if (timeSpan.hours >= UPDATE_TIMOUT && !mgr.isFlexible) {
				var updateUrl = (searchSettings.shortUrl ? searchSettings.shortUrl : document.URL);
				if (updateUrl.indexOf('noCache') < 0) {
					updateUrl = (searchSettings.shortUrl ? searchSettings.shortUrl + 'noCache/' : document.URL + '&noCache=true');
				}
				var updateImg = (searchSettings.icons && searchSettings.icons.update ? searchSettings.icons.update : IMG_ROOT + 'i/update.gif');
				var style = 'background:url(' + updateImg + ') no-repeat left center;height:16px;line-height:16px;padding:0 0 0 18px;';
				html = '<div style="' + style + '"><a class="UpdateLink" href="' + updateUrl + '">' + TXT_UPDATE + '</a></div>';
			}
		} catch (ex) { }
		return html;
	},
	getDurationAndStops: function (leg) {
		var html = '';
		try {
			if (leg.durationText || leg.duration) {
				html = (leg.durationText && leg.durationText.length > 0 ? leg.durationText : leg.duration) + '<br/>';
			}
			if (leg.stops != null && leg.stops.length > 0) {
				if (leg.stops == "0") { html += TXT_NONSTOP.toLowerCase(); }
				else if (leg.stops == "1") { html += leg.stops + ' ' + TXT_STOP.toLowerCase(); }
				else { html += leg.stops + ' ' + TXT_STOPS.toLowerCase(); }
			}
		} catch (ex) { }
		return html;
	},
	renderGroup: function (item, mgr) {
		var html = '';
		try {
			var group = mgr.groupMgr.getGroup(item);
			for (var i = 0, len = group.filtered.length; i < len; i++) {
				var flight = group.filtered[i];
				if (html.length > 0) { html += ' | '; }
				var redirect = this.getRedirect(flight);
				html += '<a href="' + redirect + '" target="_blank" class="groupPriceLink">' +
					'<span class="opName">' + flight.operator.name + '</span> - ' + flight.price + '</a>';
			}
		} catch (ex) { }
		return html;
	},
	renderOptions: function (item, mgr, render) {
		var html = '';
		try {
			var optionsTemplate = templates.getTemplate("optionsTemplate");
			if (optionsTemplate != null) {
				html = optionsTemplate.apply({ item: item, mgr: mgr, render: this });
			}
		} catch (ex) { }
		return html;
	}
});

var flightGroupManager = $.Class.create({
	isGroup:true,
	groups:null,
	sorter:null,
	filter:null,
	filtered:null,
	unfiltered:null,
	filteredCount:null,
	totalCount:null,
	init: function(filter){
		this.groups = {};
		this.filtered = [];
		this.unfiltered = [];
		this.filter = filter;
		this.filteredCount = 0;
		this.totalCount = 0;
	},
	setSorter: function(sorter){
		this.sorter = sorter;
	},
	addFlight: function(flight){
		var group = this.groups[flight.groupId];
		if(group){
			var result = group.addFlight(flight);
			if(result != -2){ this.totalCount++; }
			if(result >= 0){ this.filteredCount++; }
			if(result == 0 && group.isValid()){
				var filteredIndex = this.filtered.indexOf(group);
				if(filteredIndex != -1){ this.filtered.splice(filteredIndex, 1); }
				this.filtered.binaryInsert(group, this.sorter);
			}
		}
		else{
			group = new flightGroup(flight, this.sorter, this.filter);
			this.groups[flight.groupId] = group;
			this.unfiltered.push(group);
			if(group.hasFlights()){ this.totalCount++; }
			if(group.isValid()){
				this.filtered.binaryInsert(group, this.sorter);
				this.filteredCount++;
			}
		}
	},
	filterResults: function(doFullResults, filtersOk){
		this.filteredCount = 0;
		var arr = (doFullResults ? this.unfiltered : this.filtered);
		this.filtered = [];
		if(this.filter && !filtersOk){ this.filter.reset(); }
		arr.duffArray(this, 'filterItem');
	},
	filterItem: function(group){
		group.filterResults();
		if(group.isValid()){
			this.filtered.binaryInsert(group, this.sorter);
			this.filteredCount += group.filtered.length;
		}
	},
	getGroup: function(flight){
		return this.groups[flight.groupId];
	}
});

var flightGroup = $.Class.create({
	isGroup: true,
	groupId: null,
	opids: null,
	flights: null,
	filtered: null,
	sorter: null,
	filter: null,
	init: function(flight, sorter, filter){
		this.opids = {};
		this.flights = [];
		this.filtered = [];
		this.sorter = sorter;
		this.filter = filter;
		this.groupId = flight.groupId;
		this.addFlight(flight);
	},
	addFlight: function(flight){
		var result = -2;
		var opid = flight.opid;
		var val = this.opids[opid];
		var flightExists = (val != null);
		if(flightExists && val > flight.value){
			this.flights.removeWhere("opid", flight.opid);
			this.filtered.removeWhere("opid", flight.opid);
			flightExists = false;
		}
		if(!flightExists){
			this.opids[opid] = flight.value;
			this.flights.binaryInsert(flight, this.sorter);
			if(!this.filter || this.filter.validateItem(flight)){
				result = this.filtered.binaryInsert(flight, this.sorter);
			}
		}
		return result;
	},
	hasFlights: function(){
		return (this.flights && this.flights.length > 0);
	},
	isValid: function(){
		return (this.filtered && this.filtered.length > 0);
	},
	filterResults: function(){
		var arr = this.flights;
		this.filtered = [];
		arr.duffArray(this, 'filterItem');
	},
	filterItem: function(item){
		var itemValid = true;
		if(this.filter){ itemValid = this.filter.updateFilter(item).isvalid; }
		if(itemValid){ this.filtered.push(item); }
	}
});

var flightsManager = $.Class.create({
	airports: null,
	airlines: null,
	operators: null,
	flights: null,
	filteredResults: null,
	filter: null,
	cheapestItem: null,
	resultsElement: null,
	resultsCount: null,
	pagingElement: null,
	transportRow: null,
	filterRow: null,
	filterVisible: true,
	sliders: null,
	inbound: false,
	page: 1,
	pagesize: 25,
	pageSizeSelect: null,
	updating: false,
	operatorCount: 0,
	render: new renderer(),
	sorter: null,
	view: null,
	renderOverride: null,
	visible: false,
	premiumOp: null,
	premiumOffer: null,
	bestOp: null,
	useBestOp: true,
	render_queue: 0,
	groupMgr: null,
	isGrouped: null,
	showAirlineLogos: false,
	destCountries: false,
	ids: null,
	allowUpdate: false,
	onResultsAdded: null,
	onFilter: null,
	init: function (o, view, inbound) {
		this.visible = false;
		this.airports = {};
		this.operators = {};
		this.airlines = {};
		this.flights = [];
		this.view = view;
		this.isGrouped = view.isGrouped;
		this.filteredResults = [];
		this.ids = {};
		if (!this.airlines[multiple_op_code]) { this.airlines[multiple_op_code] = { name: TXT_MULTIPLE_CARRIERS }; }
		if (!this.airlines[other_op_code]) { this.airlines[other_op_code] = { name: TXT_OTHER_OPERATORS }; }
		if (o != null) {
			this.sliders = o.sliders;
			if (o.sliders) {
				if (o.sliders.depTime || o.sliders.retTime) { o.filters.enableTimeFilter = true; }
				if (o.sliders.depDate || o.sliders.retDate) { o.filters.enableDateFilter = true; }
				if (o.sliders.outDuration || o.sliders.retDuration) { o.filters.enableDurationFilter = true; }
				if (o.sliders.price) { o.filters.enablePriceFilter = true; }
			}
			this.filter = new filterManager(o.filters);
			if (o.allowUpdate) { this.allowUpdate = o.allowUpdate; }
			if (o.resultsElement) { this.resultsElement = o.resultsElement; }
			if (o.resultsCount) { this.resultsCount = o.resultsCount; }
			if (o.pagingElement) { this.pagingElement = o.pagingElement; }
			if (o.transportRow) { this.transportRow = o.transportRow; }
			if (o.pagesize) { this.pagesize = o.pagesize; }
			if (o.filterRow) { this.filterRow = o.filterRow; }
			if (o.premiumOp) { this.premiumOp = o.premiumOp; }
			if (o.pageSizeSelect) { this.pageSizeSelect = o.pageSizeSelect; }
			if (o.filters && o.filters.destCountries) { this.destCountries = o.filters.destCountries; }
			if (o.onResultsAdded) { this.onResultsAdded = o.onResultsAdded; }
			if (o.onFilter) { this.onFilter = o.onFilter; }
			if (o.showAirlineLogos) { this.showAirlineLogos = o.showAirlineLogos; }
		}
		if (inbound) { this.inbound = inbound; }
		this.filterVisible = !this.inbound;
		this.operatorCount = 0;
		if (this.isGrouped) { this.groupMgr = new flightGroupManager(this.filter); }
	},
	setSorters: function (sorters) {
		this.sorter = new sortManager(sorters);
		if (this.groupMgr) { this.groupMgr.setSorter(this.sorter); }
	},
	sort: function (field, render, sorters) {
		this.premiumOp = null;
		this.premiumOffer = null;
		this.bestOp = null;
		this.useBestOp = false;
		this.sorter.doSort(field, (this.isGrouped ? this.groupMgr : this), sorters);
		if (render) {
			this.page = 1;
			this.renderResults();
			if (this.filter) { this.filter.render(this); }
		}
	},
	parseDuration: function (duration) {
		var hours = 0, minutes = 0;
		if (typeof (duration) == 'string') {
			var tsParts = duration.split(':');
			var len = tsParts.length;
			if (len > 0) { hours = parseInt(tsParts[0], 10); }
			if (len > 1) { minutes = parseInt(tsParts[1], 10); }
		}
		return (hours * 60) + minutes;
	},
	initResult: function (item, result) {
		if (this.allowUpdate) { item.updateStatus = { isUpdated: false, isUpdating: false, isQueued: false, updateFailed: false }; }
		item.updated = new Date((item.updated ? item.updated : result.updated));
		item.operator = (result.operator ? result.operator : this.operators[item.opid]);
		item.cpc = (item.operator && item.operator.cpc ? item.operator.cpc : 0);
		item.transport = this.getTransportType(item.operator);
		item.totalDuration = null;
		item.aircode = null;
		if (!item.uniqueId) { item.uniqueId = "f" + this.flights.length; }
		if (item.outbound) {
			var outleg = item.outbound;
			outleg.dateValue = Date.parseDate(outleg.date);
			if (outleg.dateArrive) { outleg.dateArriveValue = Date.parseDate(outleg.dateArrive); }
			if (outleg.aircode) {
				item.aircode = outleg.aircode;
				if (outleg.aircode != other_op_code && this.airlines[outleg.aircode]) {
					outleg.airline = this.airlines[outleg.aircode].name;
				}
			}
			if (outleg.duration) {
				outleg.durationValue = this.parseDuration(outleg.duration);
				item.totalDuration = outleg.durationValue;
			}
		}
		if (item.inbound) {
			var inleg = item.inbound;
			inleg.dateValue = Date.parseDate(inleg.date);
			if (inleg.dateArrive) { inleg.dateArriveValue = Date.parseDate(inleg.dateArrive); }
			if (inleg.aircode) {
				if (inleg.aircode != item.aircode) { item.aircode = multiple_op_code; }
				if (inleg.aircode != other_op_code && this.airlines[inleg.aircode]) {
					inleg.airline = this.airlines[inleg.aircode].name;
				}
			}
			if (item.totalDuration && inleg.duration) {
				inleg.durationValue = this.parseDuration(inleg.duration);
				item.totalDuration += inleg.durationValue;
			}
			else { item.totalDuration = null; }
		}
		item.dateId = this.getDateId(item);
		return item;
	},
	update: function () {
		this.startFilter(true, false, true);
	},
	addResults: function (result) {
		if (result.operator) { this.addOperator(result.operator); }
		else if (result.operators) {
			for (var i = result.operators.length; i--; ) { this.addOperator(result.operators[i]); }
		}
		for (var i = result.airports.length; i--; ) { this.addAirport(result.airports[i]); }
		for (var prop in result.airlines) {
			if (!this.airlines[prop]) { this.airlines[prop] = result.airlines[prop]; }
		}
		for (var i = result.flights.length; i--; ) {
			var item = this.initResult(result.flights[i], result);
			this.addFlight(item);
			if (!this.filter || this.filter.validateItem(item)) {
				this.filteredResults.binaryInsert(item, this.sorter);
			}
		}
		this.setPremiumOffer();
		if (this.onResultsAdded) { this.onResultsAdded(); }
	},
	updateResults: function (result) {
		if (!this.ids) { return; }
		if (result.operator) { this.addOperator(result.operator); }
		else if (result.operators) {
			for (var i = result.operators.length; i--; ) { this.addOperator(result.operators[i]); }
		}
		for (var i = result.airports.length; i--; ) { this.addAirport(result.airports[i]); }
		for (var prop in result.airlines) {
			if (!this.airlines[prop]) { this.airlines[prop] = result.airlines[prop]; }
		}
		var resultsUpdated = false;
		for (var i = result.flights.length; i--; ) {
			var newItem = result.flights[i];
			var oldItem = this.ids[newItem.uniqueId];
			if (oldItem) {
				newItem = this.initResult(newItem, result);
				if (newItem.updateStatus) { newItem.updateStatus.isUpdated = true; }
				for (var prop in oldItem) {
					oldItem[prop] = newItem[prop];
				}
				resultsUpdated = true;
			}
		}
	},
	addOperator: function (operator) {
		if (!this.operators[operator.opid]) {
			this.operators[operator.opid] = operator;
			this.operatorCount++;
			if (operator.cpc && operator.cpc > 0) {
				if (!this.bestOp) { this.bestOp = operator; }
				else if (this.bestOp && operator.cpc > this.bestOp.cpc) { this.bestOp = operator; }
			}
		}
	},
	addAirport: function (airport) {
		if (!this.airports[airport.code]) {
			this.airports[airport.code] = airport;
		}
	},
	addFlight: function (item) {
		if (this.filter) {
			if (searchSettings.dep) {
				var depApt = this.getAirport(item.dep);
				item.depISO3166 = depApt.iso3166;
				item.depDistance = this.getDistance(searchSettings.dep.lat, searchSettings.dep.lon, depApt.lat, depApt.lon);
			}
			if (searchSettings.dest) {
				var destApt = this.getAirport(item.dest);
				item.destISO3166 = destApt.iso3166;
				item.destDistance = this.getDistance(searchSettings.dest.lat, searchSettings.dest.lon, destApt.lat, destApt.lon);
			}
			this.filter.addFilter(item, this.inbound, this.sliders);
			if (this.destCountries) { this.filter.addDestCountryFilter(this.getAirport(item.dest)); }
		}
		if (this.isGrouped) { this.groupMgr.addFlight(item); }
		this.flights.binaryInsert(item, this.sorter);
		if (!this.cheapestItem || item.value < this.cheapestItem.value) {
			if (this.isSearchDate(item)) { this.cheapestItem = item; }
		}
		if (item.uniqueId && this.ids) { this.ids[item.uniqueId] = item; }
		if (item.groupId && item.groupId.length > 0 && hashVal == '#' + item.groupId) { this.showFullDetails(item.uniqueId); }
	},
	getGroupItems: function (item) {
		if (this.isGrouped) { return this.groupMgr.getGroup(item).filtered; }
		else { return [item]; }
	},
	filterResults: function (doFullResults, filtersOk) {
		if (this.isGrouped) { this.groupMgr.filterResults(doFullResults, filtersOk); }
		else { this.filterUngrouped(doFullResults, filtersOk); }
		if (this.view && this.view.onFilter) { this.view.onFilter(this.inbound); }
		if (this.onFilter) { this.onFilter(); }
	},
	filterUngrouped: function (doFullResults, filtersOk) {
		var arr = (doFullResults ? this.flights : this.filteredResults);
		this.filteredResults = [];
		if (this.filter && !filtersOk) { this.filter.reset(); }
		for (var i = 0, len = arr.length; i < len; i++) {
			var item = arr[i];
			var itemValid = true;
			if (this.filter) { itemValid = this.filter.updateFilter(item).isvalid; }
			if (itemValid) { this.filteredResults.push(item); }
		}
	},
	startFilter: function (redraw, filtersOk, doFullResults, excludeFilter) {
		pageManager.showLoadingScreen(true);
		var mgr = this;
		var doFilter = function () {
			mgr.filterResults(doFullResults, filtersOk);
			if (redraw) { mgr.renderResults(); }
			if (!filtersOk && mgr.filter) { mgr.filter.render(mgr, excludeFilter); }
			pageManager.showLoadingScreen(false);
			mgr = null;
		};
		setTimeout(doFilter, 250);
	},
	refreshSliders: function () {
		if (!this.sliders) { return; }
		if (this.sliders.depTime) {
			if (!this.sliders.depTime.defaultMin) { this.sliders.depTime.defaultMin = 0; }
			if (!this.sliders.depTime.defaultMax) { this.sliders.depTime.defaultMax = 24; }
			this.renderSlider(this.sliders.depTime, 'minDepTime', 'maxDepTime');
		}
		if (this.sliders.retTime) {
			if (!this.sliders.retTime.defaultMin) { this.sliders.retTime.defaultMin = 0; }
			if (!this.sliders.retTime.defaultMax) { this.sliders.retTime.defaultMax = 24; }
			this.renderSlider(this.sliders.retTime, 'minRetTime', 'maxRetTime');
		}
		if (this.sliders.price) { this.renderSlider(this.sliders.price, 'minPrice', 'maxPrice'); }
		if (this.sliders.depDate) { this.renderSlider(this.sliders.depDate, 'minDepDate', 'maxDepDate'); }
		if (this.sliders.retDate) { this.renderSlider(this.sliders.retDate, 'minRetDate', 'maxRetDate'); }
		if (this.sliders.outDuration) { this.renderSlider(this.sliders.outDuration, 'minOutDuration', 'maxOutDuration'); }
		if (this.sliders.retDuration) { this.renderSlider(this.sliders.retDuration, 'minRetDuration', 'maxRetDuration'); }
	},
	renderSlider: function (slider, filterMin, filterMax) {
		var thisSlider = (slider ? $(slider.id) : null);
		if (thisSlider && this.filter) {
			if (slider.defaultMin != null) { thisSlider.slider('option', 'min', slider.defaultMin); }
			if (slider.defaultMax != null) { thisSlider.slider('option', 'max', slider.defaultMax); }
			if (slider.defaultMin != null && slider.defaultMax != null) {
				var stepSize = (slider.stepSize != null ? slider.stepSize : 1);
				thisSlider.slider('option', 'steps', (slider.defaultMax - slider.defaultMin) / stepSize);
			}
			if (thisSlider.slider && thisSlider.width() > 0) {
				var renderFunc = (slider.renderValue ? slider.renderValue : this.renderTime);
				var minval = (this.filter[filterMin] != null ? this.filter[filterMin] : slider.defaultMin);
				var maxval = (this.filter[filterMax] != null ? this.filter[filterMax] : slider.defaultMax);
				if (minval != null) {
					thisSlider.slider('moveTo', minval, 0, true);
					$(slider.minlabel).html(renderFunc(minval));
				}
				if (maxval != null) {
					thisSlider.slider('moveTo', maxval, 1, true);
					$(slider.maxlabel).html(renderFunc(maxval));
				}
			}
		}
	},
	renderTime: function (val) {
		return (val < 10 ? '0' + val.toString() : val.toString()) + ':00';
	},
	sliderChanged: function (id, hnd, val, slider, filterMin, filterMax) {
		this.premiumOp = null;
		this.bestOp = null;
		this.useBestOp = false;
		if (slider && slider.id == id) {
			if (slider.min == hnd) {
				this.page = 1;
				this.filter[filterMin] = val;
				this.startFilter(true, false, true);
			}
			else if (slider.max == hnd) {
				this.page = 1;
				this.filter[filterMax] = val;
				this.startFilter(true, false, true);
			}
		}
	},
	changeSlider: function (type, id, hnd, val) {
		if (type == 'time') { this.timesChanged(id, hnd, val); }
		else if (type == 'duration') { this.durationsChanged(id, hnd, val); }
		else if (type == 'price') { this.priceChanged(id, hnd, val); }
		else if (type == 'date') { this.datesChanged(id, hnd, val); }
	},
	timesChanged: function (id, hnd, val) {
		if (!this.sliders) { return; }
		this.sliderChanged(id, hnd, val, this.sliders.depTime, 'minDepTime', 'maxDepTime');
		this.sliderChanged(id, hnd, val, this.sliders.retTime, 'minRetTime', 'maxRetTime');
	},
	priceChanged: function (id, hnd, val) {
		if (!this.sliders) { return; }
		this.sliderChanged(id, hnd, val, this.sliders.price, 'minPrice', 'maxPrice');
	},
	datesChanged: function (id, hnd, val) {
		if (!this.sliders) { return; }
		this.sliderChanged(id, hnd, val, this.sliders.depDate, 'minDepDate', 'maxDepDate');
		this.sliderChanged(id, hnd, val, this.sliders.retDate, 'minRetDate', 'maxRetDate');
	},
	durationsChanged: function (id, hnd, val) {
		if (!this.sliders) { return; }
		this.sliderChanged(id, hnd, val, this.sliders.outDuration, 'minOutDuration', 'maxOutDuration');
		this.sliderChanged(id, hnd, val, this.sliders.retDuration, 'minRetDuration', 'maxRetDuration');
	},
	setResultsHtml: function (html) {
		if (typeof (this.resultsElement) == 'string') {
			if (this.resultsElement.charAt(0) == '#') { this.resultsElement = this.resultsElement.substr(1); }
			this.resultsElement = getElement(this.resultsElement);
		}
		this.resultsElement.innerHTML = html;
	},
	setResultsCount: function (html) {
		if (this.resultsCount && typeof (this.resultsCount) == 'string') {
			if (this.resultsCount.charAt(0) == '#') { this.resultsCount = this.resultsCount.substr(1); }
			this.resultsCount = getElement(this.resultsCount);
		}
		if (this.resultsCount != null) { this.resultsCount.innerHTML = html; }
	},
	getFlightById: function (id) {
		if (this.ids && this.ids[id]) { return this.ids[id]; }
		return null;
	},
	getErrorHtml: function (msg) {
		var html = '';
		if (searchSettings.errorMsg && searchSettings.errorMsg.length > 0) {
			html = searchSettings.errorMsg.replace('%1', msg);
		}
		else { html = '<div class="ResultDiv"><div class="ErrorMessage">' + msg + '</div></div>'; }
		return html;
	},
	setPremiumOffer: function () {
		if (this.premiumOp && this.filter && this.filter.operators) {
			var premium, item;
			var newPremium = null;
			if (typeof (this.premiumOp) == 'number') {
				noPremium = false;
				premium = this.filter.operators.items[this.premiumOp];
				if (premium && premium.check()) {
					item = premium.cheapestItem;
					if (item && this.filter.validateItem(item)) { newPremium = item; }
				}
			}
			else {
				noPremium = (this.premiumOp.length == 0);
				for (var i = this.premiumOp.length; i--; ) {
					premium = this.filter.operators.items[this.premiumOp[i]];
					if (premium && premium.check() && premium.cheapestItem) {
						item = premium.cheapestItem;
						if (this.filter.validateItem(item) && (newPremium == null ||
							Math.round(item.value) < Math.round(newPremium.value))) { newPremium = item; }
					}
				}
			}
			if (!newPremium && this.bestOp && this.useBestOp) {
				premium = this.filter.operators.items[this.bestOp.opid];
				if (premium && premium.check()) {
					item = premium.cheapestItem;
					if (item && this.filter.validateItem(item)) { newPremium = item; }
				}
			}
			this.premiumOffer = newPremium;
		}
	},
	onAfterRender: function () {
		if (this.view && this.view.onafterrender) { this.view.onafterrender(); }
	},
	renderResults: function () {
		var rendered = 0;
		if (this.renderOverride) {
			rendered = this.renderOverride();
			if (rendered > 0) { this.onAfterRender(); }
			return rendered;
		}
		if (!this.updating) {
			this.updating = true;
			var data = this.getPageResults();
			if (!data || data.length == 0) {
				if (pageManager.searchFinished) {
					var msg = (this.flights.length == 0 ? TXT_NO_RESULTS_MSG : TXT_NO_RESULTS);
					this.setResultsHtml(this.getErrorHtml(msg));
				}
			}
			else {
				var resultsHtml = '';
				var maxItems = this.pagesize;
				var flightTemplate = templates.getTemplate("flightTemplate");
				if (this.premiumOffer && this.page == 1 && this.filter.validateItem(this.premiumOffer)) {
					resultsHtml += flightTemplate.apply({ item: this.premiumOffer, mgr: this, render: this.render, view: this.view, premium: true, size: 1 });
					rendered++;
				}
				for (var i = 0, len = data.length; i < len && rendered < maxItems; i++) {
					var result = data[i];
					if (this.isGrouped || (!this.isGrouped && result != this.premiumOffer)) {
						var dataItem = (this.isGrouped ? result.filtered[0] : result);
						var itemSize = (this.isGrouped ? result.filtered.length : 1);
						resultsHtml += flightTemplate.apply({ item: dataItem, mgr: this, render: this.render, view: this.view, size: itemSize });
						rendered++;
					}
				}
				if (resultsHtml.length == 0 && pageManager.searchFinished) {
					var msg = (this.flights.length == 0 ? TXT_NO_RESULTS_MSG : TXT_NO_RESULTS);
					resultsHtml = this.getErrorHtml(msg);
				}
				this.setResultsHtml(resultsHtml);
			}
			if (this.render) {
				this.setResultsCount(this.render.getResultCounts(this.getFilteredCount(), this.getTotalCount(), this.operatorCount));
				this.render.renderPaging(this);
			}
			this.updating = false;
		}
		if (rendered > 0) { this.onAfterRender(); }
		return rendered;
	},
	getFilteredResults: function () {
		return (this.isGrouped ? this.groupMgr.filtered : this.filteredResults);
	},
	getUnfilteredResults: function () {
		return (this.isGrouped ? this.groupMgr.unfiltered : this.flights);
	},
	getFilteredCount: function () {
		return (this.isGrouped ? this.groupMgr.filteredCount : this.filteredResults.length);
	},
	getTotalCount: function () {
		return (this.isGrouped ? this.groupMgr.totalCount : this.flights.length);
	},
	startRender: function (timeout) {
		this.render_queue++;
		var t = (timeout ? timeout : 250);
		pageManager.showLoadingScreen(true);
		var mgr = this;
		var doRender = function () {
			mgr.render_queue--;
			if (mgr.render_queue <= 0) {
				mgr.renderResults();
				if (mgr.filter) { mgr.filter.render(mgr); }
				pageManager.showLoadingScreen(false);
				mgr.render_queue = 0;
			}
			mgr = null;
		};
		setTimeout(doRender, t);
	},
	getPageResults: function () {
		var filteredArray = this.getFilteredResults();
		if (!filteredArray) { this.filterResults(true, false); }
		var data = null;
		filteredArray = this.getFilteredResults();
		if (filteredArray && filteredArray.length > 0) {
			data = this.selectPageResults(filteredArray);
		}
		return data;
	},
	selectPageResults: function (results) {
		var data = null;
		var length = (results ? results.length : 0);
		if (length > 0) {
			this.page = Math.min(Math.ceil(length / this.pagesize), this.page);
			var pagestart = (this.page - 1) * this.pagesize;
			var pageend = Math.min(pagestart + this.pagesize, length);
			var arr = (pageend > pagestart ? results.slice(pagestart, pageend) : null);
			data = arr;
		}
		return data;
	},
	refresh: function () {
		var mgr = this;
		var doRender = function () {
			mgr.renderResults();
			if (mgr.filter) { mgr.filter.render(mgr); }
			mgr = null;
		};
		setTimeout(doRender, 250);
	},
	getAirport: function (code) {
		return this.airports[code];
	},
	getAirlineFilterName: function (code) {
		return (this.airlines[code] ? this.airlines[code].name : '');
	},
	getAirline: function (item, defaultText) {
		var html = (item.airline ? item.airline : defaultText);
		if (item.aircode && item.aircode != other_op_code && this.airlines[item.aircode]) {
			var airline = this.airlines[item.aircode];
			if ((this.isGrouped || this.showAirlineLogos) && airline.logo) { html = '<img src="' + IMG_ROOT + 'i/airlines/' + airline.logo + '" width="75" height="25" alt="' + airline.name + '"/>'; }
			else { html = airline.name; }
		}
		return html;
	},
	getAirlineFromCode: function (code) {
		var html = code;
		if (code && code != other_op_code && this.airlines[code]) {
			var airline = this.airlines[code];
			if ((this.isGrouped || this.showAirlineLogos) && airline.logo) { html = '<img src="' + IMG_ROOT + 'i/airlines/' + airline.logo + '" width="75" height="25" alt="' + airline.name + '"/>'; }
			else { html = airline.name; }
		}
		return html;
	},
	getAptName: function (code, showShortName) {
		var aptname = '';
		if (this.airports[code]) {
			var apt = this.airports[code];
			aptname = apt.city;
			if (apt.name && apt.name.length > 0 && !(showShortName && apt.num == 1)) { aptname += ' ' + apt.name; }
		}
		return aptname;
	},
	getAptNameWithCountry: function (code) {
		var aptname = '';
		if (this.airports[code]) {
			var apt = this.airports[code];
			aptname = apt.city;
			if (apt.name && apt.name.length > 0) { aptname += ' ' + apt.name; }
			if (apt.country && apt.country.length > 0) { aptname += ', ' + apt.country; }
		}
		return aptname;
	},
	getOperator: function (opid) {
		var opname = '';
		if (this.operators[opid]) {
			opname = this.operators[opid].name;
		}
		return opname;
	},
	getFintail: function (opid) {
		var logo = '';
		if (this.operators[opid]) {
			logo = IMG_ROOT + 'i/operator/' + this.operators[opid].logo;
		}
		return logo;
	},
	getOpTab: function (item) {
		var html = '';
		if (!item) { return html; }
		var op = this.operators[item.opid];
		if (op) {
			var onclickText = this.render.getRedirectOnClick(item, this);
			if (onclickText == null || onclickText.length == 0) {
				var redirectUrl = this.render.getRedirect(item).replace(/\'/gi, "\\'");
				onclickText = "window.open('" + redirectUrl + "','" + this.render.getRedirectTarget(item) + "');";
			}
			var style = "";
			var text = "";
			if (op.img) {
				style = "background:url(" + IMG_ROOT + 'i/operator/logo/' + op.img + ") no-repeat center center;";
			}
			else {
				style = "background-color:" + (op.bgcolor ? op.bgcolor : "#FFFFFF") + ";" +
					"color:" + (op.textcolor ? op.textcolor : "#000000") + ";";
				text = op.name;
			}
			html = '<table class="opBtnTable" onclick="' + onclickText + '">' +
				'<tr><td class="opBtn" title="' + op.name + '" style="' + style + '">' + text + '</td></tr></table>';
		}
		return html;
	},
	getDistance: function (lat1, lon1, lat2, lon2) {
		var dist = 0;
		if (lat1 == lat2 && lon1 == lon2) { return 0; }
		else { dist = Math.round(6378 * Math.acos(Math.sin(lat1 / 57.3) * Math.sin(lat2 / 57.3) + Math.cos(lat1 / 57.3) * Math.cos(lat2 / 57.3) * Math.cos(lon2 / 57.3 - lon1 / 57.3)), 0); }
		return (isNaN(dist) ? 0 : dist);
	},
	getDateId: function (item) {
		var dep = item.outbound.dateValue;
		var ret = (item.inbound ? item.inbound.dateValue : null);
		return dep.formatString('yyyy-MM-dd') + (ret ? '_' + ret.formatString('yyyy-MM-dd') : '');
	},
	setFilter: function (type, id, checked, redraw, suppressUpdate) {
		if (this.filter) {
			this.premiumOp = null;
			this.bestOp = null;
			this.useBestOp = false;
			this.page = 1;
			var excludeFilter = (id != '#all#' ? type : null);
			if (this.destCountries && type == 'destCountry') { this.setDestCountryFilter(id, checked); }
			else {
				var filterItem = this.filter.getFilterItem(type, id);
				if (checked == 'toggle') { checked = filterItem.enabled = !filterItem.enabled; }
				this.filter.setFilter(type, id, checked);
				if (redraw && this.filter) { this.filter.render(this); }
				if (!suppressUpdate && !((type == 'op' || type == 'date') && filterItem != null && filterItem.cheapestItem == null)) {
					this.startFilter(true, false, true, excludeFilter);
				}
			}
		}
	},
	setDestCountryFilter: function (id, checked) {
		var filterList = this.filter.destCountries;
		if (filterList) {
			var country = filterList[id];
			for (var i = 0, len = country.arr.length; i < len; i++) {
				var apt = country.arr[i].apt;
				this.filter.setFilter('dest', apt.code, checked);
			}
			if (len > 0) { this.startFilter(true, false, true); }
		}
	},
	getDestCountryFilter: function (id) {
		var filterList = this.filter.destCountries;
		if (filterList && filterList[id]) { return filterList[id]; }
		return null;
	},
	isSearchDate: function (item) {
		if (!searchSettings.depdate) { return false; }
		var dep = item.outbound.dateValue;
		var ret = (item.way == 2 && item.inbound ? item.inbound.dateValue : null);
		var strDepDate = (!this.inbound ? searchSettings.depdate : searchSettings.retdate);
		var strRetDate = (!this.inbound ? searchSettings.retdate : searchSettings.depdate);
		var searchDep = Date.parseDate(strDepDate, "yyyy-MM-dd");
		var searchRet = (item.way == 2 && ret ? Date.parseDate(strRetDate, "yyyy-MM-dd") : null);
		return (dep.compareDate(searchDep) && (ret && item.way == 2 ? ret.compareDate(searchRet) : true));
	},
	hasOptions: function (item) {
		var res = (item.outbound ? item.outbound.options != null : false) && (item.inbound ? item.inbound.options != null : true);
		return res;
	},
	setPageNumber: function (num) {
		this.page = num;
		if (this.page != 1) {
			this.premiumOp = null;
			this.bestOp = null;
			this.useBestOp = false;
		}
	},
	setPageSize: function (size) {
		this.pagesize = size;
		this.page = 1;
	},
	setPageSizeSelect: function () {
		if (this.pageSizeSelect) {
			var elem = getElement(this.pageSizeSelect);
			if (elem && elem.setValue) { elem.setValue(this.pagesize); }
			else if (elem && elem.value != this.pagesize && elem.options) {
				for (var i = elem.length; i--; ) {
					var option = elem.options[i];
					if (option.value == this.pagesize) {
						option.selected = true;
						return;
					}
				}
			}
		}
	},
	getTransportType: function (operator) {
		switch (operator.type) {
			case 4:
				return transport.TRAIN;
			case 5:
				return transport.BUS;
			case 6:
				return transport.FERRY;
			default:
				return transport.AIR;
		}
	},
	getAirports: function (endPoint) {
		var apts = [];
		var withDep = true; var withDest = true;
		if (endPoint == 'dep') { withDep = true; withDest = false; }
		else if (endPoint == 'dest') { withDep = false; withDest = true; }
		if (!this.filter) { return apts; }
		if (withDep && this.filter.depAirports) {
			for (var prop in this.filter.depAirports.items) {
				if (this.filter.depAirports.items[prop]) { apts.push({ item: this.filter.depAirports.items[prop], isDep: true }); }
			}
		}
		if (withDest && this.filter.destAirports) {
			for (var prop in this.filter.destAirports.items) {
				if (this.filter.destAirports.items[prop]) { apts.push({ item: this.filter.destAirports.items[prop], isDep: false }); }
			}
		}
		return apts;
	},
	toggleFilter: function () {
		this.filterVisible = !this.filterVisible;
		this.showFilter();
		if (this.filterVisible) { this.refreshSliders(); }
		return this.filterVisible;
	},
	showFilter: function () {
		var row = (this.filterRow ? $(this.filterRow) : null);
		if (row && row.get(0) != document) { row.css('display', (this.filterVisible ? '' : 'none')); }
	},
	showFullDetails: function (id) {
		if (this.ids && this.ids[id]) {
			var item = this.ids[id];
			var group = (this.isGrouped ? this.groupMgr.getGroup(item) : null);
			var itemSize = 1;
			if (group) { itemSize = group.filtered.length; }
			var detailsTemplate = templates.getTemplate("detailsTemplate");
			var txt = detailsTemplate.apply({ item: item, mgr: this, render: this.render, view: this.view, size: itemSize });
			lbox.showLightBox(txt, 620);
			return;
		}
	},
	emailOffer: function (id) {
		if (this.ids && this.ids[id]) {
			var item = this.ids[id];
			var group = (this.isGrouped ? this.groupMgr.getGroup(item) : null);
			var itemSize = 1;
			if (group) { itemSize = group.filtered.length; }
			var emailTemplate = templates.getTemplate("emailTemplate");
			var txt = emailTemplate.apply({ item: item, mgr: this, render: this.render, view: this.view, size: itemSize });
			lbox.showLightBox(txt, 600);
			return;
		}
	},
	showMultiBook: function (id) {
		if (this.ids && this.ids[id]) {
			lbox.clearLightBox();
			var item = this.ids[id];
			var itemSize = (this.isGrouped ? this.groupMgr.getGroup(item).filtered.length : 1);
			var multiBookingTemplate = templates.getTemplate("multiBookingTemplate");
			var txt = multiBookingTemplate.apply({ item: item, mgr: this, render: this.render, view: this.view, size: itemSize });
			lbox.showLightBox(txt, 620);
			return true;
		}
		return false;
	},
	setSelectedOption: function (id, selectedOpt, isOutLeg) {
		if (this.ids && this.ids[id]) {
			var item = this.ids[id];
			var direction = (isOutLeg ? item.outbound : item.inbound);
			var options = (direction ? direction.options : null);
			if (options && options.length > 0) {
				if (selectedOpt.value) { item.value = selectedOpt.value; }
				if (selectedOpt.price) { item.price = selectedOpt.price; }
				if (selectedOpt.dep) { direction.time = selectedOpt.dep; }
				if (selectedOpt.arr) { direction.arrive = selectedOpt.arr; }
				for (var i = 0, len = options.length; i < len; i++) {
					var opt = options[i];
					if (opt.dep == selectedOpt.dep && opt.arr == selectedOpt.arr) { direction.selectedOption = opt; break; }
				}
				var elem = getElement(this.getItemHtmlId(item));
				if (elem) {
					var isPremium = (this.premiumOffer == item);
					item.optionsOpen = true;
					var flightTemplate = templates.getTemplate("flightTemplate");
					elem.innerHTML = flightTemplate.apply({ item: item, mgr: this, render: this.render, view: this.view, premium: isPremium, innerHtmlOnly: true, size: 1 });
				}
			}
		}
	},
	openOptions: function (id, force) {
		if (this.ids && this.ids[id]) {
			var item = this.ids[id];
			if (force != null) { item.optionsOpen = force; }
			else { item.optionsOpen = (!item.optionsOpen ? true : false); }
		}
	},
	getCarHireSearch: function (item) {
		var url = '';
		try {
			var outApt = this.getAirport(item.dest);
			var inApt = this.getAirport(item.inbound.dep ? item.inbound.dep : item.dest);
			url = CARHIRE_PATH + 'search.aspx';
			url += '?pickup=' + encodeURIComponent(outApt.city + (outApt.country && outApt.country.length > 0 ? ' ' + outApt.country : ''));
			url += '&pickupCode=';
			url += '&pickupIata=' + outApt.code;
			url += '&dropoff=' + encodeURIComponent(inApt.city + (inApt.country && inApt.country.length > 0 ? ' ' + inApt.country : ''));
			url += '&dropoffCode=';
			url += '&dropoffIata=' + inApt.code;
			url += '&pickupDate=' + item.outbound.dateArriveValue.formatString('yyyy-MM-dd');
			url += '&pickupHour=' + item.outbound.arrive;
			url += '&dropoffDate=' + item.inbound.dateValue.formatString('yyyy-MM-dd');
			url += '&dropoffHour=' + item.inbound.time;
			if (searchSettings.currencyRegion) { url += '&currency=' + searchSettings.currencyRegion; }
			var lang = '';
			try { lang = LANG_CODE; } catch (e) { }
			url += '&lang=' + lang;
		} catch (e) { }
		return url;
	},
	getHotelSearch: function (item) {
		var url = '';
		try {
			var dest = this.getAirport(item.dest);
			url = HOTELS_PATH + 'hotelsearch.aspx';
			url += '?city=' + encodeURIComponent(dest.city + (dest.country && dest.country.length > 0 ? ' ' + dest.country : ''));
			url += '&dtCheckIn=' + item.outbound.dateValue.formatString('yyyy-MM-dd');
			url += '&dtCheckOut=' + item.inbound.dateValue.formatString('yyyy-MM-dd');
			url += '&occupancy=' + (searchSettings && searchSettings.adults ? searchSettings.adults + searchSettings.children : 1);
			if (searchSettings.currencyRegion) { url += '&currency=' + searchSettings.currencyRegion; }
			var lang = '';
			try { lang = LANG_CODE; } catch (e) { }
			url += '&lang=' + lang;
		} catch (e) { }
		return url;
	},
	checkSelectedOption: function (leg, opt) {
		if (leg.selectedOption) {
			return (leg.selectedOption == opt);
		}
		else {
			var isSelected = (leg.time == opt.dep && leg.arrive == opt.arr);
			if (isSelected) { leg.selectedOption = opt; }
			return isSelected;
		}
	},
	getItemHtmlId: function (item) {
		if (item.uniqueId) {
			return "result" + this.view.id + (this.inbound ? "IN" : "OUT") + "_" + item.uniqueId;
		}
		return '';
	}
});

var flexiFlightsManager = flightsManager.extend({
	isFlexible: true,
	chart: null,
	accessor: null,
	monthLabel: null,
	graphElement: null,
	prevMonthImgId: null,
	xmlRequest: null,
	ajaxUrl: null,
	day: null,
	month: null,
	year: null,
	way: 2,
	init: function (o, view, inbound) {
		this._super(o, view, inbound);
		this.accessor = o.accessor;
		this.monthLabel = o.monthLabel;
		this.graphElement = o.graphElement;
		this.prevMonthImgId = o.prevMonthImgId;
		this.xmlRequest = o.xmlRequest;
		this.ajaxUrl = o.ajaxUrl;
		this.month = searchSettings.month;
		this.year = searchSettings.year;
		this.chart = o.chart;
		this.chart.setMonthYear(this.month, this.year);
		if (o.way) { this.way = o.way; }
	},
	addFlight: function (item) {
		this._super(item);
		this.filterChartItem(item);
	},
	filterResults: function (doFullResults, filtersOk) {
		this._super(doFullResults, filtersOk);
		if (this.day == null) {
			this.chart.clearData();
			var arr = this.flights;
			arr.duffArray(this, 'filterChartItem');
		}
	},
	filterChartItem: function (item) {
		if (this.filter) {
			var validation = this.filter.getItemValidation(item);
			if (validation.dep && validation.dest) { this.chart.addItem(item); }
		}
	},
	loadResults: function () {
		pageManager.showLoadingScreen(true);
		this.flights = [];
		this.filteredResults = [];
		this.filter.clear(true);
		this.filter.resetSliderValues();
		this.page = 1;
		if (this.xmlRequest && this.ajaxUrl && this.month != null && this.year != null) {
			var data = 'type=' + (this.day != null ? 'day' : 'month');
			data += '&dep=' + (!this.inbound ? searchSettings.dep.iata : searchSettings.dest.iata);
			data += '&dest=' + (!this.inbound ? searchSettings.dest.iata : searchSettings.dep.iata);
			data += '&d=' + (this.day != null ? this.day : '');
			data += '&m=' + this.month;
			data += '&y=' + this.year;
			data += '&adults=' + searchSettings.adults;
			data += '&children=' + searchSettings.children;
			data += '&infants=' + searchSettings.infants;
			data += '&way=' + this.way;
			data += '&currency=' + searchSettings.currencyRegion;
			var mgr = this;
			var callback = function (req) { mgr.xmlResponse(req); };
			this.xmlRequest.Request(this.ajaxUrl, callback, 'GET', data);
		}
	},
	xmlResponse: function (req) {
		if (req.readyState == 4) {
			if (req.status == 200 && req.responseText) {
				this.addResults(eval('(' + req.responseText + ')'));
			}
			if (this.visible) {
				this.startRender();
				this.refreshSliders();
			}
		}
	},
	renderResults: function () {
		this.chart.drawChart();
		this._super();
	},
	nextMonth: function () {
		this.day = null;
		this.month++;
		if (this.month > 12) {
			this.month = 1;
			this.year++;
		}
		this.loadMonth();
	},
	prevMonth: function () {
		this.day = null;
		this.month--;
		if (this.month < 1) {
			this.month = 12;
			this.year--;
		}
		this.loadMonth();
	},
	loadMonth: function () {
		this.chart.setMonthYear(this.month, this.year);
		this.loadResults();
	},
	setDate: function (day) {
		if (this.day == day) { this.day = null; }
		else { this.day = day; }
		this.chart.setSelectedDay(this.day);
		this.loadResults();
	},
	getTooltipHtml: function (index) {
		var html = '';
		if (this.chart && this.chart.chartData.length > index && this.chart.chartData[index]) {
			var item = this.chart.chartData[index];
			html = this.render.getShortHtml(item, this);
		}
		return html;
	}
});

var filterManager = $.Class.create({
	showNonStop: true,
	show1Stop: true,
	show2Stops: true,
	depAirports: null,
	destAirports: null,
	operators: null,
	airlines: null,
	dates: null,
	transportTypes: null,
	enableTimeFilter: true,
	minDepTime: null,
	maxDepTime: null,
	minRetTime: null,
	maxRetTime: null,
	enablePriceFilter: false,
	minPrice: null,
	maxPrice: null,
	enableDateFilter: false,
	minDepDate: null,
	maxDepDate: null,
	minRetDate: null,
	maxRetDate: null,
	enableDurationFilter: false,
	minOutDuration: null,
	maxOutDuration: null,
	minRetDuration: null,
	maxRetDuration: null,
	destCountries: null,
	init: function (o) {
		if (o != null) {
			if (o.depAirports) { this.depAirports = new filterGroup(o.depAirports); }
			if (o.destAirports) { this.destAirports = new filterGroup(o.destAirports); }
			if (o.operators) { this.operators = new filterGroup(o.operators); }
			if (o.dates) { this.dates = new filterGroup(o.dates); }
			if (o.transportTypes) { this.transportTypes = new filterGroup(o.transportTypes); }
			if (o.airlines) {
				this.airlines = new filterGroup(o.airlines);
				this.airlines.defaultCheck = true;
			}
			if (o.enableTimeFilter != null) { this.enableTimeFilter = o.enableTimeFilter; }
			if (o.enablePriceFilter != null) { this.enablePriceFilter = o.enablePriceFilter; }
			if (o.enableDateFilter != null) { this.enableDateFilter = o.enableDateFilter; }
			if (o.enableDurationFilter != null) { this.enableDurationFilter = o.enableDurationFilter; }
			if (o.destCountries) { this.destCountries = {}; }
		}
	},
	addFilter: function (item, inbound, sliders) {
		if (item) {
			if (this.enableTimeFilter) { this.setTimes(item); }
			if (this.enablePriceFilter) { this.setPrices(item, sliders); }
			if (this.enableDateFilter) { this.setDates(item, sliders); }
			if (this.enableDurationFilter) { this.setDurations(item, sliders); }
			if (this.depAirports) {
				var enabled = (searchSettings.maxDistance != null && item.depDistance != null ? (item.depDistance < searchSettings.maxDistance) : true);
				if (searchSettings.directory && item.depISO3166) {
					if (item.depISO3166 != searchSettings.dep.iso3166) { enabled = false; }
				}
				this.depAirports.addItem(item.dep, null, null, null, { enabled: enabled });
				if (item.inbound && item.inbound.dest) { this.depAirports.addItem(item.inbound.dest); }
			}
			if (this.destAirports) {
				var enabled = (searchSettings.maxDistance != null && item.destDistance != null ? (item.destDistance < searchSettings.maxDistance) : true);
				if (searchSettings.directory && item.destISO3166) {
					if (item.destISO3166 != searchSettings.dest.iso3166) { enabled = false; }
				}
				this.destAirports.addItem(item.dest, null, null, null, { enabled: enabled });
				if (item.inbound && item.inbound.dep) { this.destAirports.addItem(item.inbound.dep); }
			}
			if (this.operators) { this.operators.addItem(item.opid); }
			if (this.airlines) {
				if (item.aircode) { this.airlines.addItem(item.aircode); }
				if (item.outbound && item.outbound.aircode) { this.airlines.addItem(item.outbound.aircode); }
				if (item.inbound && item.inbound.aircode) { this.airlines.addItem(item.inbound.aircode); }
			}
			if (this.transportTypes) { this.transportTypes.addItem(item.transport); }
			if (this.dates) {
				var dep = item.outbound.dateValue;
				var ret = (item.way == 2 && item.inbound ? item.inbound.dateValue : null);
				var strDepDate = (!inbound ? searchSettings.depdate : searchSettings.retdate);
				var strRetDate = (!inbound ? searchSettings.retdate : searchSettings.depdate);
				var searchDep = Date.parseDate(strDepDate, "yyyy-MM-dd");
				var searchRet = (item.way == 2 && ret ? Date.parseDate(strRetDate, "yyyy-MM-dd") : null);
				var properties = {
					dep: dep,
					ret: ret,
					enabled: (dep.compareDate(searchDep) && (ret && item.way == 2 ? ret.compareDate(searchRet) : true))
				};
				this.dates.addItem(item.dateId, null, null, null, properties);
			}
			this.updateFilter(item);
		}
	},
	addDestCountryFilter: function (apt) {
		if (!apt || !this.destAirports || !this.destCountries) { return; }
		var aptFilter = this.destAirports.getItem(apt.code);
		var country = null;
		if (!this.destCountries[apt.iso3166]) {
			country = { name: apt.country, code: apt.iso3166, arr: [], checked: false, open: false };
			this.destCountries[apt.iso3166] = country;
		}
		else { country = this.destCountries[apt.iso3166]; }
		if (country) {
			var item = { apt: apt, filterItem: aptFilter };
			country.arr.binaryInsert(item, function (a, b) { return ((a.apt.city < b.apt.city) ? -1 : ((a.apt.city > b.apt.city) ? 1 : 0)); });
			if (aptFilter.enabled) { country.checked = true; }
		}
	},
	updateFilter: function (item) {
		var validation = this.getItemValidation(item);
		if (validation.time && validation.stops && validation.price) {
			if (this.transportTypes) { this.transportTypes.addItem(item.transport, null, this.getValidItem(item, 'transport', validation)); }
			if (validation.transport) {
				if (this.dates) { this.dates.addItem(item.dateId, null, this.getValidItem(item, 'date', validation)); }
				if (validation.date) {
					if (this.depAirports) {
						var validItem = this.getValidItem(item, 'dep', validation);
						var validMapItem = this.getValidMapItem(item, 'dep', validation);
						this.depAirports.addItem(item.dep, item, validItem, validMapItem);
						if (item.inbound && item.inbound.dest) { this.depAirports.addItem(item.inbound.dest, item, validItem, validMapItem); }
					}
					if (this.destAirports) {
						var validItem = this.getValidItem(item, 'dest', validation);
						var validMapItem = this.getValidMapItem(item, 'dest', validation);
						this.destAirports.addItem(item.dest, item, validItem, validMapItem);
						if (item.inbound && item.inbound.dep) { this.destAirports.addItem(item.inbound.dep, item, validItem, validMapItem); }
					}
					if (this.operators) { this.operators.addItem(item.opid, null, this.getValidItem(item, 'operator', validation)); }
					if (this.airlines) {
						if (item.aircode) { this.airlines.addItem(item.aircode, null, this.getValidItem(item, 'airline', validation)); }
						if (item.outbound && item.outbound.aircode) { this.airlines.addItem(item.outbound.aircode, null, this.getValidItem(item, 'airline', validation)); }
						if (item.inbound && item.inbound.aircode) { this.airlines.addItem(item.inbound.aircode, null, this.getValidItem(item, 'airline', validation)); }
					}
				}
			}
		}
		return validation;
	},
	getFilterItem: function (type, id) {
		if (type == 'dep' && this.depAirports) { return this.depAirports.getItem(id); }
		else if (type == 'dest' && this.destAirports) { return this.destAirports.getItem(id); }
		else if (type == 'op' && this.operators) { return this.operators.getItem(id); }
		else if (type == 'airline' && this.airlines) { return this.airlines.getItem(id); }
		else if (type == 'date' && this.dates) { return this.dates.getItem(id); }
		else if (type == 'transport' && this.transportTypes) { return this.transportTypes.getItem(id); }
	},
	setFilter: function (type, id, enabled) {
		if (type == 'dep' && this.depAirports) { this.depAirports.setItem(id, enabled); }
		else if (type == 'dest' && this.destAirports) { this.destAirports.setItem(id, enabled); }
		else if (type == 'op' && this.operators) { this.operators.setItem(id, enabled); }
		else if (type == 'airline' && this.airlines) { this.airlines.setItem(id, enabled); }
		else if (type == 'date' && this.dates) { this.dates.setItem(id, enabled); }
		else if (type == 'transport' && this.transportTypes) { this.transportTypes.setItem(id, enabled); }
		else if (type == 'stops') {
			if (id == 0) { this.showNonStop = enabled; }
			else if (id == 1) { this.show1Stop = enabled; }
			else if (id == 2) { this.show2Stops = enabled; }
		}
	},
	setTimes: function (item) {
		var hour = parseInt(item.outbound.time, 10);
		if (this.minDepTime == null || hour < this.minDepTime) { this.minDepTime = hour; }
		hour = (hour < 24 ? hour + 1 : hour);
		if (this.maxDepTime == null || hour > this.maxDepTime) { this.maxDepTime = hour; }
		if (item.inbound) {
			hour = parseInt(item.inbound.time, 10);
			if (this.minRetTime == null || hour < this.minRetTime) { this.minRetTime = hour; }
			hour = (hour < 24 ? hour + 1 : hour);
			if (this.maxRetTime == null || hour > this.maxRetTime) { this.maxRetTime = hour; }
		}
		this.setTimesFromOptions(item.outbound, 'minDepTime', 'maxDepTime');
		this.setTimesFromOptions(item.inbound, 'minRetTime', 'maxRetTime');
	},
	setTimesFromOptions: function (leg, minProp, maxProp) {
		if (leg && leg.options) {
			for (var i = 0, len = leg.options.length; i < len; i++) {
				var hour = parseInt(leg.options[i].dep, 10);
				if (this[minProp] == null || hour < this[minProp]) { this[minProp] = hour; }
				hour = (hour < 24 ? hour + 1 : hour);
				if (this[maxProp] == null || hour > this[maxProp]) { this[maxProp] = hour; }
			}
		}
	},
	setDates: function (item, sliders) {
		var depDate = parseInt(item.outbound.dateValue.getTime() / msPerDay, 10);
		if (this.minDepDate == null || depDate < this.minDepDate) {
			this.minDepDate = depDate;
			if (sliders.depDate) { sliders.depDate.defaultMin = this.minDepDate; }
		}
		if (this.maxDepDate == null || depDate > this.maxDepDate) {
			this.maxDepDate = depDate + 1;
			if (sliders.depDate) { sliders.depDate.defaultMax = this.maxDepDate; }
		}
		if (item.inbound) {
			var retDate = parseInt(item.inbound.dateValue.getTime() / msPerDay, 10);
			if (this.minRetDate == null || retDate < this.minRetDate) {
				this.minRetDate = retDate;
				if (sliders.retDate) { sliders.retDate.defaultMin = this.minRetDate; }
			}
			if (this.maxRetDate == null || retDate > this.maxRetDate) {
				this.maxRetDate = retDate + 1;
				if (sliders.retDate) { sliders.retDate.defaultMax = this.maxRetDate; }
			}
		}
	},
	setDurations: function (item, sliders) {
		if (item.outbound.durationValue != null) {
			if (this.minOutDuration == null || item.outbound.durationValue < this.minOutDuration) {
				this.minOutDuration = Math.floor(item.outbound.durationValue / 5) * 5;
				if (sliders.outDuration) { sliders.outDuration.defaultMin = this.minOutDuration; }
			}
			if (this.maxOutDuration == null || item.outbound.durationValue > this.maxOutDuration) {
				this.maxOutDuration = Math.ceil(item.outbound.durationValue / 5) * 5;
				if (sliders.outDuration) { sliders.outDuration.defaultMax = this.maxOutDuration; }
			}
			if (this.minOutDuration != null && this.minOutDuration == this.maxOutDuration) {
				this.minOutDuration -= 5;
				this.maxOutDuration += 5;
				if (sliders.outDuration) { sliders.outDuration.defaultMin = this.minOutDuration; }
				if (sliders.outDuration) { sliders.outDuration.defaultMax = this.maxOutDuration; }
			}
		}
		if (item.inbound && item.inbound.durationValue != null) {
			if (this.minRetDuration == null || item.inbound.durationValue < this.minRetDuration) {
				this.minRetDuration = Math.floor(item.inbound.durationValue / 5) * 5;
				if (sliders.retDuration) { sliders.retDuration.defaultMin = this.minRetDuration; }
			}
			if (this.maxRetDuration == null || item.inbound.durationValue > this.maxRetDuration) {
				this.maxRetDuration = Math.ceil(item.inbound.durationValue / 5) * 5;
				if (sliders.retDuration) { sliders.retDuration.defaultMax = this.maxRetDuration; }
			}
			if (this.minRetDuration != null && this.minRetDuration == this.maxRetDuration) {
				this.minRetDuration -= 5;
				this.maxRetDuration += 5;
				if (sliders.retDuration) { sliders.retDuration.defaultMin = this.minRetDuration; }
				if (sliders.retDuration) { sliders.retDuration.defaultMax = this.maxRetDuration; }
			}
		}
	},
	setPrices: function (item, sliders) {
		if (this.minPrice == null || item.value < this.minPrice) {
			this.minPrice = Math.floor(item.value);
			if (sliders.price) { sliders.price.defaultMin = this.minPrice; }
		}
		if (this.maxPrice == null || item.value > this.maxPrice) {
			this.maxPrice = Math.ceil(item.value);
			if (sliders.price) { sliders.price.defaultMax = this.maxPrice; }
		}
	},
	resetSliderValues: function () {
		this.minDepTime = null;
		this.maxDepTime = null;
		this.minRetTime = null;
		this.maxRetTime = null;
		this.minPrice = null;
		this.maxPrice = null;
		this.minDepDate = null;
		this.maxDepDate = null;
		this.minRetDate = null;
		this.maxRetDate = null;
		this.minOutDuration = null;
		this.maxOutDuration = null;
		this.minRetDuration = null;
		this.maxRetDuration = null;
	},
	getItemValidation: function (item) {
		var validation = { time: true, stops: true, date: true, dep: true, dest: true, operator: true, transport: true, airline: true, price: true, duration: true, isvalid: true };
		if (!this.validateTimes(item)) {
			validation.time = false;
			validation.isvalid = false;
		}
		if (!this.validateStops(item)) {
			validation.stops = false;
			validation.isvalid = false;
		}
		if (!this.validateDates(item)) {
			validation.date = false;
			validation.isvalid = false;
		}
		if (!this.validateDurations(item)) {
			validation.duration = false;
			validation.isvalid = false;
		}
		if (!this.validatePrices(item)) {
			validation.price = false;
			validation.isvalid = false;
		}
		if (this.depAirports && !this.depAirports.checkItem(item.dep)) {
			validation.dep = false;
			validation.isvalid = false;
		}
		if (this.depAirports && item.inbound && item.inbound.dest && !this.depAirports.checkItem(item.inbound.dest)) {
			validation.dep = false;
			validation.isvalid = false;
		}
		if (this.destAirports && !this.destAirports.checkItem(item.dest)) {
			validation.dest = false;
			validation.isvalid = false;
		}
		if (this.destAirports && item.inbound && item.inbound.dep && !this.destAirports.checkItem(item.inbound.dep)) {
			validation.dest = false;
			validation.isvalid = false;
		}
		if (this.operators && !this.operators.checkItem(item.opid)) {
			validation.operator = false;
			validation.isvalid = false;
		}
		if (this.transportTypes && !this.transportTypes.checkItem(item.transport)) {
			validation.transport = false;
			validation.isvalid = false;
		}
		if (this.airlines) {
			if (item.aircode && !this.airlines.checkItem(item.aircode)) {
				validation.airline = false;
				validation.isvalid = false;
			}
			else if (item.outbound && item.outbound.aircode && !this.airlines.checkItem(item.outbound.aircode)) {
				validation.airline = false;
				validation.isvalid = false;
			}
			else if (item.inbound && item.inbound.aircode && !this.airlines.checkItem(item.inbound.aircode)) {
				validation.airline = false;
				validation.isvalid = false;
			}
		}
		return validation;
	},
	getValidItem: function (item, type, validation) {
		if (type != 'time' && !validation.time) { return null; }
		if (type != 'price' && !validation.price) { return null; }
		else if (type != 'date' && !validation.date) { return null; }
		else if (type != 'duration' && !validation.duration) { return null; }
		else if (type != 'dep' && !validation.dep) { return null; }
		else if (type != 'dest' && !validation.dest) { return null; }
		else if (type != 'operator' && !validation.operator) { return null; }
		else if (type != 'transport' && !validation.transport) { return null; }
		else if (type != 'airline' && !validation.airline) { return null; }
		else if (type == 'dep' && !validation.dep) { return null; }
		else if (type == 'dest' && !validation.dest) { return null; }

		return item;
	},
	getValidMapItem: function (item, type, validation) {
		if (!validation.isvalid) { return null; }
		else if (type == 'dep' && item.inbound && item.inbound.dest && item.dep != item.inbound.dest) { return null; }
		else if (type == 'dest' && item.inbound && item.inbound.dep && item.dest != item.inbound.dep) { return null; }
		return item;
	},
	validateItem: function (item) {
		if (!this.validateTimes(item)) {
			return false;
		}
		if (!this.validateStops(item)) {
			return false;
		}
		if (!this.validateDates(item)) {
			return false;
		}
		if (!this.validatePrices(item)) {
			return false;
		}
		if (!this.validateDurations(item)) {
			return false;
		}
		if (this.depAirports && !this.depAirports.checkItem(item.dep)) {
			return false;
		}
		if (this.depAirports && item.inbound && item.inbound.dest && !this.depAirports.checkItem(item.inbound.dest)) {
			return false;
		}
		if (this.destAirports && !this.destAirports.checkItem(item.dest)) {
			return false;
		}
		if (this.destAirports && item.inbound && item.inbound.dep && !this.destAirports.checkItem(item.inbound.dep)) {
			return false;
		}
		if (this.operators && !this.operators.checkItem(item.opid)) {
			return false;
		}
		if (this.transportTypes && !this.transportTypes.checkItem(item.transport)) {
			return false;
		}
		if (this.airlines) {
			if (item.aircode && !this.airlines.checkItem(item.aircode)) {
				return false;
			}
			else if (item.outbound && item.outbound.aircode && !this.airlines.checkItem(item.outbound.aircode)) {
				return false;
			}
			else if (item.inbound && item.inbound.aircode && !this.airlines.checkItem(item.inbound.aircode)) {
				return false;
			}
		}
		return true;
	},
	validateTimes: function (item) {
		if (!this.enableTimeFilter) { return true; }
		if (item.outbound) {
			this.validateOptionsTimes(item, item.outbound, this.minDepTime, this.maxDepTime);
			this.validateOptionsTimes(item, item.inbound, this.minRetTime, this.maxRetTime);
			var depHour = parseFloat(item.outbound.time.replace(':', '.'));
			if (depHour < (this.minDepTime != null ? this.minDepTime : 0) || depHour > (this.maxDepTime != null ? this.maxDepTime : 24)) {
				return false;
			}
			if (item.inbound) {
				var retHour = parseFloat(item.inbound.time.replace(':', '.'));
				if (retHour < (this.minRetTime != null ? this.minRetTime : 0) || retHour > (this.maxRetTime != null ? this.maxRetTime : 24)) {
					return false;
				}
			}
		}
		return true;
	},
	validateOptionsTimes: function (item, leg, minTime, maxTime) {
		if (!this.enableTimeFilter) { return true; }
		if (leg && leg.options) {
			var hour;
			if (leg.selectedOption) {
				hour = parseFloat(leg.selectedOption.dep.replace(':', '.'));
				if (hour < (minTime != null ? minTime : 0) || hour > (maxTime != null ? maxTime : 24)) { leg.selectedOption = null; }
			}
			for (var i = 0, len = leg.options.length; i < len; i++) {
				var opt = leg.options[i];
				hour = parseFloat(opt.dep.replace(':', '.'));
				if (hour < (minTime != null ? minTime : 0) || hour > (maxTime != null ? maxTime : 24)) { opt.invalid = true; }
				else {
					opt.invalid = false;
					if (!leg.selectedOption || opt.value < leg.selectedOption.value) {
						leg.selectedOption = opt;
						if (opt.dep) { leg.time = opt.dep; }
						if (opt.arr) { leg.arrive = opt.arr; }
						if (item.outbound && item.outbound.selectedOption) {
							var val = parseFloat(item.outbound.selectedOption.value); var price;
							if (item.inbound) {
								if (item.inbound.selectedOption) {
									val += parseFloat(item.inbound.selectedOption.value);
									price = formatCurrencyFromSettings(val);
									if (price) { item.value = val; item.price = price; }
								}
							}
							else {
								price = formatCurrencyFromSettings(val);
								if (price) { item.value = val; item.price = price; }
							}
						}
					}
				}
			}
		}
	},
	validateDurations: function (item) {
		if (!this.enableDurationFilter) { return true; }
		if (item.outbound) {
			if (item.outbound.durationValue < this.minOutDuration || item.outbound.durationValue > this.maxOutDuration) {
				return false;
			}
			if (item.inbound) {
				if (item.inbound.durationValue < this.minRetDuration || item.inbound.durationValue > this.maxRetDuration) {
					return false;
				}
			}
		}
		return true;
	},
	validateStops: function (item) {
		if (item.outbound) {
			var outStops = (!isNaN(parseInt(item.outbound.stops, 10)) ? parseInt(item.outbound.stops, 10) : 0);
			if ((!this.showNonStop && outStops <= 0) || (!this.show1Stop && outStops == 1) || (!this.show2Stops && outStops >= 2)) {
				return false;
			}
			if (item.inbound) {
				var inStops = (!isNaN(parseInt(item.inbound.stops, 10)) ? parseInt(item.inbound.stops, 10) : 0);
				if ((!this.showNonStop && inStops <= 0 && outStops <= 0) ||
					(!this.show1Stop && inStops == 1 && outStops <= 1) ||
					(!this.show2Stops && inStops >= 2))
					return false;
			}
		}
		return true;
	},
	validateDates: function (item) {
		if (this.dates && !this.dates.checkItem(item.dateId)) { return false; }
		if (this.enableDateFilter) {
			var depDate = parseInt(item.outbound.dateValue.getTime() / msPerDay, 10);
			if (depDate < this.minDepDate || depDate > this.maxDepDate) { return false; }
			if (item.inbound) {
				var retDate = parseInt(item.inbound.dateValue.getTime() / msPerDay, 10);
				if (retDate < this.minRetDate || retDate > this.maxRetDate) { return false; }
			}
		}
		return true;
	},
	validatePrices: function (item) {
		if (this.enablePriceFilter && (item.value < this.minPrice || item.value > this.maxPrice)) { return false; }
		return true;
	},
	reset: function () {
		if (this.depAirports) { this.depAirports.reset(); }
		if (this.destAirports) { this.destAirports.reset(); }
		if (this.operators) { this.operators.reset(); }
		if (this.airlines) { this.airlines.reset(); }
		if (this.transportTypes) { this.transportTypes.reset(); }
		if (this.dates) { this.dates.reset(); }
	},
	clear: function (persistApts) {
		if (this.depAirports) {if (!persistApts) { this.depAirports.clear(); } else { this.depAirports.hideAll(); } }
		if (this.destAirports) { if (!persistApts) {this.destAirports.clear(); } else { this.destAirports.hideAll(); } }
		if (this.operators) { this.operators.clear(); }
		if (this.airlines) { this.airlines.clear(); }
		if (this.transportTypes) { this.transportTypes.clear(); }
		if (this.dates) { this.dates.clear(); }
	},
	render: function (mgr, excludeType) {
		if (mgr && mgr.render) {
			if (this.depAirports && excludeType != 'dep') { mgr.render.renderAirports(mgr, this.depAirports, true); }
			if (this.destAirports && excludeType != 'dest') { mgr.render.renderAirports(mgr, this.destAirports, false); }
			if (this.operators && excludeType != 'op') { mgr.render.renderOperators(mgr, this.operators); }
			if (this.dates && excludeType != 'date') { mgr.render.renderDates(mgr, this.dates); }
			if (this.airlines && excludeType != 'airline') { mgr.render.renderAirlines(mgr, this.airlines); }
			if (excludeType != 'transport') {
				var row = (mgr.transportRow ? $(mgr.transportRow) : null);
				if (this.transportTypes) {
					if (row && row.get(0) != document) { row.css('display', (this.transportTypes.count > 1 ? '' : 'none')); }
					if (this.transportTypes.count > 1) { mgr.render.renderTransport(mgr, this.transportTypes); }
				}
				else if (row && row.get(0) != document) { row.css('display', 'none'); }
			}
		}
	}
});

var filterGroup = $.Class.create({
	items:null,
	ids:null,
	elementId:null,
	element:null,
	renderer:false,
	defaultCheck:false,
	cheapestElement:null,
	count:0,
	init: function(elem, renderer){
		this.items = {};
		this.ids = [];
		this.elementId = elem;
		this.renderer = renderer;
		this.cheapestElement = {id:null,value:null};
	},
	addItem: function(id, item, validItem, mapItem, properties){
		if(!this.items[id]){
			this.items[id] = new filterItem(id, item, validItem, mapItem, properties);
			this.ids.push(id);
			this.count++;
		}
		else{
			this.items[id].setCheapestItem(item, validItem, mapItem);
			this.items[id].visible = true;
		}
		if(validItem != null && (this.cheapestElement.value == null || validItem.value < this.cheapestElement.value)){
			this.cheapestElement.id = id;
			this.cheapestElement.value = validItem.value;
		}
	},
	checkItem: function(id){
		if(this.items[id]){ return this.items[id].check(); }
		return this.defaultCheck;
	},
	getItem: function(id){
		if(this.items[id]){ return this.items[id]; }
		return null;
	},
	setItem: function(id, enabled){
		if(id == '#all#'){ this.setAll(enabled); }
		else if(this.items[id]){ this.items[id].enabled = enabled; }
	},
	reset: function(){
		for(var prop in this.items){
			if(this.items[prop]){
				this.items[prop].visible = true;
				this.items[prop].cheapestItem = null;
			}
		}
	},
	clear: function(){
		this.items = {};
		this.ids = [];
	},
	resetCheapestItem: function(){
		for(var prop in this.items){
			if(this.items[prop]){
				this.items[prop].cheapestItem = null;
			}
		}
	},
	hideAll: function () {
		for (var prop in this.items) {
			var item = this.items[prop]
			if (item) {
				item.visible = false;
				item.clearCheapestItem();
			}
		}
	},
	setAll: function (checked) {
		for(var prop in this.items){
			if(this.items[prop]){
				this.items[prop].enabled = checked;
			}
		}
	},
	isCheapestElement: function(id){
		if(this.ids.length > 1 && this.cheapestElement.id == id){ return true; }
		return false;
	},
	writeHtml: function(html){
		if(!this.element){ this.element = getElement(this.elementId); }
		if(this.element){
			this.element.innerHTML = html;
			if(typeof(CustomForms) != 'undefined'){ CustomForms.init(this.element); }
		}
	}
});

var filterItem = $.Class.create({
	id:null,
	enabled:true,
	visible:true,
	mapItem:null,
	cheapestItem:null,
	cheapestOverall:null,
	properties:null,
	init: function(id, item, validItem, mapItem, properties){
		this.id = id;
		this.cheapestItem = validItem;
		this.cheapestOverall = item;
		if(properties){
			this.properties = properties;
			if(this.properties.enabled != null){ this.enabled = this.properties.enabled; }
			if(this.properties.visible != null){ this.visible = this.properties.visible; }
		}
	},
	setCheapestItem: function(item, validItem, mapItem){
		if(!this.cheapestItem || (validItem && validItem.value < this.cheapestItem.value)){
			this.cheapestItem = validItem;
		}
		if(!this.cheapestOverall || (item && item.value < this.cheapestOverall.value)){
			this.cheapestOverall = item;
		}
		if(!this.mapItem || (mapItem && mapItem.value < this.mapItem.value)){
			this.mapItem = mapItem;
		}
	},
	clearCheapestItem: function () {
		this.cheapestItem = null;
		this.cheapestOverall = null;
		this.mapItem = null;
	},
	check: function () { return (this.enabled && this.visible); }
});

