// ********** variables and constants **********

var supplierLogos = true; // show supplier logos
var airlineLogos = false; // show airline logos
var enablePin = false; // enable/disable pinned flights
var enhanceSegments = true; // enhance matching segments with data from other suppliers

var dayNames = null;
var monthNames = null;

var resultsPerPage = 15;
var pages = 0;
var curPage = 0;
var curView = 0; // current View number - see selectView
var supplierView = true;
var searching = false; // current state of search
var flightsScrolled = false;

var flights = []; // contains all flights
var currentflights = null; // contains currently visible flights
var flightgroups = null; // contains flight groups (similar flights with same key)
var grouped = null; // contains grouped flights (grouped by user selected field)
var groupstate = new Dictionary(); // contains state information about groupings
var pinnedflights = null;
var cheapestFlight = null;
var topAdSuppliers = null;
var combiOutSegs = [];
var combiRetSegs = [];
var combiFlight = null;

var updateFilters = false;
var flgStatusLevel = 0;

var supplierList = new Dictionary(); // contains suppliers and additional info
var supplierIataList = new Dictionary();
var suppliers = new Dictionary(); // contains suppliers
var airlines = new Dictionary(); // contains airlines
var tickets = new Dictionary(); // contains ticket classes
var origs = new Dictionary(); // contains origins
var dests = new Dictionary(); // contains destinations
var innovata = [];
var updatingSuppliers = new Hash();
var routeSuppliers = [];
var routeSuppliersIndex = new Hash();

var searchorig = null;
var searchdest = null;
var searchoneway = false;
var searchdepdate = null;
var searchretdate = null;
var mainorig = null;
var maindest = null;

var curCurrency = 'EUR';

var groupField = 'supplier';
var sortField = 'price';
var sortDirection = 1;  // ascending = 1, descending = -1

var minPrice = 999999;
var maxPrice = 0;
var sumPrice = 0;
var matchCount = 0;

var filterMinPrice = 0;
var filterMaxPrice = 100000;
var filterMinStops = 0;
var filterMaxStops = 10;
var filterMinOutDepTime = 0;
var filterMaxOutDepTime = 1440;
var filterMinRetDepTime = 0;
var filterMaxRetDepTime = 1440;

var filterPriceRangeCount = 4;
var filterPriceRange = 0;
var filterOutTime = 0;
var filterRetTime = 0;

var filterSupplier = [];
var filterAirline = [];
var filterTicket = [];
var filterOrig = [];
var filterDest = [];
var filterPriceRanges = [];
var filterPriceRangesText = [];

var appPath = '';
var themePath = '';
var imagePath = '';
var logoPath = '';
var iconPath = '';
var flagPath = '';

var isCPH = false;

function checkCPH(orig, supplierId, type)
{
	if (!isCPH)
		return true;
		
	var exclude = (searchorig == 'CPH' && orig != 'CPH');
	if (!exclude)
	{
		if (type)
		{
			exclude = (type == 3);
		}
		else
		{
			var s = getSupplier(supplierId);
			if (s)
				exclude = (s.type == 3); 
		}
	}
	return !exclude;
}

setAppPath('');
function setAppPath(path)
{
	appPath = path;
	themePath = appPath + "/themes/momondo/";
	imagePath = appPath + "/themes/momondo/images/skygate/";
	logoPath = appPath + "/logos/";
	iconPath = appPath + "/icons/";
	flagPath = appPath + "/flags/";
}

// ********** interface (FlightManager) **********

var FlightManager = {};

FlightManager.MaxPrice = function()
{
	return currencyConvert(maxPrice);
}

FlightManager.Currency = function()
{
	return curCurrency;
}

FlightManager.SetCurrency = function(curr)
{
    curCurrency = curr.toUpperCase();
    if (this.onCurrencyChange != null)
        this.onCurrencyChange(curCurrency);

    updatePriceRanges();

    showFlights(null);

    updateTop(done);
}

FlightManager.SetFilterMaxPrice = function(price)
{
	var priceEUR = currencyConvertEUR(price);
	filterMaxPrice = priceEUR;
	processFlightsWait();
}

FlightManager.SetFilterOutDepTime = function(min, max)
{
	filterMinOutDepTime = min;
	filterMaxOutDepTime = max;
	processFlightsWait();
}

FlightManager.SetFilterRetDepTime = function(min, max)
{
	filterMinRetDepTime = min;
	filterMaxRetDepTime = max;
	processFlightsWait();
}

FlightManager.FilterOnly = function(type, value)
{
	filterOnly(type, value);
}

FlightManager.FilterAll = function(type)
{
	filterAll(type);
}

FlightManager.SelectView = function(view)
{
	var viewnum = parseInt(view);
	selectView.defer(viewnum);
}

FlightManager.GroupBySortBy = function(gfield, sfield)
{
	setGroupBySortBy(gfield, sfield);
}

FlightManager.SortBy = function(field)
{
	if (field == sortField)
		sortDirection = -sortDirection;
	else
		sortDirection = 1;
	sortField = field;
	curPage = 0;
	processFlightsWait();
}

FlightManager.GroupBy = function(field)
{
	if (field != groupField)
	{
		groupField = field;
		curPage = 0;
		processFlightsWait();
	}
}

FlightManager.SetDirectOnly = function(enabled)
{
	if (enabled)
		setMaxStops(0);
	else
		setMaxStops(10);
}

FlightManager.NextPage = function()
{
	setPage(curPage + 1);
}

FlightManager.PrevPage = function()
{
	setPage(curPage - 1);
}

FlightManager.SetPage = function(page)
{
	setPage(page);
}

FlightManager.SetFlights = function()
{
	setFlights();
}

FlightManager.ResetFlights = function()
{
	initFlights();
}

// ********** implementation **********

function initFlights()
{
	isCPH = (location.href.substr(0, 11).toLowerCase() == 'http://cph.');
	
	flights = [];
	currentflights = null;
	flightgroups = null;
	grouped = null;
	groupstate = new Dictionary();
	pinnedflights = null;
	topAdSuppliers = null;

	supplierList = new Dictionary();
	supplierIataList = new Dictionary();
	suppliers = new Dictionary();
	airlines = new Dictionary();
	tickets = new Dictionary();
	origs = new Dictionary();
	dests = new Dictionary();
	innovata = [];
	updatingSuppliers = new Hash();
	routeSuppliers = [];
	routeSuppliersIndex = new Hash();
	combiOutSegs = [];
	combiRetSegs = [];
	combiFlight = null;

	filterSupplier = [];
	filterAirline = [];
	filterTicket = [];
	filterOrig = [];
	filterDest = [];

	cheapestFlight = null;

	minPrice = 999999;
	maxPrice = 0;
	sumPrice = 0;

	curPage = 0;
	filterPriceRange = 0;
	filterMinPrice = 0;
	filterMaxPrice = 100000;

	filterMaxStops = 10;
	groupField = 'supplier';
	sortField = 'price';
	sortDirection = 1;
	searching = false;

	filterMinPrice = 0;
	filterMaxPrice = 100000;
	filterMinStops = 0;
	filterMaxStops = 10;
	filterMinOutDepTime = 0;
	filterMaxOutDepTime = 1440;
	filterMinRetDepTime = 0;
	filterMaxRetDepTime = 1440;

	filterPriceRangeCount = 4;
	filterPriceRange = 0;
	filterOutTime = 0;
	filterRetTime = 0;
	
    dayNames = Sys.CultureInfo.CurrentCulture.dateTimeFormat.DayNames;
    monthNames = Sys.CultureInfo.CurrentCulture.dateTimeFormat.MonthNames;

	var dropdown = $('DropDownView');
	if (dropdown)
		dropdown.selectedIndex = 0;
	var checkbox = $('checkboxDirectOnly');
	if (checkbox)
		checkbox.checked = false;
	var radiobutton = $(ClientIDs.RadioButtonWebSite)
	if (radiobutton)
		radiobutton.checked = true;
	var hyperlink = $(ClientIDs.HyperLinkFilterShowResultsBy);
	curView = 0;
	setInnerHtml(hyperlink, getSortByText());
    
	processFlights();
	updateTripCount();
	updateTop(false);
	updatePriceRanges();
	showFilters();
	
	var errors = $('top-errors');
	if(errors)
		errors.innerHTML = '';

	errors = $('bottom-errors');
	if (errors)
		errors.innerHTML = '';		

	var live = $('livesearch');
	if(live)
		live.style.display='';

	searchStart();
}

function searchStart()
{
	searching = true;

	var img = $('ImageWait');
	if (img)
		img.src = imagePath + 'blueywait.gif';

	var label = $('LabelStopSearch');
	if (label)
		label.style.display = 'inline';

	label = $('LabelStatus');
	setInnerHtml(label, Language['FlightResults_JS_Searching']);

	var complete = $('complete');
	if (complete)
		complete.style.display = 'none';

	var searchdiv = $('searchingflights');
	if (searchdiv != null)
		searchdiv.style.display = 'block';

	var innovata = $('innovata');
	if (innovata != null)
		innovata.innerHTML = '';

	var routesuppliers = $('routesuppliers');
	if (routesuppliers)
		routesuppliers.hide();

	hidePanel($('results'));
	hidePanel($('noresults'));
	hidePanel($('live'));
}

function updateTripCount()
{
	var label = $('LabelTripCount');
	setInnerHtml(label, flights.length.toString());
}

function searchDone()
{
	done = true;
	searching = false;

	var img = $('ImageWait');
	if (img)
		img.src = imagePath + 'blueydone.gif';

	$('LabelStopSearch').style.display = 'none';
    
	updateTripCount();

	label = $('LabelStatus');
	setInnerHtml(label, Language['FlightResults_JS_Finished']);
    
	var searchdiv = $('searchingflights');
	if(searchdiv != null)
		searchdiv.hide();
		
    if (typeof showSearchForm != 'undefined')
	showSearchForm();

	if (flights.length == 0)
	{
		hidePanel($('results'));
		showPanel($('noresults'));
	}
	else
	{
		showPanel($('live'));
		updateTop(true);
	}
}

function doneFlights()
{
	searchDone();
	if (updatingSuppliers.keys.length > 0)
	{
		var alertText = Language['FlightResults_JS_NotAbleToGetFares'] + '\n';
		for (var i = 0; i < updatingSuppliers.keys.length; i++)
		{
			var supplier = getSupplier(updatingSuppliers.keys[i]);
			alertText += supplier.name + '\n';
		}
		alertDialog.alert({ bodyText: alertText });
		updatingSuppliers = new Hash();
	}
	updateRouteSuppliers(true);
}

function removeSupplier(supplierid)
{
	var newFlights = [];
	var len = flights.length;
	for (var i = 0; i < len; i++)
	{
		if (flights[i].supplier.id != supplierid)
			newFlights.push(flights[i]);
	}
	flights = newFlights;
}

function addFlight(key, supplierid, orig, dest, depdate, retdate, oneway, price, quotehours, quotedate, quotetime, factor, outsegs, retsegs)
{
	if (isNaN(price))
		return;
        
	if (price < 1)
		return;

	if (isCPH && !checkCPH(orig, supplierid))
		return;

	if (typeof updatingSuppliers.get(supplierid) == "boolean")
	{
		removeSupplier(supplierid);
		updatingSuppliers.unset(supplierid);
	}

	var fl = {
		key: key,
		oneway: oneway,
		outsegs: outsegs,
		retsegs: retsegs,
		supplier: getSupplier(supplierid),
		orig: orig,
		dest: dest,
		depdate: depdate,
		retdate: retdate,
		price: price,
		quotehours: quotehours,
		quotedate: quotedate,
		quotetime: quotetime,
		factor: factor,
		details: false
	};
	flights[flights.length] = fl;

	checkPrice(price);

	return fl;
}

function addCombiSegments(outsegs, retsegs)
{
    combiOutSegs = combiOutSegs.concat(outsegs);
    combiRetSegs = combiRetSegs.concat(retsegs);

    combiOutSegs.sort(compareSegArraysByPrice);
    combiRetSegs.sort(compareSegArraysByPrice);

    setCombiFlight();
}

function addError(supplierid, supplier, orig, origname, dest, destname, type, outresultcount, outminprice, homeresultcount, homeminprice)
{
	if (isCPH && !checkCPH(orig, null, type))
		return;

	var key = supplierid + orig + dest;
	var rs = routeSuppliers[routeSuppliersIndex.get(key)];
	if (rs)
	{
		rs.error = true;

		var e = null;
		if (type == 0)
			e = $('top-errors');
		else
			e = $('bottom-errors');
		if (type != 1 && $('error' + supplierid) == null && e != null)
		{
			var d = new Element('div');
			d.innerHTML = getErrorHtml(supplierid, supplier, orig, origname, dest, destname, type, null, outresultcount, outminprice, homeresultcount, homeminprice);
			e.appendChild(d);
		}
	}
}

function addSupplier(id, name, url, home, imgurl, iata, type, rating, ratingCount)
{
	var supplier = supplierList[id];
	if (supplier == null)
	{
		supplier = {
			id: id,
			name: name,
			url: url,
			home: home,
			imgurl: imgurl,
			iata: iata,
			type: type,
			rating: rating,
			ratingCount: ratingCount
		};
		supplierList[id] = supplier;
		supplierIataList[iata] = supplier;
        
		// add to "old" lookup - used by filters
		addLookup(suppliers, id, name);

		// add supplier img to DOM!
		addSupplierImg(supplier);
	}
	return supplier;
}

function addSupplierImg(supplier)
{
    if (supplier && supplier.imgurl)
    {
        var c = $('supplier_images');
        if (c)
        {
            var img = new Element('img');
            img.src = supplier.imgurl;
            img.alt = supplier.name;
            img.setStyle({ width: '1px', height: '1px' });
            c.appendChild(img);
        }
    }
}

function getSupplier(s)
{
	if (typeof s == 'object')
		return s;
	else
		return supplierList[s];
}

function getSupplierImg(s)
{
	var sp = getSupplier(s);
	var img = '';
	if (sp.imgurl != null && sp.imgurl != '')
		img = '<img width="1" height="1" src="' + sp.imgurl + '" />';
	return img;
}

function copyFlight(fl)
{
	return {
	    index: fl.index,
	    key: fl.key,
	    oneway: fl.oneway,
	    outsegs: fl.outsegs,
	    retsegs: fl.retsegs,
	    supplier: fl.supplier,
	    orig: fl.orig,
	    dest: fl.dest,
	    depdate: fl.depdate,
	    retdate: fl.retdate,
	    price: fl.price,
	    quotehours: fl.quotehours,
	    quotedate: fl.quotedate,
	    quotetime: fl.quotetime,
	    factor: fl.factor,
	    details: false
	};
}

function checkPrice(price)
{
	sumPrice += price;
    
	if (price > maxPrice)
	{
		maxPrice = price;
		if (FlightManager.onMaxPriceChange != null)
			FlightManager.onMaxPriceChange(maxPrice);
	}

	if (price < minPrice)
	{
		minPrice = price;
		if (FlightManager.onMinPriceChange != null)
			FlightManager.onMinPriceChange(minPrice);
	}
}

function createSegArray(s)
{
	return [s];
}

function createSeg(outbound, airlinecode, airline, flightno, tkclass, tktype, origcode, orig, destcode, dest, origmatch, destmatch, deptime, arvtime, dur, stops, price, retbased, supplierid)
{
	if (tkclass == null || tkclass == '')
		tkclass = 'UNK';

	var s = {
	    outbound: outbound,
	    airlinecode: airlinecode,
	    airline: airline,
	    flightno: flightno,
	    tkclass: tkclass,
	    tktype: tktype,
	    origcode: origcode,
	    orig: orig,
	    destcode: destcode,
	    dest: dest,
	    origmatch: origmatch,
	    destmatch: destmatch,
	    // times are stored as minutes since midnight
	    deptime: deptime,
	    arvtime: arvtime,
	    // duration is stored in minutes
	    dur: dur,
	    stops: stops,
	    price: price,
	    retbased: retbased,
	    supplierid: supplierid // only included for combi segments 
	};

	addLookup(airlines, airlinecode, airline);
	addLookup(tickets, tkclass, ticketClassName(tkclass));

	if (outbound)
	{
		addLookup(origs, origcode, orig);
		addLookup(dests, destcode, dest);
	}
	else
	{
		addLookup(origs, destcode, dest);
		addLookup(dests, origcode, orig);
	}

	return s;
}

_sa = createSegArray;
_s = createSeg;
_f = addFlight;
_e = addError;
_i = addInnovataFlight;
_as = addSupplier;
_ac = addCombiSegments;

function addLookup(list, code, text)
{
	var res = list[code];
	if (res == null)
	{
		// not in list - add text (or code, if text is empty)
		list[code] = (text == null || text == '' ? code : text);
		updateFilters = true;
	}
	else if (res == code)
	{
		// already in list, equal to code and text is assigned - set text (it must be better)
		list[code] = text;
		updateFilters = true;
	}
}

function checkSegments(flsegs, segs)
{
	// "refines" flsegs with information from segs - eg. duration or stops
	for(var i = 0; i < segs.length; i++)
	{
		var seg = segs[i];
		if(i < flsegs.length)
		{
			var flseg = flsegs[i];
			if (seg.dur > 0 && flseg.dur <= 0)
				flseg.dur = seg.dur;
			if (seg.stops >= 0 && flseg.stops < 0)
				flseg.stops = seg.stops;
			/*
			if (seg.layover > 0 && flseg.layover <= 0)
				flseg.layover = seg.layover;
			if (seg.equip != '' && flseg.equip == '')
				flseg.equip = seg.equip;
			*/
		}
		else
		{
			flsegs.push(seg);
		}
	}
}

function convertDate(date, hour, min)
{
	if(typeof hour == 'undefined' || typeof min == 'undefined')
		return new Date(date.substr(0, 4), parseInt(date.substr(4, 2), 10) - 1, date.substr(6, 2));
	return new Date(date.substr(0, 4), parseInt(date.substr(4, 2), 10) - 1, date.substr(6, 2), hour, min);
}

function momondoDate(date)
{
	// input=YYYYMMDD, output=DD/MM/YY
	return date.substr(6,2) + '/' + date.substr(4,2) + '/' + date.substr(2,2);
}

function outputDate(date)
{
	// input=YYYYMMDD, output=DD-MM-YYYY
	// return date.substr(6,2) + '-' + date.substr(4,2) + '-' + date.substr(0,4);
	var obj = convertDate(date);
	if (currentCulture == 'en-US')
		return dayNames[obj.getDay()].substr(0, 3) + ', ' + monthNames[obj.getMonth()].substr(0, 3) + ' ' + obj.getDate();
	return dayNames[obj.getDay()].substr(0, 3) + ', ' + obj.getDate() + '. ' + monthNames[obj.getMonth()].substr(0, 3);
}

function outputDateEx(date)
{
	// input=YYYYMMDD, output=DD-MM-YYYY
	// return date.substr(6,2) + '-' + date.substr(4,2) + '-' + date.substr(0,4);
	var obj = convertDate(date);
	if (currentCulture == 'en-US')
		return dayNames[obj.getDay()] + ' ' + monthNames[obj.getMonth()].substr(0, 3) + ' ' + obj.getDate();
	return dayNames[obj.getDay()] + ' ' + obj.getDate() + '. ' + monthNames[obj.getMonth()].substr(0, 3);
}

function getSupplierRedirectLink(supplierId, ref, pos, orig, dest)
{
	var extra = '';
	if (ref != null) extra += '&ref=' + ref;
	if (pos != null) extra += '&pos=' + pos;
	if (typeof orig == 'undefined')
		orig = searchorig;
	if (typeof dest == 'undefined')
		dest = searchdest;
	return getRedirectLinkEx(supplierId, orig, dest, searchoneway, searchdepdate, searchretdate) + extra;
}

function getResultRedirectLink(fl, pos)
{
	var ref = 'result';
	if (isTopAdSupplier(fl.supplier.id))
		ref += '-topad';
	return getRedirectLink(fl, ref, pos);
}

function getRedirectLink(fl, ref, pos)
{
	var extra = '';
	if (ref != null) extra += '&ref=' + ref;
	if (pos != null) extra += '&pos=' + pos;
	return getRedirectLinkEx(fl.supplier.id, fl.orig, fl.dest, fl.oneway, fl.depdate, fl.retdate, fl.price, fl.quotedate, fl.quotetime) + extra;
}

function getRedirectLinkEx(supplierid, orig, dest, oneway, depdate, retdate, price, quotedate, quotetime)
{
	var rdate = '';
	if (!oneway)
		rdate = '&ReturnDate=' + momondoDate(retdate);
	return appPath + '/Redirect.aspx?Supplier=' + supplierid + '&Orig=' + orig + '&Dest=' + dest + '&ReturnTrip=' + (oneway ? 'false' : 'true') + '&DepartDate=' + momondoDate(depdate) + rdate + (price == null ? '' : '&Price=' + Math.round(currencyConvert(price)) + '&Currency=' + curCurrency) + (quotedate == null ? '' : '&QuoteDate=' + momondoDate(quotedate)) + (quotetime == null ? '' : '&QuoteTime=' + quotetime);
}

function compareNum(a, b, x, y)
{
	var r = (sortDirection * (x-y));
	if (r == 0 || isNaN(r))
		r = (a.price - b.price);
	return r;
}

function compareStr(a, b, x, y)
{
	var r = (sortDirection * String.compare(x,y));
	if (r == 0)
		r = (a.price - b.price);
	return r;
}

function compareSegsByPrice(a, b)
{
    return a.price - b.price;
}

function compareSegArraysByPrice(a, b)
{
    return a[0].price - b[0].price;
}

function compareGroupsByPrice(a, b)
{
	var x = a.fl.price;
	var y = b.fl.price;
	return (x-y);
}

function compareGroupsByRating(a, b)
{
	var x = a.fl.supplier.rating;
	var y = b.fl.supplier.rating;
	if (y == x)
	{
		x = a.fl.supplier.ratingCount;
		y = b.fl.supplier.ratingCount;
	}
	return y - x; // NOTE: descending sort
}

function compareFlightsByPriceAsc(a, b)
{
	var x = a.price;
	var y = b.price;
	return (x-y);
}

function compareFlightsByPrice(a, b)
{
	var x = a.price;
	var y = b.price;
	return (sortDirection * (x-y));
}

function compareFlightsByOutDepTime(a, b)
{
	return compareNum(a, b, a.outsegs[0].deptime, b.outsegs[0].deptime);
}

function compareFlightsByRetDepTime(a, b)
{
	return compareNum(a, b, a.retsegs[0].deptime, b.retsegs[0].deptime);
}

function compareFlightsBySupplierId(a, b)
{
	return compareStr(a, b, a.supplier.id.toLowerCase(), b.supplier.id.toLowerCase());
}

function compareFlightsBySupplierName(a, b)
{
	return compareStr(a, b, a.supplier.name.toLowerCase(), b.supplier.name.toLowerCase());
}

function compareFlightsByAirline(a, b)
{
	var fa = a.outsegs[0].airlinecode + a.outsegs[0].flightno;
	var fb = b.outsegs[0].airlinecode + b.outsegs[0].flightno;
	return compareStr(a, b, fa.toLowerCase(), fb.toLowerCase());
}

function compareFlightsByAirlineCode(a, b)
{
	return compareStr(a, b, a.outsegs[0].airlinecode.toLowerCase(), b.outsegs[0].airlinecode.toLowerCase());
}

function compareFlightsByStops(a, b)
{
	return compareNum(a, b, a.outsegs[0].stops, b.outsegs[0].stops);
}

function compareFlightsByDuration(a, b)
{
	return compareNum(a, b, a.outsegs[0].dur, b.outsegs[0].dur);
}

function compareFlightsByKey(a, b)
{
	return compareStr(a, b, a.key.toLowerCase(), b.key.toLowerCase());
}

function compareFlightsByRating(a, b)
{
	var res = compareNum(a, b, a.supplier.rating, b.supplier.rating);
	if (res == 0)
		res = compareNum(a, b, a.supplier.ratingCount, b.supplier.ratingCount);
	return res;
}

function compareFlightsByScore(a, b)
{
	if(a.score == null || b.score == null)
		return compareFlightsByPrice(a, b);
	else
		return -compareNum(a, b, a.score, b.score);
}

function compareFlightsByFactor(a, b)
{
	if(a.factor == null || b.factor == null)
		return compareFlightsByPrice(a, b);
	else
		return -compareNum(a, b, a.factor, b.factor);
}

function sortFlights(list, field)
{
	if (field == 'price')
	{
		list.sort(compareFlightsByPrice);
	}
	else if (field == 'outdeptime')
	{
		list.sort(compareFlightsByOutDepTime);
	}
	else if (field == 'retdeptime')
	{
		list.sort(compareFlightsByRetDepTime);
	}
	else if (field == 'supplierid')
	{
		list.sort(compareFlightsBySupplierId);
	}
	else if (field == 'suppliername')
	{
		list.sort(compareFlightsBySupplierName);
	}
	else if (field == 'airline')
	{
		list.sort(compareFlightsByAirline);
	}
	else if (field == 'airlinecode')
	{
		list.sort(compareFlightsByAirlineCode);
	}
	else if (field == 'stops')
	{
		list.sort(compareFlightsByStops);
	}
	else if (field == 'duration')
	{
		list.sort(compareFlightsByDuration);
	}
	else if (field == 'key')
	{
		list.sort(compareFlightsByKey);
	}
	else if (field == 'rating')
	{
		list.sort(compareFlightsByRating);
	}
	else if (field == 'score')
	{
		list.sort(compareFlightsByScore);
	}
}

function calcPriceRange(fl)
{
	var price = currencyConvert(fl.price);
	if (price < 1000)
		return 'R1';
	if (price < 2000)
		return 'R2';
	if (price < 3000)
		return 'R3';
	if (price < 4000)
		return 'R4';
}

function includeFlight(fl)
{
	if (fl.price < filterMinPrice)
		return false;
	if (fl.price > filterMaxPrice)
		return false;
	if (fl.outsegs[0].stops > filterMaxStops)
		return false;
	if (fl.outsegs[0].deptime > filterMaxOutDepTime)
		return false;
	if (fl.outsegs[0].deptime < filterMinOutDepTime)
		return false;

	if(filterSupplier.contains(fl.supplier.id))
		return false;
	if(filterAirline.contains(fl.outsegs[0].airlinecode))
		return false;
	if(filterTicket.contains(fl.outsegs[0].tkclass))
		return false;
	if(filterOrig.contains(fl.outsegs[0].origcode))
		return false;
	if(filterDest.contains(fl.outsegs[0].destcode))
		return false;

	if(!fl.oneway)
	{
		if (fl.retsegs[0].stops > filterMaxStops)
			return false;
		if (fl.retsegs[0].deptime > filterMaxRetDepTime)
			return false;
		if (fl.retsegs[0].deptime < filterMinRetDepTime)
			return false;
		if(filterAirline.contains(fl.retsegs[0].airlinecode))
			return false;
		if(filterTicket.contains(fl.retsegs[0].tkclass))
			return false;
		if(filterOrig.contains(fl.retsegs[0].destcode))
			return false;
		if(filterDest.contains(fl.retsegs[0].origcode))
			return false;
	}
    
	return true;
}

function filterFlights(list)
{
	var res = [];
	for (var i = 0; i < list.length; i++)
	{
		var fl = list[i];
		if (includeFlight(fl))
			res.push(fl);
	}
	return res;
}

function groupFlights(field, list)
{
	var groups = new Dictionary();
        
	for (var i = 0; i < list.length; i++)
	{
		var fl = list[i];

		if (field == 'supplier')
			ident = fl.supplier.id + fl.orig + fl.dest;
		else if (field == 'airline')
			ident = getFlightAirline(fl);
		else if (field == 'price')
			ident = fl.price.toString();
		else
			ident = fl.key;

		var group = groups[ident];
		if (group == null)
		{
			// fl does not match an existing group - make new group
			group = {};

			group.flights = [];
			group.ident = ident;
			group.fl = fl;

			groups[ident] = group;
		}
		else
		{
			// fl is contained in an existing group - check against best price
			if (fl.price < group.fl.price)
				group.fl = fl;

			if (enhanceSegments && field == 'key')
			{
				checkSegments(fl.outsegs, group.fl.outsegs);
				checkSegments(group.fl.outsegs, fl.outsegs);
				if (!fl.oneway)
				{
					checkSegments(fl.retsegs, group.fl.retsegs);
					checkSegments(group.fl.retsegs, fl.retsegs);
				}
			}
		}

		// add flight to group
		group.flights.push(fl);
	}
    
	return groups;
}

function getGroupedByPrice(list)
{
	var res = new Dictionary();

	for (var i = 0; i < list.length; i++)
	{
		var gr = list[i];
		res[gr.ident] = groupByPrice(gr);
	}

	return res;
}

function groupByPrice(group)
{
	// "group" contains flights from same supplier or airline

	var result = {};
	result.flights = [];
	result.ident = group.ident;
	result.fl = null;

	// group flights by price
	var groups = groupFlights('price', group.flights);
	var grouplist = groups.Values();

	// "groups" now contains groups of flights with same price
	for (var i = 0; i < grouplist.length; i++)
	{
		var gr = grouplist[i];

		// collect all segs for the "group"
		var outsegs = [];
		var retsegs = null;

		var hasReturns = false;

		var time = -1;
		sortFlights(gr.flights, 'outdeptime');

		for (var j = 0; j < gr.flights.length; j++)
		{
			var fl = gr.flights[j];
			var s = fl.outsegs[0];
			if (s.deptime != time)
				outsegs.push(s);
			time = s.deptime;

			hasReturns = hasReturns || (!fl.oneway);
		}

		if (hasReturns)
		{
			retsegs = [];

			time = -1;
			sortFlights(gr.flights, 'retdeptime');

			for (var j = 0; j < gr.flights.length; j++)
			{
				var fl = gr.flights[j];
				if (includeFlight(fl))
				{
					if (fl.retsegs != null && fl.retsegs.length > 0)
					{
						var s = fl.retsegs[0];
						if (s.deptime != time)
							retsegs.push(s);
						time = s.deptime;
					}
				}
			}
		}

		var cp = copyFlight(gr.fl);
		cp.outsegs = outsegs;
		cp.retsegs = retsegs;
		cp.groupfl = gr.fl;
		result.flights.push(cp);
	}

	result.fl = result.flights[0];

	return result;
}

function showStatus(visible)
{
	var d = $('flgstatus');
	if (d)
	{
		if (visible)
		{
			if (flgStatusLevel <= 0)
			{
				var scroll = getScrollXY();
				var posY = scroll[1] - 200;
				if (posY < 100) posY = 100;
				d.style.top = posY + 'px';
				showPanel(d);
				flgStatusLevel = 0;
			}
			flgStatusLevel++;
		}
		else
		{
			flgStatusLevel--;
			if (flgStatusLevel == 0)
			{
				hidePanel(d);
			}
		}
	}
}

function setCombiFlight()
{
    if (combiOutSegs.length > 0 && combiRetSegs.length > 0)
    {
        var s = getSupplier('momondo');
        if (!s)
        {
            s = addSupplier('momondo', 'Combined Flights', '', '', '', '', 0, 0, 0);
        }

        var out = combiOutSegs[0];
        var ret = combiRetSegs[0];
        var price = out[0].price + ret[0].price;

        if (combiFlight)
        {
            combiFlight.price = price;
            combiFlight.outsegs = out;
            combiFlight.retsegs = ret;
        }
        else
        {
            combiFlight = addFlight('momondo', 'momondo', out.origcode, out.destcode, searchdepdate, searchretdate, 0, false, price, searchdepdate, 789, 1, out, ret)
        }
    }
}

function setFlights()
{
	// sort flights ascending by price 
	flights.sort(compareFlightsByPriceAsc);

	// update indexes on each flight - for reference purposes
	for (var i = 0; i < flights.length; i++)
		flights[i].index = i;

	updatePriceRanges();

	processFlightsWait();

	updateTripCount();

	updateTop(false);

	if (!flightsScrolled)
	{
	    flightsScrolled = true;
	    var c = $('content');
	    if (c == null)
	        c = $('searchresults');
	    Effect.ScrollTo(c, { duration: 1.0 });
	}

	// addToTripPad.setScroll.bind(addToTripPad).defer();
}

function processFlightsWait()
{
	showStatus(true);
	processFlights.defer();
}

function processFlights()
{
	var list = filterFlights(flights);
	matchCount = list.length;

	// group similar flights (by key)
	flightgroups = groupFlights('key', list);

	if (!supplierView)
	{
		// in all other views than "price and supplier"...
		// remove more expensive alternatives of similar flights 
		list = getSingleFlightFromGroups(flightgroups);
	}

	// sort flights according to the selected sorting
	sortFlights(list, sortField);

	if (groupField != '')
	{
		// group according the the selected grouping
		grouped = groupFlights(groupField, list);
		// get list of groupings
		list = grouped.Values();
		// sort groups by price (specific sorting within the group will remain intact)
		list.sort(compareGroupsByPrice);

		if (supplierView)
		{
			// further group by price - in supplier view only
			grouped = getGroupedByPrice(list);
			// get list of new groupings
			list = grouped.Values();

			if (sortField == 'rating')
				list.sort(compareGroupsByRating);
		}
	}

	updateRouteSuppliers();
	
	updateMatrix(flights);

	updateTimeTable(flights);

	showFlights(list);
	showStatus(false);

}

function getSingleFlightFromGroups(grouplist)
{
	var groups = grouplist.Values();
	var result = [];
	for (var i = 0; i < groups.length; i++)
	{
		var gr = groups[i];
		var list = gr.flights;
		if (list != null && list.length > 0)
			result.push(list[0]);
	}
	return result;
}

function showFlights(list)
{
	if (list == null)
		list = currentflights;
        
	if (list == null)
		return;
        
	currentflights = list;
        
	var panelFlights = $('flightresults');
	var panelResults = $('results');

	var len = list.length;
	if (len == 0)
	{
		var html = '<div class="textbox">' + Language['FlightResults_JS_NoMatches'] + '</div>';
		setInnerHtml(panelFlights, html);
	}
	else
	{
		showPanel(panelResults);

		pages = Math.ceil(len / resultsPerPage);
		if (curPage >= pages)
			curPage = pages-1;

		var start = curPage * resultsPerPage;
		var last = start + resultsPerPage;
        
		if (start < 0)
			start = 0;

		if (last > list.length)
			last = list.length;
            
		var html = '';
		for(var i = start; i < last; i++)
		{
			var item = list[i];
			if (item.fl)
				html += getGroupHtml(i, item); // item is a group
			else
				html += getFlightHtml(item); // item is a flight
		}

		setInnerHtml(panelFlights, html);

		showMatrix();
	}
    
	var m = $('mytripadvertisment');
	if(m!=null)
		m.show();
    
	showPinnedFlights();
    
	updateNav();
	updateFilterText();
    
	showFilters();
}

function showPinnedFlights(list)
{
	if (!enablePin) return;
    
	if (list == null)
		list = pinnedflights;
        
	var panel = $('pinnedresults');
	if (list == null || list.length == 0)
	{
		hidePanel(panel);
	}
	else
	{    
		var html = '';
		for(var i = 0; i < list.length; i++)
		{
			var fl = list[i];
			html += getFlightHtmlEx(fl, 'pin_');
		}
        
		setInnerHtml($('pinnedflights'), html);
		showPanel(panel);
	}
}

function togglePinFlight(index)
{
	var fl = flights[index];
	if (pinnedflights == null)
		pinnedflights = [];
        
	var index = pinnedflights.indexOf(fl);
	if (index < 0)
	{
		pinnedflights.push(fl);
		fl.pinned = true;
	}
	else
	{
		pinnedflights.splice(index, 1);
		fl.pinned = false;
	}

	showFlights();
}

function pinFlight(index)
{
	var fl = flights[index];
	if (pinnedflights == null)
		pinnedflights = [];
        
	var index = pinnedflights.indexOf(fl);
	if (index < 0)
	{
		pinnedflights.push(fl);
		fl.pinned = true;
	}

	showFlights();
}

function unpinFlight(index)
{
	var fl = flights[index];
	if (pinnedflights == null)
		pinnedflights = [];
        
	var index = pinnedflights.indexOf(fl);
	if (index >= 0)
	{
		pinnedflights.splice(index, 1);
		fl.pinned = false;
	}

	showFlights();
}

function setGroupBySortBy(gfield, sfield)
{
	var changed = false;
    
	if (gfield != groupField)
	{
		groupField = gfield;
		changed = true;
	}

	if (sfield != sortField)
	{
		sortDirection = 1;
		sortField = sfield;
		changed = true;
	}
    
	if (changed)
	{
		curPage = 0;
		processFlightsWait();
	}
}

function selectView(view)
{
	supplierView = false;
	curView = view;
	switch (curView)
	{
		case 1:
			setGroupBySortBy('airline', 'price');
			break;
		case 2:
			setGroupBySortBy('', 'price');
			break;
		case 3:
			setGroupBySortBy('', 'outdeptime');
			break;
		case 4:
			setGroupBySortBy('', 'retdeptime');
			break;
		case 5:
			supplierView = true;
			setGroupBySortBy('supplier', 'rating');
			break;
		default:
			curView = 0;
			supplierView = true;
			setGroupBySortBy('supplier', 'price');
			break;
	}
    
	var nm = 'selectview' + curView.toString();
	var radio = $(nm);
	if (radio != null)
		radio.checked = true;
        
	updateMatrix(flights);
	showMatrix();
}

// ********** output / formatting functions **********

function stringPad(str, len, pad)
{
	var strpad = '';
	for(var i = 0; i < len - str.length; i++)
	{
		strpad += pad;
	}
	return strpad + str;
}


function zeroPad(num, len)
{
	return stringPad(num.toString(), len, '0');
}

function minToTime(minutes, isDuration)
{
	var hours = Math.floor(minutes / 60);
	var mins = (minutes - hours * 60);
	var retTime = '';
	
	if(currentCulture == 'en-US' && !isDuration)
	{
	    var a_p = '';
	    
	    if (hours < 12)
           {
           a_p = "AM";
           }
        else
           {
           a_p = "PM";
           }
        if (hours == 0)
           {
           hours = 12;
           }
        if (hours > 12)
           {
           hours = hours - 12;
           }
       retTime= zeroPad(hours, 2) + ':' + zeroPad(mins, 2)+' '+a_p;
	}
	else
	{
	    retTime = zeroPad(hours, 2) + ':' + zeroPad(mins, 2);
	}
	return retTime;
}

function getOrig(s)
{
	return (s.orig == null || s.orig == '' ? s.origcode : s.orig);
}

function getOrigEx(s)
{
	return (s.orig == null || s.orig == '' || s.orig == s.origcode ? s.origcode : s.orig  + ' (' + s.origcode + ')');
}

function getOrigFormatted(s, ex)
{
	var text = '';

	if (ex)
		text = getOrigEx(s);
	else
		text = getOrig(s);
        
	if (s.origmatch > 1)
		text = '<strong>' + text + '</strong>';
	return text;
}

function getDest(s)
{
	return (s.dest == null || s.dest == '' ? s.destcode : s.dest);
}

function getDestEx(s)
{
	return (s.dest == null || s.dest == '' || s.dest == s.destcode ? s.destcode : s.dest + ' (' + s.destcode + ')');
}

function getDestFormatted(s, ex)
{
	var text = '';

	if (ex)
		text = getDestEx(s);
	else
		text = getDest(s);

	if (s.destmatch > 1)
		text = '<strong>' + text + '</strong>';
	return text;
}

function outputFlightNo(seg)
{
	return (seg.airlinecode == '' || seg.airlinecode == 'ZZ' ? '' : seg.airlinecode + (seg.flightno == 0 ? '' : zeroPad(seg.flightno, 4)));
}

function outputAirline(seg)
{
	return seg.airline;
}

function getFlightAirline(fl)
{
	var code = fl.outsegs[0].airlinecode;
	if (!fl.oneway)
		if (code != fl.retsegs[0].airlinecode)
			code = "ZZ";
	return code;
}

function getAirlineLogo(obj)
{
	if (!airlineLogos)
		return '';
        
	var code = obj.airlinecode;
	if (code == null)
		code = getFlightAirline(obj);

	if (code == '' || code == 'ZZ')
		code = "MULT";

	return '<img src="http://www.kayak.com/v109/images/air/' + code + '.gif" />';
}

function getSupplierLogo2(id)
{
	if (!supplierLogos)
		return '';
	return '<img src="' + logoPath + id + '.png" />';
}

function getSupplierLogo(fl)
{
	return getSupplierLogo2(fl.supplier.id);
}

function getGroupDetails(group)
{
	var html = '';
	for (var i = 1; i < Math.min(1000, group.flights.length); i++)
	{
		html += getFlightHtmlEx(group.flights[i], '', group);
	}
	return html;
}

function getQuoteText(fl)
{
	return getQuoteTime(fl.quotehours);
}

function tripPadCallback(tripid, id, orig, dest, index)
{
	showFlights();

	var fl = flights[index];
	var flightTripPadJS =
	{
		MyTripId: tripid,
		From: orig,
		To: dest,
		DepartDate: new Date(
			parseInt(searchdepdate.substr(0, 4), 10),
			parseInt(searchdepdate.substr(4, 2), 10) - 1,
			parseInt(searchdepdate.substr(6, 2), 10)),
		ReturnDate: new Date(
			parseInt(searchretdate.substr(0, 4), 10),
			parseInt(searchretdate.substr(4, 2), 10) - 1,
			parseInt(searchretdate.substr(6, 2), 10)),
		Subject: '',
		Url: searchurl,
		RedirectUrl: getRedirectLink(fl),
		Price: Math.round(currencyConvert(fl.price)),
		Currency: curCurrency,
		Supplier: fl.supplier.id
	};

	flightTripPadJS.OutSegments = [];
	for (var i = 0; i < fl.outsegs.length; i++)
	{
		var seg = fl.outsegs[i];
		var segment = {};
		segment.Orig = seg.origcode;
		segment.Dest = seg.destcode;
		segment.DepartTime = convertDate(fl.depdate, Math.floor(seg.deptime / 60), seg.deptime % 60);
		segment.ArriveTime = convertDate(fl.depdate, Math.floor(seg.arvtime / 60), seg.arvtime % 60);
		segment.Stops = seg.stops;
		segment.Suppliers = outputAirline(seg);
		flightTripPadJS.OutSegments.push(segment);
	}
	flightTripPadJS.HomeSegments = [];
	for (var i = 0; i < fl.retsegs.length; i++)
	{
		var seg = fl.retsegs[i];
		var segment = {};
		segment.Orig = seg.origcode;
		segment.Dest = seg.destcode;
		segment.DepartTime = convertDate(fl.retdate, Math.floor(seg.deptime / 60), seg.deptime % 60);
		segment.ArriveTime = convertDate(fl.retdate, Math.floor(seg.arvtime / 60), seg.arvtime % 60);
		segment.Stops = seg.stops;
		segment.Suppliers = outputAirline(seg);
		flightTripPadJS.HomeSegments.push(segment);
	}
	MyTripWS.AddFlightToTripPad(flightTripPadJS, addFlightToTripPadSuccess, addFlightToTripPadFailure, fl);
}

function addFlightToTripPadSuccess(result, userContext, methodName)
{
	userContext.added = true;
	setFlights();
	alertDialog.alert({ bodyText: Language['Trip_Add_Flight_Success'] });
}

function addFlightToTripPadFailure()
{
	alertDialog.alert({ bodyText: Language['Trip_Add_Flight_Failure'] });
}

function getGroupHtml(index, group)
{
	var fl = group.fl;
	var html = '<div class="group' + (fl.supplier.type == 'Train' ? ' train' : '') + '">';

	var supplier = fl.supplier;
	var supplierName = fl.supplier.name;
	var nameHeader = null;
	var name = '';
	var flag = '';
	var text = '';
	var logo = '';
	var link = '';
	var products = '';
	var notes = '';
	var info = '';
	var count = group.flights.length;

	var redirUrl = getResultRedirectLink(fl, fl.index + 1);

	if (groupField == 'supplier')
	{
		name = fl.supplier.url;
		//nameHeader = '<a href="' + redirUrl + '" target="_blank">' + name + '</a>';
		flag = (fl.supplier.home != '' ? '<img src="' + flagPath + fl.supplier.home.toLowerCase() + '.gif" alt="" />&nbsp;' : '');
		logo = getSupplierLogo(fl);
		text = (count > 1 ? count.toString() + ' ' + Language['FlightResults_JS_Trips'] : '1 ' + Language['FlightResults_JS_Trip']);
		products = getProductsHtml(fl, 2);
		notes = getProductNotesHtml(fl);
	}
	else if (groupField == 'airline')
	{
		var code = getFlightAirline(fl);
		if (code == 'ZZ')
		{
			name = Language['FlightResults_JS_Different_Airlines'];
			code = 'MULT';
		}
		else
		{
			var s = fl.outsegs[0];
			name = (s.airline == '' ? supplierName : s.airline);
		}
		nameHeader = name;
		text = Language['FlightResults_JS_Has'] + ' ' + (count > 1 ? count.toString() + ' ' + Language['FlightResults_JS_Departures'] : '1 ' + Language['FlightResults_JS_Departure']);
		logo = getAirlineLogo(fl);
	}

	if (count > 1)
	{
		link = ' - <a href="javascript:toggleGroupDetails(\'' + group.ident + '\')">' + Language['FlightResults_JS_See_All'] + '</a>';
	}
	else
	{
		link = '';
	}

	html += '<div class="groupheader">';

	html += '<table cellspacing="0" cellpadding="0" class="groupheader" style="float:left"><tr>';
	if (logo)
	    html += '<td class="logo"><a href="' + redirUrl + '" target="_blank">' + logo + '</a></td>';
	/* replaced by addSupplierImg!
	affImg = getSupplierImg(fl.supplier);
	if (affImg)
		html += '<td>' + affImg + '</td>';
	*/
	if (flag)
		html += '<td class="flag">' + flag + '</td>';
	if (nameHeader != null)
		html += '<td class="name">' + nameHeader + '</td>';
	html += '<td class="caption">' + text + link + '</td>';
	html += '</tr></table>';
	if (supplierView)
	{
		html += '<div class="supplierrating" style="float:right">' + getSupplierRatingHtml(supplier) + '</div>';
		if (fl.supplier.type == 'Train')
		{
			html += '<div style="float:right;padding-right:10px;"><img src="' + appPath + '/icons/reduceco2.gif" /></div>';
			html += '<div style="float:right;padding-right:10px;"><img src="' + appPath + '/icons/train.gif" /></div>';
		}
	}
	html += '<div class="clearfloats" style="clear:both"></div></div>';

	html += products;
	html += getFlightHtmlEx(group.flights[0], '', group);
	html += notes;

	var open = groupstate[group.ident];
	var disp = (open ? "block" : "none");
	html += '<div id="flgroup_' + group.ident + '" class="groupdetails" style="display: ' + disp + '">';
	if (open)
	{
		html += getGroupDetails(group);
	}
	html += '</div></div>';
	return html;
}

function getFlightGroup(ident, collapse)
{
	var list = null;
	var group = flightgroups[ident];
	if (group)
	{
		if (group.flights)
		{
			if (collapse)
			{
				list = [];
				var dict = new Dictionary();
				for (var i = 0; i < group.flights.length; i++)
				{
					var fl = group.flights[i];
					var spid = fl.supplier.id;
					if (!dict[spid])
					{
						dict[spid] = 1;
						list.push(fl);
					}
				}
			}
			else
			{
				list = group.flights;
			}
		}
	}
	return list;
}

function getFlightHtml(fl)
{
	return getFlightHtmlEx(fl, '');
}

function getFlightHtmlEx(fl, base, group)
{
	var logo = getAirlineLogo(fl);

	var html = '<div id="' + base + 'flmain' + fl.index.toString() + '" class="flight">';
	html += '<table cellspacing="0" cellpadding="0" border="0" style="width: 100%"><tr>';
	html += '<td class="flightsegments">';
	html += '<table cellspacing="0" cellpadding="0" border="0" style="width:100%">';
	for (var i = 0; i < fl.outsegs.length; i++)
	{
		var s = fl.outsegs[i];
		html += getSegmentHtml(fl, s, false, i == 0);
	}

	if (!fl.oneway)
	{
		for (var i = 0; i < fl.retsegs.length; i++)
		{
			var s = fl.retsegs[i];
			html += getSegmentHtml(fl, s, true, i == 0);
		}
	}
	html += '</table></td>';

	var linked = getFlightGroup(fl.key, true);
	var prices = '';
	for (var l = 0; l < linked.length; l++)
	{
		var fl2 = linked[l];
		var link = '<a href="' + getResultRedirectLink(fl2, fl2.index + 1) + '" target="_blank">';
		var logo = getSupplierLogo(fl2);
		prices += '<tr><td class="supplierlogo">' + link + logo + '</a></td><td class="price">' + link + formatPrice(fl2.price) + ' ' + curCurrency + '</a></td></tr>';
	}

	// best supplier price
	var redirUrl = getResultRedirectLink(fl, fl.index + 1);
	var link = '<a href="' + redirUrl + '" target="_blank">';
	html += '<td class="priceinfo">';
//	if (supplierView && !User.anonymous)
//	{
//	    html += '<div class="trippad">';
//	    if (!fl.added)
//	    {
//	        var orig = fl.outsegs[0].origcode;
//	        var dest = fl.outsegs[0].destcode;
//	        html += addToTripPad.render('tripPadCallback', group.ident + fl.index, group.ident, orig, dest, fl.index);
//	        html += '<a href="#" class="addtotrippad" onclick="addToTripPad.showAddTripPad(\'' + group.ident + fl.index + '\',\'tripPadCallback\',\'' + group.ident + '\',\'' + orig + '\',\'' + dest + '\',' + fl.index + ');return false;"><span class="link addtotrippad">' + Language['Trip_Add_AddToTripPad'] + '</span>';
//	        html += '<img class="addtotrippad" src="' + csThemePath + '/images/SkyGate/trippad/btn_add.png" /></a>';
//	    }
//	    else
//	    {
//			html += Language['Trip_Add_AddedToTripPad'];
//	    }
//	    html += '</div>';
//	}
	if(supplierView)
	{
		html += '<div class="price">' + link + formatPrice(fl.price) + ' ' + curCurrency + '</a></div>';
		html += '<input type="button" class="button_black" onclick="window.open(\'' + redirUrl + '\');supplierEvaluation.show(\'' + fl.supplier.id + '\',\'' + fl.supplier.name + '\');return false;" value="' + Language['FlightResults_JS_Visit'] + '" />';
		html += '<div class="' + (fl.quotehours == 0 ? 'live' : '') + 'quote">' + getQuoteText(fl) + '</div>';
		if (updatingSuppliers.get(fl.supplier.id) != true)
		{
			if (fl.quotehours != 0)
				html += '<div class="livesearch ' + fl.supplier.id + '"><a href="javascript:startLiveSearchSupplier(\'' + fl.supplier.id + '\')">' + Language['FlightResults_LabelLiveSearch2.Text'] + '</a></div>';
		}
		else
			html += '<div class="livesearch ' + fl.supplier.id + '"><img src="' + imagePath + 'wait.gif" alt="" style="vertical-align:bottom" />&nbsp;' + Language['FlightResults_JS_Updating'] + '</div>';

		var flightInfoBox = getProductInfoHtml(fl);
		html += flightInfoBox;
	}
	else
		html += '<table cellpadding="0" cellspacing="0">' + prices + '</table>';

	/*var desc = 'Send denne rejse til en ven';
	link= '<a href="javascript:tipAFriend(' + fl.index.toString() + ')" title="' + desc + '">' + desc + '</a>';
	html += '<div class="tipafriend">' + link + '</div>';*/

	html += '</td></tr></table>';

	var linked = getFlightGroup(fl.key, true);
	var count = linked.length;

	// pin link
	var wPin = '';
	if (enablePin)
	{
		var wPinLink = '<a href="javascript:togglePinFlight(' + fl.index.toString() + ')">';
		if (fl.pinned)
		{
			// var wPinLink = '<a href="javascript:unpinFlight(' + fl.index.toString() + ')">';
			wPin = '<td>' + wPinLink + '<img src="' + imagePath + 'pindown.gif" alt="gem ikke denne rejse" /></a></td><td>' + wPinLink + 'gem ikke</a></td>';
		}
		else
		{
			// var wPinLink = '<a href="javascript:pinFlight(' + fl.index.toString() + ')">';
			wPin = '<td>' + wPinLink + '<img src="' + imagePath + 'pinup.gif" alt="gem denne rejse" /></a></td><td>' + wPinLink + 'gem rejse</a></td>';
		}
	}

	var enableDetails = (fl.groupfl == null);
	if (enableDetails)
	{
		html += '<div style="width:100%">';

		// details link
		desc = Language['FlightResults_JS_See_more_details'];
		var wDetailsLink = '<a href="javascript:toggleFlightDetailsEx(' + fl.index.toString() + ', \'' + base + '\')" title="' + desc + '">';
		html += '<div class="info" style="float:right;padding-right:20px">';
		html += '<table cellspacing="0" cellpadding="0" border="0"><tr>';
		html += '<tr><td>' + wDetailsLink + '<img src="' + imagePath + 'info.gif" alt="' + desc + '" /></a></td><td>' + wDetailsLink + Language['FlightResults_JS_More_details'] + '</a></td></tr>';
		html += '</table>';
		html += '</div>';
		html += '<div class="clearfloats" style="clear:both;height:0px"></div>';
		html += '</div>';
	}


	// details
	if (enableDetails)
	{
		var disp = (fl.details ? "block" : "none");
		html += '<div id="' + base + 'fldetails' + fl.index.toString() + '" class="details" style="display: ' + disp + '">';
		if (fl.details)
		{
			html += getFlightDetails(fl);
		}
		html += '</div>';
	}

	html += '</div>';
	return html;
}

function getSegmentHtml(fl, seg, home, first, showticket)
{
	var dir = 'outbound';
	var dt = fl.depdate;
	if (home) 
	{
		dir = 'homebound';
		dt = fl.retdate;
	}
    
	var html = '';
	html += '<tr class="' + dir + '">';
	if (first)
	{
		html += '<td class="' + dir + '"><img src="' + imagePath + 'plane_' + dir + '.png" alt="" /></td>';
		html += '<td class="date">' + outputDate(dt) + '</td>';
	}
	else
	{
		html += '<td class="' + dir + '"></td>';
		html += '<td class="date"></td>';
	}
    
	html += '<td class="times"><strong>' + minToTime(seg.deptime) + '</strong> - ' + minToTime(seg.arvtime) + '</td>'; 
	html += '<td class="route">' + getOrigFormatted(seg, false) + '<br />' + getDestFormatted(seg, false) + '</td>'; 

	var wAirline = outputAirline(seg);

	var wStops = '';
	if (seg.stops < 0) wStops = '';
	else if (seg.stops > 1) wStops = seg.stops.toString() + ' ' + Language['FlightResults_JS_Stops'];
	else if (seg.stops == 1) wStops = '1 ' + Language['FlightResults_JS_Stop'];
	else wStops = Language['FlightResults_JS_NonStop'];
	if (wStops != '') wStops = '<span class="stops">' + wStops + '</span> ';

	var wDuration = (seg.dur > 0 ? '<span class="duration">(' + minToTime(seg.dur,true) + ')</span>' : '');
    
	var wStopDur = wStops + wDuration;

	var wLine = wAirline + (wAirline != '' && wStopDur != '' ? '<br />' : '') + wStopDur;

	html += '<td class="airline">' + wLine + '</td>';
	if(supplierView)
	{
		if (seg.tkclass == null || seg.tkclass == '' || seg.tkclass == 'UNK')
		{
			html += '<td class="ticket">&nbsp;</td>';
		}
		else
		{
			var s = ticketClassName(seg.tkclass);
			if (seg.tktype != null && seg.tktype != '' && seg.tktype != s)
				s += '<br /><span class="tickettype">(' + seg.tktype + ')</span>';
			html += '<td class="ticket">' + s + '</td>'; 
		}
	}
	html += '</tr>';
    
	return html;
}

function getFlightDetails(fl)
{
	return getFlightDetailsEx(fl, '');
}

function getFlightDetailsEx(fl, base)
{
	var html = "";
    
	var prices = '';

	/*var linked = getFlightGroup(fl.key, true);
	for(var l = 0; l<linked.length; l++)
	{
		var fl2 = linked[l];
		var link = '<a href="' + getResultRedirectLink(fl2, fl2.index+1) + '" target="_blank">';
		var logo = getSupplierLogo(fl2);
		prices += '<tr><td class="supplierlogo">' + link + logo + '</a></td><td class="price">' + link + formatPrice(fl2.price) + ' ' + curCurrency + '</a></td></tr>';
	}*/

	html += '<table cellspacing="0" cellpadding="0" border="0" style="width: 100%">';
	html += '<tr><td style="vertical-align:top;width:90%">';
	html += '<div class="header">' + Language['FlightResults_JS_DepartureTrip'] + ' ' + outputDateEx(fl.depdate) + '</div>';
	for(var i1 = 0; i1 < fl.outsegs.length; i1++)
	{
		var s = fl.outsegs[i1];
		html += getFlightSegmentHtml(fl, s);
	}
	if (!fl.oneway)
	{
		html += '<div class="header" style="margin-top: 10px">' + Language['FlightResults_JS_ReturnTrip'] + ' ' + outputDateEx(fl.retdate) + '</div>';
		for(var i2 = 0; i2 < fl.retsegs.length; i2++)
		{
			var s = fl.retsegs[i2];
			html += getFlightSegmentHtml(fl, s);
		}
	}
	html += '</td><td style="vertical-align: top; width: 10%">';
	html += '<div id="' + base + 'flprices' + fl.index.toString() + '" class="prices">';
	html += '</div></td></tr></table>';

	return html;
}

function getFlightSegmentHtml(fl, s)
{
	var logo = getAirlineLogo(s);

	var html = '';
	html += '<div class="segment">';
	html += '<table cellspacing="0" cellpadding="5" border="0"><tr>';
	if (logo != '')
		html += '<td class="airlinelogo">' + logo + '</td>';
	html += '<td class="flightinfo">' + (s.airline == '' ? fl.supplier.id : s.airline) + '<br />';
	html += Language['FlightResults_JS_Flight'] + ' ' + s.airlinecode + zeroPad(s.flightno, 4) + '</td>';
	html += '<td class="departinfo">' + Language['FlightResults_JS_Leave'] + ' ' + minToTime(s.deptime) + '<br />';
	html += getOrigFormatted(s, true) + '</td>';
	html += '<td class="arriveinfo">' + Language['FlightResults_JS_Arrive'] + ' ' + minToTime(s.arvtime) + '<br />';
	html += getDestFormatted(s, true) + '</td>';
	html += '</tr>';
    
	var stops = (s.stops < 0 ? Language['FlightResults_JS_Unknown'] : s.stops.toString());
	var duration = (fl.outsegs[0].dur > 0 ? minToTime(fl.outsegs[0].dur) : Language['FlightResults_JS_Unknown']);

	html += '<tr><td>' + Language['FlightResults_JS_StopOvers'] + ' : ' + stops + '</td>';
	html += '<td>' + Language['FlightResults_JS_TravelTime'] + ' : ' + duration + '</td>';
	html += '<td><td></tr>';
    
	var text = '';
	if (s.origmatch > 1)
		text += Language['FlightResults_JS_AltOrigAirport1'] + ' ' + getOrig(s) + ' ' + Language['FlightResults_JS_AltOrigAirport2'] + '<br />';
	if (s.destmatch > 1)
		text += Language['FlightResults_JS_AltDestAirport1'] + ' ' + getDest(s) + ' ' + Language['FlightResults_JS_AltDestAirport2'] + '<br />';
        
	if (text != '')
		html += '<tr><td colspan="3"><strong>' + Language['FlightResults_JS_Note'] + '</strong>: ' + text + '</td></tr>';
    
	html += '</table>';

	 html += '</div>';
	return html;
}

function toggleFlightDetails(index)
{
	return toggleFlightDetails(index, '');
}

function toggleFlightDetailsEx(index, base)
{
	var dtls = $(base + 'fldetails' + index.toString());

	var fl = flights[index];
	if (fl.details)
	{
		hidePanel(dtls);
		fl.details = false;
	}
	else
	{
		setInnerHtml(dtls, getFlightDetails(fl));
		showPanel(dtls);
		fl.details = true;
	}
}

function toggleGroupDetails(ident)
{
	var dtls = $('flgroup_' + ident);

	var open = groupstate[ident];
	if (open)
	{
		hidePanel(dtls);
		groupstate[ident] = false;
	}
	else
	{
		setInnerHtml(dtls, getGroupDetails(grouped[ident]));
		showPanel(dtls);
		groupstate[ident] = true;
	}
}

// ********** navigation **********

function updateNav()
{
	var panelNav = $('pagenav');
	if (panelNav != null)
		panelNav.innerHTML = getNavHtml();
}

function getNavHtml()
{
	if (pages <= 1)
		return '';

	var html = '<div class="pagemenu">';
	var wStart = curPage - 4;
	var wStop = curPage + 5;
	wStart = Math.min(wStart, pages - 9);
	wStart = Math.max(wStart, 0);
	wStop = Math.max(wStop, 9)
	wStop = Math.min(wStop, pages);

	if (curPage == 0)
		html += Language['FlightResults_JS_First'] + '&nbsp;&nbsp;|&nbsp;&nbsp;';
	else
		html += '<a href="javascript:setPage(0);">' + Language['FlightResults_JS_First'] + '</a>&nbsp;&nbsp;|&nbsp;&nbsp;';

	if (curPage < 1)
		html += Language['FlightResults_JS_Previous'] + '&nbsp;&nbsp;|&nbsp;&nbsp;';
	else
		html += '<a href="javascript:prevPage();">' + Language['FlightResults_JS_Previous'] + '</a>&nbsp;&nbsp;|&nbsp;&nbsp;';

	for (var i = wStart; i < wStop; i++)
	{
		if (i == curPage)
			html += (i + 1).toString() + '&nbsp;&nbsp;|&nbsp;&nbsp;';
		else
			html += '<a href="javascript:setPage(' + i.toString() + ');">' + (i + 1).toString() + '</a>&nbsp;&nbsp;&nbsp;|&nbsp;';
	}

	if (curPage >= pages - 1)
		html += Language['FlightResults_JS_Next'] + '&nbsp;&nbsp;|&nbsp;&nbsp;';
	else
		html += '<a href="javascript:nextPage();">' + Language['FlightResults_JS_Next'] + '</a>&nbsp;&nbsp;|&nbsp;&nbsp;';

	if (curPage == pages - 1)
		html += Language['FlightResults_JS_Last'];
	else
		html += '<a href="javascript:setPage(' + (pages - 1).toString() + ');">' + Language['FlightResults_JS_Last'] + '</a>';

	html += '</div>';
	return html;
}

function nextPage()
{
	location.href = "#results";
	FlightManager.SetPage(curPage+1);
}

function prevPage()
{
	location.href = "#results";
	FlightManager.SetPage(curPage - 1);
}

function setPage(page)
{
	location.href = "#results";

	if (currentflights == null)
		return;
        
	if (page >= 0 && page < pages)
	{
		curPage = page;
		showFlights(currentflights);
	}
}

function setMaxStops(stops)
{
	if (stops != filterMaxStops)
	{
		filterMaxStops = stops;
		processFlightsWait();
	}
}

// ********** products **********

function getProductHtml(p)
{
	var className = 'product';
	if (p.className != null && p.className != '')
		className += ' ' + p.className;
	var style = '';
	if (p.style != null && p.style != '')
		style = ' style="' + p.style + '"';
        
	var html = '<div class="' + className + '"' + style + '>';
	html += '<table cellspacing="0" cellpadding="0"><tr>';
	if (p.icon != null && p.icon != '')
	{
		html += '<td class="icon"><img src="' + iconPath + p.icon + '"></td>';
	}
	html += '<td class="text">' + p.text + '</td></tr></table>';
	html += '</div>';
	return html;
}

function getProductsHtml(fl, textType, preText, postText)
{
	var hasContent = false;
	var html = '<div class="products">';

	if (preText) 
	{
		hasContent = true;
		html += preText;
	}
                
	var s = GFlightSuppliers.getSupplier(fl.supplier.id);
	if (s)
	{
		var ps = s.getProducts(textType);
		if (ps != null && ps.length > 0)
		{
			hasContent = true;
			for(var i = 0; i < ps.length; i++)
				html += getProductHtml(ps[i]);
		}
	}
    
	if (postText)
	{
		hasContent = true;
		html += postText;
	}

	html += '</div>';
    
	if (hasContent)
		return html;
	else
		return '';
}

function getProductNotesHtml(fl)
{
	var note = '';
	var s = fl.outsegs[0];
	if (s.origmatch > 1)
		note += '<div class="product">' + Language['FlightResults_JS_AltOrigAirport1'] + ' <strong>' + getOrig(s) + '</strong> ' + Language['FlightResults_JS_AltOrigAirport2'] + '</div>';
	if (s.destmatch > 1)
		note += '<div class="product">' + Language['FlightResults_JS_AltDestAirport1'] + ' <strong>' + getDest(s) + '</strong> ' + Language['FlightResults_JS_AltDestAirport2'] + '</div>';

	var html = getProductsHtml(fl, 3, note);
	if (fl.supplier.type == 'Train')
		html += '<div class="trains"><div class="train" style="font-weight:bold"><span style="color:#77933C">Go train</span> <span style="color:#31859C">- Save on CO<sub>2</sub></span></div></div>';
	if (html != '')
		html = '<div class="products_note">' + html + '</div>';
        
	return html;
}

function getProductInfoHtml(fl, base)
{
	var html = '';
	var info = getProductsHtml(fl, 4);
	if (info != '')
	{
		if (typeof base == 'undefined' || base == null) base = '';

		var name = base + 'productinfo_' + fl.index;
		html += '<div class="products_callout" onmouseover="$(\'' + name + '\').show()" onmouseout="$(\'' + name + '\').hide()">';
		html += '<table cellspacing="0" cellpadding="0" style="margin-left: auto"><tr><td>' + Language['FlightResults_JS_ViewInfo'] + '&nbsp;</td><td><img src="' + imagePath + 'about.gif" /></td></tr></table>';
		html += '</div><div style="position:relative"><div id="' + name + '" class="products_info" style="display: none;">' + info + '</div></div>';
	}
	return html;
}

// ********** tickets **********

function ticketClassOrder(tkclass)
{
	if (tkclass == null || tkclass == '')
		return 0;
	if (tkclass == 'CCC')
		return 1;
	if (tkclass == 'ECO')
		return 2;
	if (tkclass == 'FLX')
		return 3;
	if (tkclass == 'BIZ')
		return 4;
	if (tkclass == 'FST')
		return 5;
	return -1;
}

function ticketClassName(tkclass)
{
	if (tkclass == null || tkclass == '')
		return Language['FlightResults_JS_Ticket_UNK'];
	else
		return Language['FlightResults_JS_Ticket_' + tkclass];
}

// ********** filters **********

function updateCurrency(currency, text)
{
	hyperlink = $(ClientIDs.HyperLinkCurrency);
	setInnerHtml(hyperlink, currency);
}

function toggleFilters()
{
	var filters = $('filters');
	var filterslink = $('filterslink');
	var filterarrow = $('filterarrow');
	if(filters.getStyle('display') == 'none')
	{
		filterslink.innerHTML = Language['FlightResults_JS_HideFilters'];
		filterarrow.src = imagePath + 'arrow_open.gif';
		new Effect.BlindDown(filters, { duration: 0.5 });
		new Effect.Appear(filters, { duration: 0.5 });
	}
	else
	{
		filterslink.innerHTML = Language['FlightResults_JS_ShowFilters'];
		filterarrow.src = imagePath + 'arrow_closed.gif';
		filters.hide();
	}
}

function toggleMoreFilters()
{
	var filters = $('morefilters');
	var morefilterslink = $('morefilterslink');
	if(filters.getStyle('display') == 'none')
	{
		morefilterslink.innerHTML = Language['FlightResults_JS_HideFilters'];
		new Effect.BlindDown(filters, { duration: 0.5 });
		new Effect.Appear(filters, { duration: 0.5 });
	}
	else
	{
		morefilterslink.innerHTML = Language['FlightResults_JS_ShowFilters'];
		filters.hide();
	}
	updateFilterText();
}

function showFilters()
{
	var hyperlink = $(ClientIDs.HyperLinkFilterDeparture);
	setInnerHtml(hyperlink, getTimeFilterText(filterOutTime));
	
	hyperlink = $(ClientIDs.HyperLinkFilterReturn);
	setInnerHtml(hyperlink, getTimeFilterText(filterRetTime));
	
	hyperlink = $(ClientIDs.HyperLinkFilterShowResultsBy);
	setInnerHtml(hyperlink, getSortByText());
	
	if (updateFilters)
	{
		var panelFilter = $('panelFilterSupplier');
		setInnerHtml(panelFilter, getSupplierFilterHtml());

		panelFilter = $('panelFilterAirline');
		setInnerHtml(panelFilter, getAirlineFilterHtml());

		panelFilter = $('panelFilterTicket');
		setInnerHtml(panelFilter, getTicketFilterHtml());

		panelFilter = $('panelFilterOrig');
		setInnerHtml(panelFilter, getOrigFilterHtml());

		panelFilter = $('panelFilterDest');
		setInnerHtml(panelFilter, getDestFilterHtml());
            
		panelFilter = $('panelFilterPrices');
		setInnerHtml(panelFilter, getPricesFilterHtml());

		panelFilter = $('panelFilterOutTime');
		setInnerHtml(panelFilter, getOutTimeFilterHtml());

		panelFilter = $('panelFilterRetTimeContainer');
		var panelFilterTeaser = $('filterteaser');
		if(searchoneway)
		{
			panelFilter.up().hide();
			panelFilterTeaser.down('.filter.return').hide();
		}
		else
		{
			panelFilter.up().show();
			panelFilterTeaser.down('.filter.return').show();
			panelFilter = $('panelFilterRetTime');
			setInnerHtml(panelFilter, getRetTimeFilterHtml());
		}
        
		updateFilters = false;
	}
}

function updateFilterText()
{
	var panel = $('filterText');
	setInnerHtml(panel, getFilterText());
}

function getFilterText()
{
	var text = '<span style="font-weight: bold">' + matchCount + '</span> ' + Language['FlightResults_JS_FlightsOf'] + ' ' + 
		'<span style="font-weight: bold">' + flights.length + '</span> ' + Language['FlightResults_JS_MatchesYourCriteria'] + '.';
	var morefilters = $('morefilters');
    
	if(morefilters != null && morefilters.style.display == 'none' && (filterAirline.length > 0 ||
		filterTicket.length > 0 || filterOrig.length > 0 || filterDest.length > 0 || filterPriceRange > 0))
		text += ' <strong>' + Language['FlightResults_JS_HiddenFilters'] + '</strong>';
	return text;
}

function getLookup(type)
{
	if (type == 'Supplier')
		return suppliers;
	else if (type == 'Airline')
		return airlines;
	else if (type == 'Ticket')
		return tickets;
	else if (type == 'Orig')
		return origs;
	else if (type == 'Dest')
		return dests;
}

function getFilterList(type)
{
	if (type == 'Supplier')
		return filterSupplier;
	else if (type == 'Airline')
		return filterAirline;
	else if (type == 'Ticket')
		return filterTicket;
	else if (type == 'Orig')
		return filterOrig;
	else if (type == 'Dest')
		return filterDest;
}

function filterCheckAll(type)
{
	var lookup = getLookup(type);
	var list = lookup.Keys();

	var filter = getFilterList(type);
	filter.splice(0, filter.length);
    
	for(var i = 0; i < list.length; i++)
	{
		var itemval = list[i];
		if (itemval != '')
		{
			var name = 'filterCheck' + type + itemval;
			var checkbox = $(name);
			if (checkbox)
				checkbox.checked = true;
		}
	}
}

function filterAll(type)
{
	filterCheckAll(type);
	processFlightsWait();
}

function filterOnly(type,value)
{
	var lookup = getLookup(type);
	var list = lookup.Keys();
    
	var filter = getFilterList(type);
	filter.splice(0, filter.length);

	for(var i = 0; i < list.length; i++)
	{
		var itemval = list[i];
		if (itemval != '')
		{
			if(type != 'Supplier')
			{
				var name = 'filterCheck' + type + itemval;
				var checkbox = $(name);
				if (checkbox)
				{
					if (itemval == value)
					{
						checkbox.checked = true;
					}
					else
					{
						checkbox.checked = false;
						filter.push(itemval);
					}
				}
			}
			else
			{
				if(itemval != value)
					filter.push(itemval);
			}
		}
	}

	processFlightsWait();
	if(type == 'Orig' || type == 'Dest')
		showInnovata();
}

function filterOnlyClicked(type, value)
{
	filterOnly.defer(type, value);
}

function filterChanged(type, value, checked)
{
	var filter = getFilterList(type);
	if (checked)
	{
		// remove from filter
		var i = filter.indexOf(value);
		if (i >= 0)
			filter.splice(i, 1);
	}
	else
	{
		// add to filter
		filter.condAdd(value);
	}

	processFlightsWait();
	if (type == 'Orig' || type == 'Dest')
		showInnovata();
}

function filterClicked(type, checkbox)
{
	filterChanged.defer(type, checkbox.value, checkbox.checked);
}

function checkboxHtmlEx(type, checked, funcname, eventname, code, text, hint, showcode)
{
	var name = 'filterCheck' + type + code;
	var link = '<a href="javascript:' + funcname + '(\'' + type + '\',\'' + code + '\')" title="' + hint + '">';
	var disp = text + (showcode ? ' (' + code + ')' : '');
	/*if (type == 'Supplier')
		disp = '<img src="' + logoPath + code + '.png" />';*/
	return '<tr><td><input id="' + name + '" class="filter" value="' + code + '" type="checkbox" ' + (checked ? 'checked' : '') + ' onclick="' + eventname + '(\'' + type + '\',this)" title="' + hint + '" /></td><td>' + link + disp + '</a></td></tr>';
}

function checkboxHtml(type, checked, code, text, showcode)
{
	return checkboxHtmlEx(type, checked, 'filterOnlyClicked', 'filterClicked', code, text, showcode);
}

function radioHtmlEx(type, checked, funcname, eventname, code, text, hint, showcode)
{
	var id = 'filterRadio' + type + code;
	var name = 'filterRadio' + type;
	var link = '<a href="javascript:' + funcname + '(\'' + type + '\',\'' + code + '\')" title="' + hint + '">';
	return '<tr><td><input id="' + id + '" name="' + name + '" class="filter" value="' + code + '" type="radio" ' + (checked ? 'checked' : '') + ' onclick="' + eventname + '(\'' + type + '\',this.value)" title="' + hint + '" /></td><td>' + link + text + (showcode ? ' (' + code + ')' : '') + '</a></td></tr>';
}

function ticketComparePairValues(a, b)
{
	var t1 = ticketClassOrder(a.key);
	var t2 = ticketClassOrder(b.key);
	if (t1 == t2) 
		return 0;
	if (t1 > t2) 
		return 1;
	return -1;
}

function dropDownChanged(type,value)
{
	if(value == '')
		filterAll(type);
	else
		filterOnly(type,value);
}

function getFilterDropdownHtml(type, list, filterlist)
{
	var html = '<select onchange="dropDownChanged(\'' + type + '\',this.options[this.selectedIndex].value)">';
	
	html += '<option value="">' + Language["FlightResults_JS_AllSuppliers"] + '</option>';

	var pairs = list.Pairs();
	pairs.sort(dictionaryComparePairValues);
    
	for (var i = 0; i < pairs.length; i++)
	{
		var pair = pairs[i];
		if(type == 'Supplier' && pair.key.length == 2)
			continue;
		if (pair.key != '' && pair.value != '')
		{
			var selected = '';
			if(filterlist.length > 0 && !filterlist.contains(pair.key))
				selected = ' selected="selected"';
			html += '<option value="' + pair.key + '"' + selected + '>' + pair.value + '</option>';
		}
	}
		
	html += '</select>';
	return html;
}

function getFilterHtml(type, list, filterlist, showcode, comparefunc)
{
	var html = '<table cellspacing="0" cellpadding="0">';

	var pairs = list.Pairs();
	if (comparefunc == null)
		pairs.sort(dictionaryComparePairValues);
	else
		pairs.sort(comparefunc);
        
	for (var i = 0; i < pairs.length; i++)
	{
		var pair = pairs[i];
		if(type == 'Supplier' && pair.key.length == 2)
			continue;
		if (pair.key != '' && pair.value != '')
			html += checkboxHtml(type, !filterlist.contains(pair.key), pair.key, pair.value, pair.value + ' (' + pair.key + ')', showcode);
	}

	html += '</table>';
	return html;
}

function getSupplierFilterHtml()
{
	return getFilterDropdownHtml('Supplier', suppliers, filterSupplier);
}

function getAirlineFilterHtml()
{
	return getFilterHtml('Airline', airlines, filterAirline, false);
}

function getTicketFilterHtml()
{
	return getFilterHtml('Ticket', tickets, filterTicket, false, ticketComparePairValues);
}

function getOrigFilterHtml()
{
	return getFilterHtml('Orig', origs, filterOrig, false);
}

function getDestFilterHtml()
{
	return getFilterHtml('Dest', dests, filterDest, false);
}

function linkRadioClicked(type, code)
{
	var id = 'filterRadio' + type + code;
	var radio = $(id);
	if (radio)
	{
		radio.checked = true;
		if (type == 'Prices')
			filterPricesClicked(type, code);
		else 
			filterTimeClicked(type, code);
	}
}

function filterPricesChanged(type, code)
{
	filterPriceRange = parseInt(code);

	filterMinPrice = 0;
	filterMaxPrice = 100000;
	if (filterPriceRange > 0)
	{
		var idx = filterPriceRange-1;
        
		if (idx > 0)
			filterMinPrice = filterPriceRanges[idx-1];

		if (idx < filterPriceRanges.length)        
			filterMaxPrice = filterPriceRanges[idx];
	}

	processFlightsWait();
}

function filterPricesClicked(type, value)
{
	filterPricesChanged(type, value);
}

function getPricesFilterHtml()
{
	var len = filterPriceRanges.length;
    
	var html = '<table cellspacing="0" cellpadding="0">';
    
	html += radioHtmlEx('Prices', filterPriceRange == 0, 'linkRadioClicked', 'filterPricesClicked', '0', Language['FlightResults_JS_AllPrices'], '', false);
	for (var i = 0; i < len; i++)
	{
		var n = i+1;
		var text = filterPriceRangesText[i];
		html += radioHtmlEx('Prices', filterPriceRange == n, 'linkRadioClicked', 'filterPricesClicked', n.toString(), text, '', false);
	}

	html += '</table>';
	return html;
}

function updatePriceRanges()
{
	filterPriceRanges = [];
	filterPriceRangesText = [];

	var len = flights.length;
	if (len > 0)
	{
		var avg = sumPrice / len;
		var diff = avg / 3;
        
		var prev = '0';
		var prevconv = 0;
		var price = avg - diff;
		var last = filterPriceRangeCount-1;
		for (var i = 0; i < last; i++)
		{
			var conv = currencyConvert(price);
			conv = Math.floor(conv / 100) * 100;

			// make sure we are not presenting a range = 0 - 0 GBP
			if (conv <= prevconv) 
				conv = prevconv + 100; 
            
			var priceStr = formatPriceEx(conv, false);
			filterPriceRangesText[i] = prev + ' - ' + priceStr + ' ' + curCurrency;
			filterPriceRanges[i] = currencyConvertEUR(conv); // convert back to EUR

			prev = priceStr;
			prevconv = conv;
			price += diff;
		}
		filterPriceRangesText[last] = Language['FlightResults_JS_PricesAbove'] + ' ' + prev + ' ' + curCurrency;
		filterPriceRanges[last] = 100000;
	}
    
	updateFilters = true;
}

function setFilterTime(type, value)
{
	var minTime = 0;
	var maxTime = 0;
	switch (value)
	{
		case 1:
			minTime = 0;
			maxTime = 600;  // 10:00
			break;
		case 2:
			minTime = 600;  // 10:00
			maxTime = 840;  // 14:00
			break;
		case 3:
			minTime = 840;  // 14:00
			maxTime = 1080; // 18:00
			break;
		case 4:
			minTime = 1080; // 18:00
			maxTime = 1440; // 24:00
			break;
		default:
			minTime = 0;
			maxTime = 1440;
			break;
	}
    
	if (type == 'OutTime')
	{
		filterMinOutDepTime = minTime;
		filterMaxOutDepTime = maxTime;
		filterOutTime = value;
	}
	else
	{
		filterMinRetDepTime = minTime;
		filterMaxRetDepTime = maxTime;
		filterRetTime = value;
	}
    
	updateFilters = true;
}

function filterTimeChanged(type, code)
{
	var value = parseInt(code);
	setFilterTime(type, value);
	processFlightsWait();
}

function filterTimeClicked(type, value)
{
	filterTimeChanged.defer(type, value);
}

function getSupplierFilterText()
{
	var text = Language["FlightResults_JS_AllSuppliers"];

	var pairs = suppliers.Pairs();
	for (var i = 0; i < pairs.length; i++)
	{
		var pair = pairs[i];
		if (pair.key != '' && pair.value != '')
		{
			if(filterSupplier.length > 0 && !filterSupplier.contains(pair.key))
			{
				text = pair.value;
				break;
			}
		}
	}
	return text;
}

function getSortByText()
{
	switch(curView)
	{
		case 0:
			return Language['FlightResults_LiteralPriceAndSupplier.Text'];
		case 1:
			return Language['FlightResults_LiteralPriceAndAirline.Text'];
		case 2:
			return Language['FlightResults_LiteralOnlyPrice.Text'];
		case 3:
			return Language['FlightResults_LiteralDepartureTime.Text'];
		case 4:
			return Language['FlightResults_LiteralReturnTime.Text'];
		case 5:
			return Language['FlightResults_LiteralRating.Text'];
	}
	return '';
}

function getTimeFilterText(selected)
{
	switch(selected)
	{
		case 0:
			return Language['FlightResults_JS_AllTimes'];
		case 1:
			return Language['FlightResults_JS_Morning'];
		case 2:
			return Language['FlightResults_JS_Noon'];
		case 3:
			return Language['FlightResults_JS_Afternoon'];
		case 4:
			return Language['FlightResults_JS_Evening'];
	}
	return '';
}

function getTimeFilterHtml(type, selected, linkevent, radioevent)
{
	var html = '<table cellspacing="0" cellpadding="0">';
    
	html += radioHtmlEx(type, selected == 0, linkevent, radioevent, '0', getTimeFilterText(0), '00:00 - 24:00', false);
	html += radioHtmlEx(type, selected == 1, linkevent, radioevent, '1', getTimeFilterText(1), '00:00 - 10:00', false);
	html += radioHtmlEx(type, selected == 2, linkevent, radioevent, '2', getTimeFilterText(2), '10:00 - 14:00', false);
	html += radioHtmlEx(type, selected == 3, linkevent, radioevent, '3', getTimeFilterText(3), '14:00 - 18:00', false);
	html += radioHtmlEx(type, selected == 4, linkevent, radioevent, '4', getTimeFilterText(4), '18:00 - 24:00', false);

	html += '</table>';
	return html;
}

function getOutTimeFilterHtml()
{
	return getTimeFilterHtml('OutTime', filterOutTime, 'linkRadioClicked', 'filterTimeClicked');
}

function getRetTimeFilterHtml()
{
	return getTimeFilterHtml('RetTime', filterRetTime, 'linkRadioClicked', 'filterTimeClicked');
}

/* Statistical Analasis */
var Statistics = Class.create(
{
	initialize: function()
	{
		this._total = 0;
		this._data = [];
		this._recalculate = true;
	},

	// internal calculate statistics
	_calculate: function()
	{
		if(this._recalculate)
		{
			if(this._data.length == 0)
				throw "No data";

			this._recalculate = false;
			this._data.sort();
			this._average = this._total / this._data.length;
			this._median = this._data[this._data.length / 2];
		}
	},

	addObservation: function(obs)
	{
		this._total += obs;
		this._data[this._data.length] = obs;
		this._recalculate = true;
	},

	average: function()
	{
		this._calculate();
		return this._average;
	},

	median: function()
	{
		this._calculate();
		return this._median;
	},

	percentile: function(percent)
	{
		this._calculate();
		return this._data[this._data.length * (percent / 100)];
	}
});

// ********** help functions for rating **********

function getDepTime(fl, segs)
{
	if (segs.length > 0)
		return segs[0].deptime;
	return -1;
}

function getArvTime(fl, segs)
{
	if (segs.length > 0)
		return segs[segs.length-1].arvtime;
	return -1;
}

function getDur(segs)
{
	var dur = 0;
	if (segs.length > 0)
	{
		for (var i = 0; i < segs.length; i++)
		{
			dur += segs[i].dur;
		}
	}
	return dur;
}

function getStops(segs)
{
	if(segs.length == 1)
		return segs[0].stops;
	return segs.length-1;
}

function getDays(fl)
{
	var depdate = convertDate(fl.depdate);
	var retdate = convertDate(fl.retdate);
	var oneday = 86400000; // 1000*60*60*24;

	return Math.floor((retdate.getTime() - depdate.getTime()) / oneday);
}

// ********** rating **********

// NOTE: score is a number between 0 and 1 - NOT including 1!

var defaultDurScore = 0.7;
var defaultDepScore = 0.7;
var defaultAptScore = 1;

var minDurOut = 0;
var maxDurOut = 0;
var minDurRet = 0;
var maxDurRet = 0;

var minStopsOut = -1;
var maxStopsOut = 0;
var minStopsRet = -1;
var maxStopsRet = 0;

var durationStatsOut = new Statistics();
var durationStatsRet = new Statistics();
var stopsStatsOut = new Statistics();
var stopsStatsRet = new Statistics();

var durationAvgsOut = [];
var durationAvgsRet = [];

function rateFlights()
{
	minDurOut = 0;
	maxDurOut = 0;
	minDurRet = 0;
	maxDurRet = 0;

	minStopsOut = -1;
	maxStopsOut = 0;
	minStopsRet = -1;
	maxStopsRet = 0;

	durationStatsOut = new Statistics();
	durationStatsRet = new Statistics();
	stopsStatsOut = new Statistics();
	stopsStatsRet = new Statistics();

	durationAvgsOut = [];
	durationAvgsRet = [];

	for (var i = 0; i<flights.length; i++)
	{
		var fl = flights[i];
		prepareRating(fl);
	}
    
	for (var i = 0; i<flights.length; i++)
	{
		var fl = flights[i];
		fl.score = calcScore(fl);
	}

	showFlights(null);
}

function updateStatisticsOut(segs)
{
	var stops = getStops(segs);
	var dur = getDur(segs);

	if (dur > 0)
	{
		if (dur > maxDurOut)
			maxDurOut = dur;
		if (minDurOut == 0 || dur < minDurOut)
			minDurOut = dur;
	}

	if (stops >= 0)
	{
		if (stops > maxStopsOut)
			maxStopsOut = stops;
		if (minStopsOut == -1 || stops < minStopsOut)
			minStopsOut = stops;
	}

	stopsStatsOut.addObservation(stops);
	if(dur > 0)
	{
		durationStatsOut.addObservation(dur);
		
		if(stops != -1)
		{
			if(typeof durationAvgsOut[stops] == 'undefined')
				durationAvgsOut[stops] = new Statistics();
			durationAvgsOut[stops].addObservation(dur);
		}
	}
}

function updateStatisticsRet(segs)
{
	var stops = getStops(segs);
	var dur = getDur(segs);

	if (dur > 0)
	{
		if (dur > maxDurRet)
			maxDurRet = dur;
		if (minDurRet == 0 || dur < minDurRet)
			minDurRet = dur;
	}

	if (stops >= 0)
	{
		if (stops > maxStopsRet)
			maxStopsRet = stops;
		if (minStopsRet == -1 || stops < minStopsRet)
			minStopsRet = stops;
	}

	stopsStatsRet.addObservation(stops);
	if(dur > 0)
	{
		durationStatsRet.addObservation(dur);
		
		if(stops != -1)
		{
			if(typeof durationAvgsRet[stops] == 'undefined')
				durationAvgsRet[stops] = new Statistics();
			durationAvgsRet[stops].addObservation(dur);
		}
	}
}

function prepareRating(fl)
{
	updateStatisticsOut(fl.outsegs);
	if (!fl.oneway)
		updateStatisticsRet(fl.retsegs);
}

function calcScore(fl)
{
	var scorePrice = calcScore_Price(fl);
	var scoreDurOut = calcScore_DurOut(fl);
	var scoreAptOutOrig = calcScore_Apt(fl, fl.outsegs, true);
	var scoreAptOutDest = calcScore_Apt(fl, fl.outsegs, false);
	var scoreAptOut = (scoreAptOutOrig + scoreAptOutDest) / 2;

	var score = 0;
	if (fl.oneway)
	{
		score = 
			0.50 * scorePrice + 
			0.30 * scoreAptOut +
			0.20 * scoreDurOut;
	}
	else
	{
		var scoreDurRet = calcScore_DurRet(fl);
		var scoreAptRetOrig = calcScore_Apt(fl, fl.retsegs, true);
		var scoreAptRetDest = calcScore_Apt(fl, fl.retsegs, false);
		var scoreAptRet = (scoreAptRetOrig + scoreAptRetDest) / 2;
		var scoreStay = calcScore_Stay(fl);

		score = 
			0.40 * scorePrice + 
			0.15 * scoreAptOut +
			0.15 * scoreAptRet +
			0.10 * scoreDurOut +
			0.10 * scoreDurRet +
			0.10 * scoreStay;
            
		fl.scoreDurRet = scoreDurRet;
		fl.scoreAptRet = scoreAptRet;
		fl.scoreStay = scoreStay;
	}
    
	fl.scorePrice = scorePrice;
	fl.scoreDurOut = scoreDurOut;
	fl.scoreAptOut = scoreAptOut;
    
	return score;
}

function calcScore_Price(fl)
{
	var avg = sumPrice / flights.length;
	var diff = avg - minPrice; 
	var price = fl.price - minPrice;
	if (price > diff)
		return 0;
        
	var score = (diff == 0 ? 1 : 1 - price / diff);
	return score;
}

function calcScore_Dur(fl, segs, minDur, maxDur, minStops, maxStops, durationStats, durationAvgs, stopsStats)
{
	var dur = getDur(segs);
	var stops = getStops(segs);
	
	if(dur == 0 && stops != -1 && typeof durationAvgs[stops] != 'undefined')
		try
		{
			dur = durationAvgs[stops].average();
		}
		catch(e)
		{
			dur = 0;
		}

	var durationAvg = 0;
	try
	{
		durationAvg = durationStats.average();
	}
	catch(e)
	{
	}
	var stopsAvg = -1;
	try
	{    
		stopsAvg = stopsStats.average();
	}
	catch(e)
	{
	}

	if(durationAvg == 0 && stopsAvg == -1)
		return 0.5;
		
	if(stops == -1)
		stops = stopsAvg;
	var span = maxStops - minStops;
	var diff = stops - minStops;
	var ret = (span == 0 ? 1 : 1 - diff / span);
	stopsScore = (ret < 0 ? 0 : ret);

	if(dur != 0)
	{    
		maxDur = (durationAvg * 2 < maxDur ? durationAvg * 2 : maxDur);
		span = maxDur - minDur;
		diff = dur - minDur;

		ret = (span == 0 ? 1 : 1 - diff / span);
		durScore = (ret < 0 ? 0 : ret);
		return (stopsScore * 0.5) + (durScore * 0.5);
	}
	return (stopsScore * 0.5);
}

function calcScore_DurOut(fl)
{
	return calcScore_Dur(fl, fl.outsegs, minDurOut, maxDurOut, minStopsOut, maxStopsOut, durationStatsOut, durationAvgsOut, stopsStatsOut);
}

function calcScore_DurRet(fl)
{
	return calcScore_Dur(fl, fl.retsegs, minDurRet, maxDurRet, minStopsRet, maxStopsRet, durationStatsRet, durationAvgsRet, stopsStatsRet);
}

function calcScore_Apt(fl, segs, isOrig)
{
	if (segs.length == 0)
		return defaultAptScore;
        
	var match = 0;
	if (isOrig)
	{
		var s = segs[0];
		if (s)
			match = s.origmatch;
	}
	else
	{
		var s = segs[segs.length-1];
		if (s)
			match = s.destmatch;
	}
    
	if (match < 2)
		return 1;
	else if (match == 2)
		return 0.5;
	else 
		return 0;
}

function calcScore_DepOut(fl)
{
	var time = getDepTime(fl, fl.outsegs);
	if (time < 0)
		return defaultDepScore; // time is not available
	if (time < 6)
		return 0.3;
	if (time <= 10)
		return 1;
	if (time <= 14)
		return 0.8;
	if (time <= 20)
		return 0.6;
	return 0.5;
}

function calcScore_DepRet(fl)
{
	var time = getDepTime(fl, fl.retsegs);
	if (time < 0)
		return defaultDepScore; // time is not available
	if (time < 6)
		return 0.3;
	if (time <= 10)
		return 0.8;
	if (time <= 17)
		return 0.5;
	if (time <= 22)
		return 0.8;
	return 0.3;
}

function calcScore_Stay(fl)
{
	var days = getDays(fl);

	var arvtime = getArvTime(fl, fl.outsegs);
	var rettime = getDepTime(fl, fl.retsegs);

	var stay = days * 1440 + rettime - arvtime;
	var span = (days + 1) * 1440;
    
	return (span == 0 ? 1 : stay / span);
}

function formatScore(score)
{
	var scoreDec = Math.floor(100 * score) / 100;
	return scoreDec.toString();
}

function getStarsEx(score, attr)
{
	var score2 = score;
	if (score2 > 1) score2 = 1;
	if (score2 < 0) score2 = 0;

	var scoreIndex = Math.round(score2 * 5);
	if (scoreIndex == 0) scoreIndex = 1;
	var scoreStr = scoreIndex.toString();
	var scoreDesc = Language['FlightResults_JS_TotalScore'] + ': ' + formatScore(score2 * 5);

	var html = '';
	var left = true;
	var lit = 'on';
	for(var i=0;i<10;i++)
	{
		var direction = 'left';
		if(!left)
			direction = 'right';
		left = !left;
		html += '<img src="' + imagePath + 'star-' + direction + '-' + lit + '-blue.gif" alt="" ' + attr + '/>';
		if((i/2) > score*5)
			lit = 'off';
	}
	return html;//'<img src="' + imagePath + 'stars_small' + scoreStr + '.gif" alt="' + scoreDesc + '" ' + attr + '/>';
}

function getStars(score)
{
	return getStarsEx(score, '');
}

function outputScore(fl)
{
	return outputScoreEx(fl, '');
}

function outputScoreEx(fl, base, content)
{
	// if this flight is grouped by price - use the score from the "mapped" flight
	if (fl.groupfl != null && fl.groupfl.score != null)
		fl = fl.groupfl;

	var wOutput = '';
	if (fl.score != null)
	{
		if (typeof base == 'undefined' || base == null) base = '';
            
		var panel = '<div id="' + base + 'rating_' + fl.index + '" class="rating" style="display: none;">rating</div>';

		var events = 'onmouseover="showRatingEx(' + fl.index + ', \'' + base + '\')" onmouseout="hideRatingEx(' + fl.index + ', \'' + base + '\')"';
		if(content)
		{
			wOutput += '<span ' + events + '>' + content + '</span>' + panel;
		}
		else
		{
			wOutput += '<div class="stars">' + getStarsEx(fl.score, events) + '</div>';
			wOutput += '<div class="ratingpanel">' + panel + '</div>';
		}
	}
	return wOutput;
}

function showRating(index)
{
	showRatingEx(index, '');
}

function showRatingEx(index, base)
{
	var panel = $(base + 'rating_' + index.toString());
	if (panel != null)
	{
		var fl = flights[index];
        
		if (fl.score != null)
		{
			var html = '<h2 class="header blue">' + Language['FlightResults_JS_Rating'] + '</h2>';
			html += '<div class="info">';
			html += '<table cellspacing="0" cellpadding="0" style="width:100%">';
			html += '<tr><td>' + Language['FlightResults_JS_Price'] + '</td><td class="stars">' + getStars(fl.scorePrice) + '</td></tr>';
			if (fl.scoreAptOut < 1)
				html += '<tr><td>' + Language['FlightResults_JS_OutboundAirports'] + '</td><td class="stars">' + getStars(fl.scoreAptOut) + '</td></tr>';
			html += '<tr><td>' + Language['FlightResults_JS_OutboundDuration'] + '</td><td class="stars">' + getStars(fl.scoreDurOut) + '</td></tr>';
			if (!fl.oneway)
			{
				if (fl.scoreAptRet < 1)
					html += '<tr><td>' + Language['FlightResults_JS_HomeboundAirports'] + '</td><td class="stars">' + getStars(fl.scoreAptRet) + '</td></tr>';
				html += '<tr><td>' + Language['FlightResults_JS_HomeboundDuration'] + '</td><td class="stars">' + getStars(fl.scoreDurRet) + '</td></tr>';
				html += '<tr><td>' + Language['FlightResults_JS_TimeAtDestination'] + '</td><td class="stars">' + getStars(fl.scoreStay) + '</td></tr>';
			}
			html += '</table></div>';

			setInnerHtml(panel, html);
			showPanel(panel);
		}
	}
}

function hideRating(index)
{
	hideRatingEx(index, '');
}

function hideRatingEx(index, base)
{
	var panel = $(base + 'rating_' + index.toString());
	hidePanel(panel);
}

function getSupplierRatingHtml(supplier)
{
	var html = '';
	if (supplier) 
	{
		var showLink = false;
		if (supplierInfo)
			showLink = true; // supplierInfo dialog must be initialized - otherwise do not link

		var rating = supplier.rating;
		var ratingCount = supplier.ratingCount;
		if (ratingCount > 0 && rating > 0)
		{
			var score = rating.toString();
			if (score.length == 1) score += '.0';

			var link = '<a href="javascript:openSupplierInfo(\'' + supplier.id + '\')">';
            
			html += '<table cellspacing="0" cellpadding="0"><tr>';
			html += '<td class="rating-count">(' + link + ratingCount + ' ' + Language['FlightResults_JS_Ratings'] + '</a>)</td>';
			html += '<td class="rating">' + score + '</td>';
			html += '<td>';
			var width = Math.round(72.0 * rating / 5.0);
			html += '<div class="starbar">';
			if (showLink) html += link;
			html += '<div class="outer">';
			html += '<div class="inner" style="width:' + width + 'px"></div>';
			html += '</div>';
			if (showLink) html += '</a>';
			html += '</div>';
			html += '</td></tr></table>';
		}
	}
	return html;
}

function openSupplierInfo(supplierId)
{
	if (supplierInfo)
	{
		var s = getSupplier(supplierId);
		supplierInfo.setSupplier(s);
		supplierInfo.show();
	}
}

// ********** tip a friend **********

function getFlightHtmlSimple(fl)
{
	var logo = getAirlineLogo(fl);

	var html = '<div class="flight">';
	html += '<table cellspacing="4" cellpadding="0" border="0" style="width: 100%"><tr>';

	html += '<td>';
	html += '<table cellspacing="0" cellpadding="0" border="0" style="width:100%"><tr class="outbound">';
	html += '<td class="outbound"><img src="' + imagePath + 'plane_right.png" alt="" /></td>';
	html += '<td class="date">' + outputDate(fl.depdate) + '</td>';
	html += '<td class="route">' + getOrig(fl.outsegs[0]) + '<br />' + getDest(fl.outsegs[0]) + '</td>'; 
	html += '<td class="flightno">' + outputFlightNo(fl.outsegs[0]) + '</td>';
	html += '<td class="times"><strong>' + minToTime(fl.outsegs[0].deptime) + '</strong> - ' + minToTime(fl.outsegs[0].arvtime) + '</td>'; 
	html += '<td class="stops">' + (fl.outsegs[0].stops >= 0 ? fl.outsegs[0].stops : '') + '</td>'; 
	html += '<td class="duration">' + (fl.outsegs[0].dur > 0 ? ' (' + minToTime(fl.outsegs[0].dur,true) + ')' : '') + '</td>'; 
	html += '</tr>';
	if (!fl.oneway)
	{
		html += '<tr>';
		html += '<td class="homebound"><img src="' + imagePath + 'plane_left.png" alt="" /></td>';
		html += '<td class="date">' + outputDate(fl.retdate) + '</td>';
		html += '<td class="route">' + getOrig(fl.retsegs[0]) + '<br />' + getDest(fl.retsegs[0]) + '</td>'; 
		html += '<td class="flightno">' + outputFlightNo(fl.retsegs[0]) + '</td>';
		html += '<td class="times"><strong>' + minToTime(fl.retsegs[0].deptime) + '</strong> - ' + minToTime(fl.retsegs[0].arvtime) + '</td>'; 
		html += '<td class="stops">' + (fl.retsegs[0].stops >= 0 ? fl.retsegs[0].stops : '') + '</td>'; 
		html += '<td class="duration">' + (fl.retsegs[0].dur > 0 ? ' (' + minToTime(fl.retsegs[0].dur,true) + ')' : '') + '</td>'; 
		html += '</tr>';
	}
	html += '</table></td>';
    
	// best supplier price
	html += '<td class="price">' + formatPrice(fl.price) + ' ' + curCurrency + '</a></td>';
	html += '</tr></table>';

	html += '</div></div>';
	return html;
}

function getFlightText(fl)
{
	var text = '';
    
	text += (fl.oneway ? 'Flyrejse' : 'Udrejse') + ':\n';

	var s = fl.outsegs[0];
	text += outputDateEx(fl.depdate) + ' kl. ' + minToTime(s.deptime) + ', ' + getOrigEx(s) + ' - ' + getDestEx(s);
	text += ', ankomst kl. ' + minToTime(s.arvtime);
	text += ' med ' + (s.airline == '' ? fl.supplier.id : s.airline) + ' ' + outputFlightNo(s) + '\n';
    
	if (!fl.oneway)
	{
		text += '\nHjemrejse:\n';
        
		s = fl.retsegs[0];
		text += outputDateEx(fl.retdate) + ' kl. ' + minToTime(s.deptime) + ', ' + getOrigEx(s) + ' - ' + getDestEx(s);
		text += ', ankomst kl. ' + minToTime(s.arvtime);
		text += ' med ' + (s.airline == '' ? fl.supplier.id : s.airline) + ' ' + outputFlightNo(s) + '\n';
	}
    
	text += '\nFlybilletten udbydes af ' + fl.supplier.name + '.';
    
	/*
	var linked = getFlightGroup(fl.key, true);
	for(var i = 0; i<linked.length; i++)
	{
		var f = linked[i];
		text += '\n' + f.supplier.name + ' - ' + getFlightPrice(f);
	}
	*/
    
	return text;
}

function getFlightPrice(fl)
{
	return formatPrice(fl.price) + ' ' + curCurrency;
}

function getFlightSubject(fl)
{
	return 'Flybillet ' + getOrig(fl.outsegs[0]) + ' - ' + getDest(fl.outsegs[0]) + ', fra ' +  formatPrice(fl.price) + ' ' + curCurrency;
}

/******* Top flights *******/

function updateTop(done)
{
	cheapestFlight = flights[0];
}

/******* Flight Top Ads *******/

function renderTopAds()
{
    var html = '';
	var div = $('flightads');
	if (isCPH && searchorig == 'CPH')
	{
		html = '<div style="padding-bottom:30px"><a href="/partner/CPH/TaxFree.aspx" target="_blank"><img src="/partner/CPH/taxfree.gif" alt="Tax Free" width="620" style="width:620px" /></a></div>';
	}
	else if (typeof GFlightAds != 'undefined')
	{
		var topAds = GFlightAds.getTopAds();
		html = getTopAdsHtml(topAds);
	}
	div.update(html);
}

function getTopAdsHtml(topAds)
{
	var html = '';
	if (topAds != null && topAds.length > 0)
	{
		html += '<div class="description">' + Language['FlightResults_JS_RouteSponsors'] + '</div>';
	    html += '<div class="flightads"><table cellpadding="0" cellspacing="0" style="margin-left:12px"><tr>';
		for(var i = 0; i < topAds.length; i++)
		{
			html += getTopAdHtml(i, topAds[i]);
		}
		html += '</tr></table></div>';
	}
	return html;
}

function getTopAdHtml(i, p)
{
	setTopAdSupplier(p.supplierId, p);
    
	var logo = getSupplierLogo2(p.supplierId);
	var url = getSupplierRedirectLink(p.supplierId, 'topad', i+1) + '&p=' + p.id + '&url=' +  escape(p.redirUrl);

	var html = '<td><div class="flightad" id="flightad' + i.toString() + '">';
	html += '<div class="logo"><a href="' + url + '" target="_blank">' + logo + '</a></div>';
	html += '<div class="text">' + p.text + '</div>';
	html += '<div class="link"><a href="' + url + '" target="_blank" class="green">' + p.displayUrl + '</a></div>';
	html += '</div></td>';
	return html;
}

function setTopAdSupplier(supplierId, value)
{
	if (!topAdSuppliers)
		topAdSuppliers = {};
	topAdSuppliers[supplierId] = value;
}

function isTopAdSupplier(supplierId)
{
	if (topAdSuppliers)
		return topAdSuppliers[supplierId];
	return false;
}

/******* Error suppliers *******/

function getErrorHtml(supplierid, name, orig, origname, dest, destname, type, rating, outresultcount, outminprice, homeresultcount, homeminprice)
{
	var redirUrl = getRedirectLinkEx(supplierid, orig, dest, searchoneway, searchdepdate, searchretdate) + '&ref=error';
	var url = '';

	var html = '<div id="error' + supplierid + '" class="group">';
	html += '<div class="groupheader">' +
		'<table cellspacing="0" cellpadding="0" class="groupheader" style="float:left"><tr>' +
		'<td class="logo"><a href="' + redirUrl + '" target="_blank">' + getSupplierLogo2(supplierid) + '</a></td>' +
		'<td class="name">' + name /* + getSupplierImg(supplierid) [replaced by addSupplierImg] */ + '</td>' +
		'</tr></table>' +
		'<div class="url" style="float:right"><a href="' + redirUrl + '" target="_blank" class="green">' + url + '</a></div>' +
		'<div class="clearfloats" style="clear:both"></div></div>';

	html += '<div class="error">' +
		'<table cellpadding="0" cellspacing="0">' +
		'<tr><td class="error">';
	if (outresultcount == 0 && homeresultcount == 0)
		html += String.format(Language['FlightResults_JS_ZeroResultsError'], name, '<b>' + origname + ' - ' + destname + '</b>');
	else if (outresultcount > 0 && homeresultcount == 0)
		html += String.format(Language['FlightResults_JS_NoReturnFlightsError'], name, '<b>' + origname, destname + '</b>', curCurrency, formatPrice(outminprice));
	else if (outresultcount == 0 && homeresultcount > 0)
		html += String.format(Language['FlightResults_JS_NoOutFlightsError'], name, '<b>' + destname, origname + '</b>', curCurrency, formatPrice(homeminprice));
	html += '</td><td class="priceinfo"><input type="button" class="button_black" onclick="window.open(\'' + redirUrl + '\');return false;" value="' + Language['FlightResults_JS_Visit'] + '" /></td>';
	html + '</tr>' +
		'</table>' +
		'</div>';

	html += '</div>';

	return html;
}

/********** matrix *********/

var matrix = null;
var matrixValues = null;

function updateMatrix(list)
{
	matrix = {};
	matrixValues = [];
    
	var hash = {};
    
	for(var i=0; i<list.length; i++)
	{
		var fl = list[i];

		var x = '';
		if (supplierView)
			x = fl.supplier.id;
		else
			x = getFlightAirline(fl);
            
		var y = getFlightStops(fl);

		var key = getMatrixKeyEx(x, y);
		var entry = matrix[key];
		if (entry == null)
		{
			entry = {};
			entry.x = x;
			entry.y = y;
			entry.fl = fl;
			matrix[key] = entry;
            
			if (!hash[x])  // already added x (supplier or airline) to matrixValues?
			{
				hash[x] = entry;
				matrixValues.push(x);
			}
		}
	}
}

function showMatrix()
{
	var panel = $('matrix');
    
	if (panel)
	{
		var html = getMatrixHtml();
		setInnerHtml(panel, html);
	}
}

function getMatrixHtml()
{
	var html = '';
    
	if (matrix)
	{
		var head = '<td class="corner">&nbsp;</td>';
		var rows = [];
		rows[0] = '<td class="y">non-stop</td>';
		rows[1] = '<td class="y">1 stop</td>';
		rows[2] = '<td class="y">2+ stops</td>';
		rows[3] = '<td class="y">(not known)</td>';
        
		var hasUnk = false;
            
		for (var v=0; v<matrixValues.length; v++)
		{
			var x = matrixValues[v];
			head += getMatrixHead(x);
			rows[0] += getMatrixCell(x, 0);
			rows[1] += getMatrixCell(x, 1);
			rows[2] += getMatrixCell(x, 2);

			var e = getMatrixEntry(x, -1);
			if (e) hasUnk = true;
			rows[3] += getMatrixEntryCell(e);
		}
        
		var lastRow = 2;
		if (hasUnk) lastRow = 3;

		html += '<table cellspacing="0" cellpadding="0" class="matrix">';
		html += '<tr>' + head + '</tr>';
		for (var r=0; r<=lastRow; r++)
			html += '<tr>' + rows[r] + '</tr>';
		html += '</table>';
	}
    
	return html;
}

function getMatrixDisplay(x)
{
	if (supplierView) return suppliers[x];
	else return airlines[x];
}

function getMatrixHref(x)
{
	var t = '';
	if (supplierView) t = 'Supplier';
	else t = 'Airline';
	return 'javascript:filterMatrix(\'' + t + '\',\'' + x + '\')';
}

function getMatrixHead(x)
{
	var text = '<a href="' + getMatrixHref(x) + '">' + getMatrixDisplay(x) + '</a>';
	return '<td class="x">' + text + '</td>';
}

function getMatrixCell(x, y)
{
	return getMatrixEntryCell(getMatrixEntry(x, y));
}

function getMatrixEntry(x, y)
{
	var key = getMatrixKeyEx(x, y);
	return matrix[key];
}

function getMatrixEntryCell(entry)
{
	var val = '&nbsp;';
	if (entry != null) val = formatPrice(entry.fl.price);
	return '<td>' + val + '</td>';
}

function getFlightStops(fl)
{
	var stops = getStops(fl.outsegs);
	if (!fl.oneway)
		stops = Math.max(stops, getStops(fl.retsegs));
	return stops;
}

function getMatrixKeyEx(x, stops)
{
	var s = '?';
	if (stops >= 0)
		s = stops.toString();
	return x + '-' + s;
}

function filterMatrix(type, value)
{
	if (type == 'Supplier')
	{
		filterCheckAll('Airline');
		filterAirline = [];
	}
	else
	{
		filterCheckAll('Supplier');
		filterSupplier = [];
	}
	filterOnlyClicked(type, value);
}

/*** TimeTable ***/

function updateTimeTable(list)
{
	var hash = {};

	for (var i = 0; i < list.length; i++)
	{
	    var fl = list[i];
	}
}

function showTimeTable()
{
}

/*** Innovata ***/

var Innovata = Class.create(
{
	initialize: function(airline, flightno, orig, origairport, origterm, dest, destairport, destterm, depart, arrive, duration, returntrip)
	{
		this.airline = airline;
		this.flightno = flightno;
		this.orig = orig;
		this.origairport = origairport;
		this.origterm = origterm;
		this.dest = dest;
		this.destairport = destairport;
		this.destterm = destterm;
		this.depart = depart;
		this.arrive = arrive;
		this.duration = duration;
		this.returntrip = returntrip;
	},

	getSupplier: function()
	{
		return supplierIataList[this.airline];
	}
});

function addInnovataFlight(airline, flightno, orig, origairport, origterm, dest, destairport, destterm, depart, arrive, duration, returntrip)
{
	innovata[innovata.length] = new Innovata(airline, flightno, orig, origairport, origterm, dest, destairport, destterm, depart, arrive, duration, returntrip);
}

function sortInnovata(a, b)
{
	if (a.returntrip != b.returntrip)
	{
		if (a.returntrip)
			return 1;
		return -1;
	}
	else if (a.depart != b.depart)
		return a.depart.getTime() - b.depart.getTime();
	else if (a.duration != b.duration)
		return a.duration - b.duration;
	return 0;
}

function pad(s,c,l)
{
	while(s.length < l)
		s = c + s;
	return s;
}

function showInnovata()
{
	var html = '';

	var count = innovata.length;
	var iv = [];
	for (var i = 0; i < count; i++)
	{
		var orig = innovata[i].orig;
		var dest = innovata[i].dest;
		if (innovata[i].returntrip)
		{
			var t = orig;
			orig = dest;
			dest = t;
		}
		if (filterOrig.length > 0 && filterOrig.contains(orig))
			continue;
		if (filterDest.length > 0 && filterDest.contains(dest))
			continue;

		iv[iv.length] = innovata[i];
	}
	iv.sort(sortInnovata);

	count = iv.length;
	if (count == 0)
	{
		$('innovata').hide();
		return;
	}
	$('innovata').show();
	html += '<div class="group">';
	html += '<div class="groupheader">';
	html += '<span class="timetable_header"><img src="' + imagePath + 'timetable_outbound.gif" style="vertical-align:middle" />&nbsp;' + String.format(Language['FlightResults_JS_DepartureFlights'], mainorig, maindest) + '</span>';
	html += '</div>';

	html += '<div class="timetable"><table cellpadding="0" cellspacing="0" class="timetable">';
	html += '<tr>' +
		'<th>' + Language['FlightResults_JS_DepArr'] + '</th>' +
		'<th>' + Language['FlightResults_JS_From'] + '</th>' +
		'<th>' + Language['FlightResults_JS_To'] + '</th>' +
		'<th>' + Language['FlightResults_JS_Duration'] + '</th>' +
		'<th>' + Language['FlightResults_JS_Carrier'] + '</th>' +
		'</tr>';
	var dateShown = false;
	var headerShown = false;
	var departShown = false;
	var count = iv.length;

	var oldreturntrip = null;
	var olddepart = new Date();
	var oldduration = 0;
	var oldorigairport = null;
	var olddestairport = null;
	for (var i = 0; i < count; i++)
	{
		var origdest = iv[i].returntrip ? iv[i].dest + iv[i].orig : iv[i].orig + iv[i].dest;
		var arrowName = '';
		if (oldreturntrip != iv[i].returntrip)
		{
			oldreturntrip = iv[i].returntrip;
			dateShown = false;
			headerShown = false;
		}
		if (!headerShown)
		{
			headerShown = true;
			if (iv[i].returntrip)
			{
				html += '</table></div>';
				html += '</div>';
				html += '<div class="group">';
				html += '<div class="groupheader">';
				html += '<span class="timetable_header"><img src="' + imagePath + 'timetable_homebound.gif" style="vertical-align:middle" />&nbsp;' + String.format(Language['FlightResults_JS_ReturnFlights'], maindest, mainorig) + '</span>';
				html += '</div>';
				html += '<div class="timetable"><table cellpadding="0" cellspacing="0" class="timetable">';
				html += '<tr>' +
					'<th>' + Language['FlightResults_JS_DepArr'] + '</th>' +
					'<th>' + Language['FlightResults_JS_From'] + '</th>' +
					'<th>' + Language['FlightResults_JS_To'] + '</th>' +
					'<th>' + Language['FlightResults_JS_Duration'] + '</th>' +
					'<th>' + Language['FlightResults_JS_Carrier'] + '</th>' +
					'</tr>';
				arrowName = 'homebound';
			}
			else
			{
				arrowName = 'outbound';
			}
		}
		if (oldorigairport != iv[i].origairport)
		{
			oldorigairport = iv[i].origairport;
			departShown = false;
		}
		if (olddestairport != iv[i].destairport)
		{
			olddestairport = iv[i].destairport;
			departShown = false;
		}
		if (olddepart.getTime() != iv[i].depart.getTime())
		{
			olddepart = iv[i].depart;
			departShown = false;
		}
		if (oldduration != iv[i].duration)
		{
			oldduration = iv[i].duration;
			departShown = false;
		}
		html += '<tr>';
		if (!departShown)
		{
			departShown = true;
			html += '<td class="times">';
			html += '<strong>' + pad(iv[i].depart.getHours().toString(), '0', 2) + ':' + pad(iv[i].depart.getMinutes().toString(), '0', 2) + '</strong> - ';
			html += pad(iv[i].arrive.getHours().toString(), '0', 2) + ':' + pad(iv[i].arrive.getMinutes().toString(), '0', 2);
			html += '</td>';
			html += '<td class="route">' + iv[i].origairport + '</td><td class="route">' + iv[i].destairport + '</td>';
		}
		else
		{
			html += '<td class="times"></td>';
			html += '<td class="route"></td>';
			html += '<td class="route"></td>';
		}
		var airline = iv[i].getSupplier();
		var airlineName = '';
		var redirUrl = null;
		if (airline != null)
		{
			airlineName = airline.name;
			if (airline.id.length > 2)
				redirUrl = getRedirectLinkEx(airline.id, iv[i].orig, iv[i].dest, searchoneway, searchdepdate, searchretdate);
		}
		else
		{
			airlineName = iv[i].airline;
		}

		html += '<td class="duration">' + (iv[i].duration > 0 ? minToTime(iv[i].duration,true).toString() : '') + '</td>';
		html += '<td class="airline">';
		if (redirUrl != null)
			html += '<a target="_blank" href="' + redirUrl + '">';
		html += airlineName;
		if (redirUrl != null)
			html += '</a>';
		html += '</td>';
		html += '</tr>';

	}
	html += '</table></div>';
	html += '</div>';
	html += '</div>';

	$('innovata').innerHTML = html;
}

function addRouteSuppliers(suppliers)
{
	routeSuppliers = suppliers;
	for (var i = 0; i < routeSuppliers.length; i++)
	{
		var rs = routeSuppliers[i];
		var key = rs.id + rs.orig + rs.dest;
		routeSuppliersIndex.set(key, i);
	}
	renderRouteSuppliers();
}

function updateRouteSuppliers(force)
{
	if (searching || force)
	{
		var routeGroup = groupFlights('supplier', flights);
		var list = routeGroup.Values();
		list.sort(compareGroupsByPrice);
		routeGroup = getGroupedByPrice(list);

		var keys = routeGroup.Keys();
		var len = keys.length;
		for (var i = 0; i < len; i++)
		{
			var group = routeGroup[keys[i]];
			var index = routeSuppliersIndex.get(group.ident);
			if (typeof index != 'undefined')
			{
				var rs = routeSuppliers[index];
				if (typeof rs != 'undefined' && typeof rs.done == 'undefined')
				{
					rs.done = true;
					rs.price = group.flights[0].price;
					rs.flightCount = group.flights.length;
				}
			}
		}
		renderRouteSuppliers.defer(force);
	}
}

function renderRouteSuppliers(last)
{
	var s = $('routesuppliers');
	if (s == null)
		return;

var html = '<div style="clear:both;padding:10px;" id="routesponsorlist">';
	if (routeSuppliers.length > 0)
	{
		var headerShown = [false, false, false, false];
		for (var i = 0; i < routeSuppliers.length; i++)
		{
			var rs = routeSuppliers[i];
			if (isCPH && !checkCPH(rs.orig, null, rs.type))
				continue;
			if (!headerShown[rs.type])
			{
				headerShown[rs.type] = true;
				html += '<div class="header">';
				switch (rs.type)
				{
					case 0:
						html += Language['general_lowcost'];
						break;
					case 1:
						html += Language['general_classic'];
						break;
					case 2:
						html += Language['general_travelagency'];
						break;
					case 3:
						html += Language['general_train'];
						break;
				}
				html += '</div>';
			}

			var orig = rs.orig;
			var dest = rs.dest;
			html += '<div class="supplier"><table cellspacing="0" cellpadding="0">' +
				'<tr><td class="logo" rowspan="2">' +
				'<a href="' + getSupplierRedirectLink(rs.id, null, null, orig, dest) + '" target="_blank">' +
				getSupplierLogo2(rs.id) + '</a></td><td class="route">' + orig + ' - ' + dest;
			if (rs.done)
			{
				html += ' (' + rs.flightCount + ')';
			}
			html +=
				'</td></tr><tr><td class="result' + (rs.done ? ' done' : '') + '">';
			if (rs.done)
			{
				html += curCurrency + ' ' + Math.round(currencyConvert(rs.price));
			}
			else if (rs.error === true)
				html += '';
			else if (last != true)
				html += '<img src="' + imagePath + 'pricelist_loader.gif" />';
			html += '</td></tr></table></div>';
		}
	}
	html += '</div>';

	s.innerHTML = html;
	s.show();
}

/* MomondoFlights proxy */

var MomondoFlightsProxy = Class.create(
{
    initialize: function()
    {
    },

    setFlights: function()
    {
        setFlights();
    },

    doneFlights: function()
    {
        doneFlights();
    },

    showInnovata: function()
    {
        showInnovata();
    },

    addRouteSuppliers: function(s)
    {
        addRouteSuppliers(s);
    },

    renderTopAds: function()
    {
        renderTopAds();
    }
});

var MomondoFlights = new MomondoFlightsProxy();