﻿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 = 1250;
var other_op_code = '$X';

var getElement = function(id){ return (document.all ? document.all[id] : document.getElementById(id)); }

Array.prototype.insert = function(pos, newValue){
	if(pos > -1 && pos < this.length)
		this.splice(pos, 0, newValue);
	else
		this.push(newValue);
};

Array.prototype.duffArray = function(obj, func){
	var iterations = Math.floor(this.length / 8);
	var leftover = this.length % 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){
	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){
		var len = this.length;
		for(var i = 0; 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);
	var len = parts.length;
	for(var i = 0; 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){
			var id = elements[prop];
			if(id){
				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){
			if(mgr.isGroup){
				var sorter = this;
				var len = mgr.unfiltered.length;
				for(var i = len; 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{
				var sorter = this;
				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);
		return this.compare(x.value, y.value);
	},
	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);
	},
	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;
			default:
				return this.compareValue;
		}
	}
});

var viewManager = $.Class.create({
	activeView:null,
	items:null,
	onResultsAdded:null,
	init: function(o){
		this.items = new Object();
	},
	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); }
		}
	},
	refresh: function(){
		if(this.activeView){
			this.activeView.refresh();
			this.activeView.refreshSliders();
		}
	},
	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);
			}, 250);
		}
	},
	timesChanged: function(id, hnd, val){
		if(id[0] != '#'){ id = '#' + id; }
		if(this.activeView){
			this.activeView.timesChanged(id, hnd, val);
			this.activeView.refresh();
		}
	},
	setFilter: function(type, id, checked, inbound){
		if(this.activeView){ this.activeView.setFilter(type, id, checked, inbound); }
	},
	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); }
	}
});

var pageView = $.Class.create({
	id:null,
	panels:null,
	tab:null,
	outboundMgr:null,
	inboundMgr:null,
	sorters:new Object(),
	onflightsadded:null,
	onshow:null,
	properties:new Object(),
	renderOverride:null,
	onFilter:null,
	isGrouped:false,
	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.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();
		}
		this.refreshSliders();
		if(this.tab){$(this.tab).attr('class','selectedTab');}
		$.each(this.panels, function(index, value){ $(value).css('display',''); });
		if(!norefresh){ this.refresh(); }
		if(this.onshow){ this.onshow(this); }
	},
	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','');}
	},
	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); }
	},
	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);
		}
	},
	refresh: function(timeout){
		if(this.outboundMgr){ this.outboundMgr.startRender(timeout); }
		if(this.inboundMgr){ this.inboundMgr.startRender(timeout); }
	},
	setFilter: function(type, id, checked, inbound){
		if(!inbound && this.outboundMgr){ this.outboundMgr.setFilter(type, id, checked); }
		else if(this.inboundMgr){ this.inboundMgr.setFilter(type, id, checked); }
	},
	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();
		}
	},
	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(); }
	}
});

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;
		if(this.onEndpointChanged){ this.onEndpointChanged(this, true); }
		viewMgr.showView(this.id, true);
	},
	showDestinations: function(){
		this.isDeparture = false;
		this.iata = null;
		if(this.onEndpointChanged){ this.onEndpointChanged(this, true); }
		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){
			var arr = mgr.getAirports();
			for(var i = 0; i < arr.length; i++){
				var marker = arr[i];
				var dataItem = marker.item.cheapestItem;
				var code = marker.item.id;
				var apt = mgr.getAirport(code);
				this.map.updateMarkers({
					id: code, img: (dataItem ? mgr.render.getPinImage(apt.type) : null),
					width: 20, height: 34, lat: apt.lat, lon: apt.lon,
					html: this.getMapHtml(dataItem, mgr, marker.isDep),
					title: mgr.getAptName(code), visible: marker.item.check()
				});
			}
		}
	},
	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 == '2') { taxHtml = TXT_EXCLUDING_TICKET_EMISSION; }
		else if (val == '3') { taxHtml = TXT_APPROX_PRICE; }
		else { taxHtml = TXT_TAX_INCLUDED; strCss = 'txtGreen' }

		if (taxHtml != '') { taxHtml = '<span class="' + strCss + '">' + taxHtml + '</span>'; }
		return taxHtml;
	},
	getRedirect: function(item) {
		var outIATA = (item.operator.dep ? item.operator.dep : item.dep);
		var inIATA = (item.operator.dest ? item.operator.dest : item.dest);
		var url = REDIRECT_PATH;
		url += '?opid=' + item.opid;
		url += '&url=' + (item.url ? encodeURIComponent(item.url) : '');
		url += '&DepartAirport=' + outIATA;
		url += '&DestinationAirport=' + inIATA;
		url += '&Adults=' + searchSettings.adults;
		url += '&Children=' + searchSettings.children;
		url += '&Infants=' + searchSettings.infants;
		url += '&DepartureDate=' + (item.outbound ? encodeURIComponent(item.outbound.date) : '');
		url += '&ReturnDate=' + (item.inbound ? encodeURIComponent(item.inbound.date) : '');
		if (BUSINESS_CLASS != "Economy") { url += '&BusinessClass=true'; }
		return url;
	},
	getLastUpdated: function(item) {
		var html = '';
		try {
			if (item.tax == 3) {
				html = '<img src=' + IMG_ROOT + 'i/warning.gif width=11 height=10 border=0 align=absmiddle> ' + TXT_TO_BE_VERIFIED;
			}
			else if (item.updated != null && server_time != null) {
				var timeSpan = server_time.subtractTime(item.updated);
				var updatedText = TXT_LAST_UPDATED + ': ';
				var updatedImg = '<img src=' + IMG_ROOT + 'i/clock3.gif width=11 height=11 border=0 align=absmiddle>';

				if (timeSpan.days > 0)
					updatedText += TXT_DAYS_AGO.replace('%1', timeSpan.days);
				else if (timeSpan.hours > 0)
					updatedText += TXT_HOURS_AGO.replace('%1', timeSpan.hours);
				else if (timeSpan.minutes > 0)
					updatedText += TXT_MINS_AGO.replace('%1', timeSpan.minutes);
				else {
					updatedText = TXT_VERIFIED_AVAILABILITY;
					updatedImg = '<img src=' + IMG_ROOT + 'i/tick-green.gif width=14 height=15 border=0 align=absmiddle>';
				}

				html = updatedImg + ' ' + updatedText;
			}
			else {
				html = '<img src=' + IMG_ROOT + 'i/tick-green.gif width=14 height=15 border=0 align=absmiddle> ' + TXT_VERIFIED_AVAILABILITY;
			}
		} 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;
	},
	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; i < ids.length; i++) {
			var id = ids[i];
			var item = filter.items[id];
			if (item && item.visible) {
				var redirect = (item.cheapestItem ? this.getRedirect(item.cheapestItem) : '');
				var labelcss = (item.cheapestItem ? 'opNameLabel' : 'filterLabelOff');
				html += '<tr><td width="14" valign="middle">' +
					'<input type="checkbox" value="' + id + '" ' + (item.enabled ? 'checked' : '') + ' onclick="' + func + '"/>' +
					'</td><td valign="middle" class="' + labelcss + '">' +
					'<a target="_blank" href="' + redirect + '">' + mgr.getOperator(id) + '</a>' +
					'</td><td valign="middle" align="right" nowrap>' + this.renderPriceLink(item.cheapestItem) + '</td></tr>';
			}
		}
		html += '</table>';
		filter.writeHtml(html);
	},
	renderAirports: function(mgr, filter, isDep) {
		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; i < ids.length; 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 ? 'opNameLabel' : 'filterLabelOff');
				html += '<tr><td width="14" valign="middle">' +
					'<input type="checkbox" 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; i < ids.length; i++) {
			var id = ids[i];
			var item = filter.items[id];
			if (item && item.visible) {
				var redirect = (item.cheapestItem ? this.getRedirect(item.cheapestItem) : '');
				var labelcss = (item.cheapestItem ? 'opNameLabel' : 'filterLabelOff');
				var nameFunc = "viewMgr.setFilter('airline','" + id + "','toggle'," + (mgr.inbound ? "true" : "false") + ")";
				html += '<tr><td width="14" valign="middle">' +
					'<input type="checkbox" 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; i < ids.length; i++) {
			var id = ids[i];
			var item = filter.items[id];
			if (item && item.visible) {
				var labelcss = (item.cheapestItem ? 'opNameLabel' : 'filterLabelOff');
				html += '<tr><td width="14" valign="middle">' +
					'<input type="checkbox" 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) + '</td></tr>';
			}
		}
		html += '</table>';
		filter.writeHtml(html);
	},
	renderPriceLink: function(item) {
		var html = '';
		if (item) { html = '<a target="_blank" href="' + this.getRedirect(item) + '"><span>' + 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.isGrouped ? mgr.groupMgr.filtered : mgr.filteredResults);
			var numResults = (count ? count : filteredArray.length);
			var html = '';
			var clickFunc = '';
			var pages = Math.ceil(numResults / mgr.pagesize);
			var minPage = Math.min(mgr.page - 5, pages - 10);
			minPage = Math.max(minPage, 1);
			for (var i = minPage; i <= minPage + 10 && i <= pages; i++) {
				if (mgr.page == i) {
					html += '&nbsp;<span class="ChangePageSelected"><b>' + i + '</b></span>&nbsp;';
				}
				else {
					var func = "viewMgr.setPageNumber(" + i + "," + (mgr.inbound ? "true" : "false") + ")";
					html += '&nbsp;<a class="ChangePage" onclick="' + func + '">' + i + '</a>&nbsp;';
				}
			}
			clickFunc = "viewMgr.setPageNumber(1," + (mgr.inbound ? "true" : "false") + ")";
			var goFirst = mgr.page > 6 && pages > 11 ? '&nbsp;<a class="ChangePage" onclick="' + clickFunc + '">' + TXT_FIRST + '</a>&nbsp;' : '';

			clickFunc = "viewMgr.setPageNumber(" + pages + "," + (mgr.inbound ? "true" : "false") + ")";
			var goLast = mgr.page < pages - 10 ? '&nbsp;<a class="ChangePage" onclick="' + clickFunc + '">' + TXT_LAST + '</a>' : '';

			elem.html(goFirst + html + goLast);
		}
	},
	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; i < ids.length; i++) {
			var id = ids[i];
			var item = filter.items[id];
			if (item && item.visible) {
				html += '<tr><td width="14" valign="middle">' +
					'<input type="checkbox" value="' + id + '" ' + (item.enabled ? 'checked' : '') + ' onclick="' + func + '"/>' +
					'</td><td width="18" valign="middle">' +
					'<img height="16" width="16" src="' + IMG_ROOT + 'i/transport/' + 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 html = '<div class="mapHeader"><div class="mapHeadLeft2">';
		html += '<img hspace="4" height="18" width="12" align="absmiddle" src="' + this.getPinImage(apt.type, true) + '"/>';
		html += mgr.getAptName(iata) + ", " + apt.country + '</div>';
		if (apt.type == transport.AIR && 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>';
		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) {
		if (type == transport.TRAIN) { return 'rail-sm.gif'; }
		else if (type == transport.BUS) { return 'bus-sm.gif'; }
		else if (type == transport.FERRY) { return 'ferry-sm.gif'; }
		else { return 'plane-sm.gif'; }
	},
	getPinImage: function(type, small) {
		var path = IMG_ROOT + 'i/map/';
		if (type == transport.TRAIN) { return path + (small ? 'rail_sml.gif' : 'rail.png'); }
		else if (type == transport.BUS) { return path + (small ? 'bus_sml.gif' : 'bus.png'); }
		else if (type == transport.FERRY) { return path + (small ? 'ferry_sml.gif' : 'ferry.png'); }
		else { return path + (small ? 'apt_sml.gif' : 'apt.png'); }
	},
	getIconImage: function(mgr, code, out) {
		var path = IMG_ROOT + 'i/grouping/';
		var apt = mgr.getAirport(code);
		if (apt.type == transport.TRAIN) { return path + (out ? 'train_out.gif' : 'train_in.gif'); }
		else if (apt.type == transport.BUS) { return path + (out ? 'bus2_out.gif' : 'bus2_in.gif'); }
		else if (apt.type == transport.FERRY) { return path + (out ? 'ferry.gif' : 'ferry.gif'); }
		else { return path + (out ? 'out.gif' : 'ret.gif'); }
	},
	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 += '</table><div style="padding-top:4px;">' + this.getLastUpdated(item) + '</div>';
		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 = document.URL;
				if (updateUrl.indexOf('noCache') < 0) { updateUrl += '&noCache=true'; }
				html = '<img height="11" width="11" border="0" align="absmiddle" src="' + IMG_ROOT + 'i/update.gif"/> ' +
					'<a class="UpdateLink" href="' + updateUrl + '">' + TXT_UPDATE + '</a>';
			}
		} 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){
				var txt = new String();
				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; i < group.filtered.length; 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;
	}
});

var flightGroupManager = $.Class.create({
	isGroup:true,
	groups:null,
	sorter:null,
	filter:null,
	filtered:null,
	unfiltered:null,
	init: function(filter){
		this.groups = new Object();
		this.filtered = new Array();
		this.unfiltered = new Array();
		this.filter = filter;
	},
	setSorter: function(sorter){
		this.sorter = sorter;
	},
	addFlight: function(flight){
		var group = this.groups[flight.groupId];
		if(group){
			var result = group.addFlight(flight);
			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.isValid()){ this.filtered.binaryInsert(group, this.sorter); }
		}
	},
	filterResults: function(doFullResults, filtersOk){
		var arr = (doFullResults ? this.unfiltered : this.filtered);
		this.filtered = new Array();
		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); }
	},
	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 = new Object();
		this.flights = new Array();
		this.filtered = new Array();
		this.sorter = sorter;
		this.filter = filter;
		this.groupId = flight.groupId;
		this.addFlight(flight);
	},
	addFlight: function(flight){
		var result = -1;
		if(!this.opids[flight.opid]){
			this.opids[flight.opid] = flight.operator.name;
			this.flights.binaryInsert(flight, this.sorter);
			if(!this.filter || this.filter.validateItem(flight)){
				result = this.filtered.binaryInsert(flight, this.sorter);
			}
		}
		return result;
	},
	isValid: function(){
		if(this.filtered && this.filtered.length > 0){ return true; }
		else{ return false; }
	},
	filterResults: function(){
		var arr = this.flights;
		this.filtered = new Array();
		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,
	bestOp:null,
	useBestOp:true,
	render_queue:0,
	groupMgr:null,
	isGrouped:null,
	init: function(o, view, inbound){
		this.visible = false;
		this.airports = new Object();
		this.operators = new Object();
		this.airlines = new Object();
		this.flights = new Array();
		this.view = view;
		this.isGrouped = view.isGrouped;
		this.filteredResults = new Array();
		if(o != null){
			this.filter = new filterManager(o.filters);
			this.sliders = o.sliders;
			var str = new String();
			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(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.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); }
		}
	},
	addResults: function(result){
		if(result.operator){
			this.addOperator(result.operator);
		}
		else if(result.operators){
			var len = result.operators.length;
			for(var i = len; i--;){
				this.addOperator(result.operators[i]);
			}
		}
		var len = result.airports.length;
		for(var i = len; i--;){
			this.addAirport(result.airports[i]);
		}
		for(var prop in result.airlines){
			if(!this.airlines[prop]){ this.airlines[prop] = result.airlines[prop]; }
		}
		var len = result.flights.length;
		for(var i = len; i--;){
			var item = result.flights[i];
			item.updated = new Date((item.updated ? item.updated : result.updated));
			item.operator = (result.operator ? result.operator : this.operators[item.opid]);
			item.transport = this.getTransportType(item.operator);
			if(item.outbound){
				var outleg = item.outbound;
				outleg.dateValue = Date.parseDate(outleg.date);
				if(outleg.aircode && outleg.aircode != other_op_code && this.airlines[outleg.aircode]){
					outleg.airline = this.airlines[outleg.aircode].name;
				}
			}
			if(item.inbound){
				var inleg = item.inbound;
				inleg.dateValue = Date.parseDate(inleg.date);
				if(inleg.aircode && inleg.aircode != other_op_code && this.airlines[inleg.aircode]){
					inleg.airline = this.airlines[inleg.aircode].name;
				}
			}
			item.dateId = this.getDateId(item);
			this.addFlight(item);
			if(!this.filter || this.filter.validateItem(item)){
				this.filteredResults.binaryInsert(item, this.sorter);
			}
		}
	},
	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){ this.filter.addFilter(item, this.inbound); }
		if(this.isGrouped){ this.groupMgr.addFlight(item); }
		this.flights.binaryInsert(item, this.sorter);
		if(!this.cheapestItem || item.value < this.cheapestItem.value){
			this.cheapestItem = 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); }
	},
	filterUngrouped: function(doFullResults, filtersOk){
		var arr = (doFullResults ? this.flights : this.filteredResults);
		this.filteredResults = new Array();
		if(this.filter && !filtersOk){ this.filter.reset(); }
		var len = arr.length;
		for(var i = 0; 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){
		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); }
			pageManager.showLoadingScreen(false);
		};
		setTimeout(doFilter, 250);
	},
	refreshSliders: function(){
		if(!this.sliders){ return; }
		var depTime = (this.sliders.depTime ? $(this.sliders.depTime.id) : null);
		if(depTime && depTime.slider && depTime.width() > 0 && this.filter){
			var minval = (this.filter.minDepTime != null ? this.filter.minDepTime : 0);
			var maxval = (this.filter.maxDepTime != null ? this.filter.maxDepTime : 24);
			depTime.slider('moveTo',minval,0,true);
			$(this.sliders.depTime.minlabel).html((minval < 10 ? '0' + minval.toString() : minval.toString())+':00');
			depTime.slider('moveTo',maxval,1,true);
			$(this.sliders.depTime.maxlabel).html((maxval < 10 ? '0' + maxval.toString() : maxval.toString())+':00');
		}
		var retTime = (this.sliders.retTime ? $(this.sliders.retTime.id) : null);
		if(retTime && retTime.slider && retTime.width() > 0 && this.filter){
			var minval = (this.filter.minRetTime != null ? this.filter.minRetTime : 0);
			var maxval = (this.filter.maxRetTime != null ? this.filter.maxRetTime : 24);
			retTime.slider('moveTo',minval,0,true);
			$(this.sliders.retTime.minlabel).html((minval < 10 ? '0' + minval.toString() : minval.toString())+':00');
			retTime.slider('moveTo',maxval,1,true);
			$(this.sliders.retTime.maxlabel).html((maxval < 10 ? '0' + maxval.toString() : maxval.toString())+':00');
		}
	},
	timesChanged: function(id, hnd, val){
		if(!this.sliders){ return; }
		this.premiumOp = null;
		this.bestOp = null;
		this.useBestOp = false;
		if(this.sliders.depTime && this.sliders.depTime.id == id){
			if(this.sliders.depTime.min == hnd){
				this.page = 1;
				this.filter.minDepTime = val;
				this.startFilter(true, false, true);
			}
			else if(this.sliders.depTime.max == hnd){
				this.page = 1;
				this.filter.maxDepTime = val;
				this.startFilter(true, false, true);
			}
		}
		if(this.sliders.retTime && this.sliders.retTime.id == id){
			if(this.sliders.retTime.min == hnd){ this.filter.minRetTime = val; this.startFilter(true, false, true); }
			else if(this.sliders.retTime.max == hnd){ this.filter.maxRetTime = val; this.startFilter(true, false, true); }
		}
	},
	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(typeof(this.resultsCount) == 'string'){
			if(this.resultsCount.charAt(0) == '#'){ this.resultsCount = this.resultsCount.substr(1); }
			this.resultsCount = getElement(this.resultsCount);
		}
		this.resultsCount.innerHTML = html;
	},
	renderResults: function(){
		if(this.renderOverride){ return this.renderOverride(); }
		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('<div class="ResultDiv"><div class="ErrorMessage">' + msg + '</div></div>');
				}
			}
			else{
				var resultsHtml = '';
				var premiumOffer = null;
				if(this.premiumOp && this.filter && this.filter.operators){
					var premium;
					if(typeof(this.premiumOp) == 'number'){
						premium = this.filter.operators.items[this.premiumOp];
						if(premium && premium.check()){
							var item = premium.cheapestItem;
							if(item && this.filter.validateItem(item)){ premiumOffer = item; }
						}
					}
					else {
						var len = this.premiumOp.length;
						for(var i = len; i--;){
							var premium = this.filter.operators.items[this.premiumOp[i]];
							if(premium && premium.check() && premium.cheapestItem){
								var item = premium.cheapestItem;
								if(this.filter.validateItem(item) && (premiumOffer == null || item.value < premiumOffer.value)){ premiumOffer = item; }
							}
						}
					}
					if(!premiumOffer && this.bestOp && this.useBestOp){
						premium = this.filter.operators.items[this.bestOp.opid];
						if(premium && premium.check()){
							var item = premium.cheapestItem;
							if(item && this.filter.validateItem(item)){ premiumOffer = item; }
						}
					}
				}
				var maxItems = this.pagesize;
				var rendered = 0;
				if(premiumOffer){
					resultsHtml += flightTemplate.apply({item:premiumOffer, mgr:this, render:this.render, premium:true, size:1});
					rendered++;
				}
				var len = data.length;
				for(var i = 0; i < len && rendered < maxItems; i++){
					var result = data[i];
					if(this.isGrouped || (!this.isGrouped && result != 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, size:itemSize});
						rendered++;
					}
				}
				if(resultsHtml.length == 0 && pageManager.searchFinished){
					var msg = (this.flights.length == 0 ? TXT_NO_RESULTS_MSG : TXT_NO_RESULTS);
					resultsHtml = '<div class="ResultDiv"><div class="ErrorMessage">' + msg + '</div></div>';
				}
				this.setResultsHtml(resultsHtml);
			}
			if(this.render){
				var filteredArray = (this.isGrouped ? this.groupMgr.filtered : this.filteredResults);
				var unfilteredArray = (this.isGrouped ? this.groupMgr.unfiltered : this.flights);
				this.setResultsCount(this.render.getResultCounts(filteredArray.length, unfilteredArray.length, this.operatorCount));
			}
			if(this.render){ this.render.renderPaging(this); }
			this.updating = false;
		}
	},
	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;
			}
		};
		setTimeout(doRender, t);
	},
	getPageResults: function(){
		var filteredArray = (this.isGrouped ? this.groupMgr.filtered : this.filteredResults);
		if(!filteredArray){ this.filterResults(true, false); }
		var data = null;
		filteredArray = (this.isGrouped ? this.groupMgr.filtered : this.filteredResults);
		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); }
		};
		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 && 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){
		var aptname = '';
		if(this.airports[code]){
			var apt = this.airports[code];
			aptname = apt.city;
			if(apt.name && apt.name.length > 0){ aptname += ' ' + apt.name; }
		}
		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(opid){
		var html = '';
		var op = this.operators[opid];
		if(op){
			var style = "background-color:" + (op.bgcolor ? op.bgcolor : '#FFFFFF') + ';' +
				"color:" + (op.textcolor ? op.textcolor : '#000000') + ';'
			html = '<div class="opBtn" style="' + style + '">' + op.name + '</div>';
		}
		return html;
	},
	getDistance: function(lat1, lon1, lat2, lon2){
		var 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 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){
		if(this.filter){
			this.premiumOp = null;
			this.bestOp = null;
			this.useBestOp = false;
			this.page = 1;
			var filterItem = this.filter.getFilterItem(type, id);
			if(checked == 'toggle'){ checked = filterItem.enabled = !filterItem.enabled; }
			this.filter.setFilter(type, id, checked);
			if(!((type == 'op' || type == 'date') && filterItem != null && filterItem.cheapestItem == null)){
				this.startFilter(true, false, true);
			}
		}
	},
	isSearchDate: function(item){
		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));
	},
	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.value != this.pagesize && elem.options){
				var len = elem.length;
				for(var i = len; 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(){
		var apts = new Array();
		if(!this.filter){ return apts; }
		if(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(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')); }
	}
});

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.chart.addItem(item);
	},
	loadResults: function(){
		pageManager.showLoadingScreen(true);
		this.flights = new Array();
		this.filteredResults = new Array();
		this.filter.reset();
		this.filter.resetTimes();
		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.chart.setMonthYear(this.month, this.year);
		this.loadResults();
	},
	prevMonth: function(){
		this.day = null;
		this.month--;
		if(this.month < 1){
			this.month = 12;
			this.year--;
		}
		this.chart.setMonthYear(this.month, this.year);
		this.loadResults();
	},
	setDate: function(day){
		this.day = day;
		this.chart.setSelectedDay(this.day);
		this.loadResults();
	},
	getTooltipHtml: function(index){
		var html = '', opDetail = '', apts = '';
		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,
	minDepTime:null,
	maxDepTime:null,
	minRetTime:null,
	maxRetTime: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;
			}
		}
	},
	addFilter: function(item, inbound){
		if(item){
			this.setTimes(item);
			if(this.depAirports){
				this.depAirports.addItem(item.dep, null);
				if(item.inbound && item.inbound.dest){ this.depAirports.addItem(item.inbound.dest, null); }
			}
			if(this.destAirports){
				this.destAirports.addItem(item.dest, null);
				if(item.inbound && item.inbound.dep){ this.destAirports.addItem(item.inbound.dep, null); }
			}
			if(this.operators){ this.operators.addItem(item.opid, null); }
			if(this.airlines){
				if(item.outbound && item.outbound["aircode"]){ this.airlines.addItem(item.outbound.aircode, null); }
				if(item.inbound && item.inbound["aircode"]){ this.airlines.addItem(item.inbound.aircode, null); }
			}
			if(this.transportTypes){ this.transportTypes.addItem(item.transport, null); }
			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, properties);
			}
			this.updateFilter(item);
		}
	},
	updateFilter: function(item){
		var validation = this.getItemValidation(item);
		if(validation.time){
			if(this.transportTypes){ this.transportTypes.addItem(item.transport, this.getValidItem(item, 'transport', validation)); }
			if(validation.transport){
				if(this.dates){ this.dates.addItem(item.dateId, this.getValidItem(item, 'date', validation)); }
				if(validation.date){
					if(this.depAirports){
						this.depAirports.addItem(item.dep, this.getValidItem(item, 'dep', validation));
						if(item.inbound && item.inbound.dest){ this.depAirports.addItem(item.inbound.dest, this.getValidItem(item, 'dep', validation)); }
					}
					if(this.destAirports){
						this.destAirports.addItem(item.dest, this.getValidItem(item, 'dest', validation));
						if(item.inbound && item.inbound.dep){ this.destAirports.addItem(item.inbound.dep, this.getValidItem(item, 'dest', validation)); }
					}
					if(this.operators){ this.operators.addItem(item.opid, this.getValidItem(item, 'operator', validation)); }
					if(this.airlines){
						if(item.outbound && item.outbound["aircode"]){ this.airlines.addItem(item.outbound.aircode, this.getValidItem(item, 'airline', validation)); }
						if(item.inbound && item.inbound["aircode"]){ this.airlines.addItem(item.inbound.aircode, 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; }
		}
	},
	resetTimes: function(){
		this.minDepTime = null;
		this.maxDepTime = null;
		this.minRetTime = null;
		this.maxRetTime = null;
	},
	getItemValidation: function(item){
		var validation = {time:true,date:true,dep:true,dest:true,operator:true,transport:true,airline:true,isvalid:true};
		if(!this.validateTimes(item)){
			validation.time = false;
			validation.isvalid = false;
		}
		if(!this.validateDates(item)){
			validation.date = 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 && item.outbound && item.outbound["aircode"] && !this.airlines.checkItem(item.outbound.aircode)){
			validation.airline = false;
			validation.isvalid = false;
		}
		if(this.airlines && 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; }
		else if(type != 'date' && !validation.date){	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; }
		return item;
	},
	validateItem: function(item){
		if(!this.validateTimes(item)){
			return false;
		}
		if(!this.validateDates(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 && item.outbound && item.outbound["aircode"] && !this.airlines.checkItem(item.outbound.aircode)){
			return false;
		}
		if(this.airlines && item.inbound && item.inbound["aircode"] && !this.airlines.checkItem(item.inbound.aircode)){
			return false;
		}
		return true;
	},
	validateTimes: function(item){
		if(item.outbound){
			var depHour = parseFloat(item.outbound.time.replace(':','.'));
			if(depHour < (this.minDepTime != null ? this.minDepTime : 0) || depHour > (this.maxDepTime != null ? this.maxDepTime : 24))
				return false;

			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 retHour = parseFloat(item.inbound.time.replace(':','.'));
				if(retHour < (this.minRetTime != null ? this.minRetTime : 0) || retHour > (this.maxRetTime != null ? this.maxRetTime : 24))
					return false;

				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){
			if(!this.dates.checkItem(item.dateId))
				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(); }
	},
	render: function(mgr){
		if(mgr && mgr.render){
			if(this.depAirports){ mgr.render.renderAirports(mgr, this.depAirports, true); }
			if(this.destAirports){ mgr.render.renderAirports(mgr, this.destAirports, false); }
			if(this.operators){ mgr.render.renderOperators(mgr, this.operators); }
			if(this.dates){ mgr.render.renderDates(mgr, this.dates); }
			if(this.airlines){ mgr.render.renderAirlines(mgr, this.airlines); }

			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,
	count:0,
	init: function(elem, renderer){
		this.items = new Object();
		this.ids = new Array();
		this.elementId = elem;
		this.renderer = renderer;
	},
	addItem: function(id, item, properties){
		if(!this.items[id]){
			this.items[id] = new filterItem(id, item, properties);
			this.ids.push(id);
			this.count++;
		}
		else{
			this.items[id].setCheapestItem(item);
			this.items[id].visible = true;
		}
	},
	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;
			}
		}
	},
	resetCheapestItem: function(){
		for(var prop in this.items){
			if(this.items[prop]){
				this.items[prop].cheapestItem = null;
			}
		}
	},
	setAll: function(checked){
		for(var prop in this.items){
			if(this.items[prop]){
				this.items[prop].enabled = checked;
			}
		}
	},
	writeHtml: function(html){
		if(!this.element){ this.element = getElement(this.elementId); }
		if(this.element){ this.element.innerHTML = html; }
	}
});

var filterItem = $.Class.create({
	id:null,
	enabled:true,
	visible:true,
	cheapestItem:null,
	properties:null,
	init: function(id, cheapestItem, properties){
		this.id = id;
		this.cheapestItem = cheapestItem;
		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){
		if(!this.cheapestItem || (item && item.value < this.cheapestItem.value)){
			this.cheapestItem = item;
		}
	},
	check: function(){
		return (this.enabled && this.visible);
	}
});
