var flightProvider = {
    expedia: 'Expedia.de',
    lastminute: 'Lastminute.de',
//    sterling: 'Sterling',
//    airberlin: 'Air Berlin',
    ebookers: 'ebookers.de'
}

// num of provider to request
var num_provider = 5;
/* * /
var flight_search_url = '/getresults.php';
var airportAutocompleteURL = '/airports.php';
/* */
var flight_search_url = '/search/getresults.php5';
var airportAutocompleteURL = '/search/airports.php5';
/* */

/**
 * Usage for AirportCompleter:
 * configure airportAutocompleteURL
 * 
 * Bind autocompleter to input fields by calling:
 * AirportAutocomplete.bind('inputBoxId');
 */


var AirportAutocomplete = new Class({
	initialize: function(textBoxToComplete){
		// complete airports for this textbox input element
		this.element = $(textBoxToComplete);

		// is completionbox active?
		this.active = false;
		this.lastsearch = '';
		this.requestTimer = null;
		this.completionDiv = null;

		// options for currently displayed completionbox
		this.currentSelection = 0;
		this.listSize = 0;
		this.listElementsIdPrefix = 'completion_' + this.element.id + '_';
		
		// intercept key strokes
		this.element.addEvent(window.ie ? 'keydown' : 'keypress', this.handleEnterAndArrowKeys.bindWithEvent(this));
		this.element.addEvent('keyup', (function(e) {
			this.handleKeyStroke(e);
		}).bind(this));
		
		// close on blur
		this.element.addEvent('blur', (function(e) {
			this.close.bind(this).delay(200);
		}).bind(this));
		
		// request object we use for completion
		this.request = new Json.Remote(airportAutocompleteURL, 
		{
			onComplete: (function(airports){
				this.showCompletions(airports);
			}).bind(this)
		});
    },
	
	handleEnterAndArrowKeys: function(e, mouse){
		var event = new Event(e);
		
		if (this.active == false) {
            return; // no box open, just return
        }

		if (event.key == 'esc') {
			// close box on escape key
			this.close();
			return;
		}

		var curselected = $(this.listElementsIdPrefix + this.currentSelection);

		// handle arrow keys
		if (event.key == 'up' || event.key == 'down') {
			event.stop(); // prevent moving cursor in input box
			var direction;
			var newselected;
			if (event.key == 'down') {
				direction = 1;
			} else { // up
				direction = -1;
			}
			newselected = $(this.listElementsIdPrefix + (this.currentSelection + direction));
			if (!newselected) return; // element doesnt exists, nothing to select
			
			this.currentSelection += direction;

			// deselect old selection
			if (curselected) {
				curselected.removeClass('selected');
			}
			
			newselected.addClass('selected');
			return;
		}

		// handle enter key
		if (event.key == 'enter') {
			// completion box is opened, instead of submitting, take selected value
			event.stop(); // prevent submit
			if (!curselected) return; // no selection

			this.selectElement(this.currentSelection);

			return;
		}

		// handle tab key
		if (event.key == 'tab') {
			if (!curselected) return; // no selection
			this.selectElement(this.currentSelection);
			return;
		}
	},
	
	selectElement: function(elementNum) {
		var curselected = $(this.listElementsIdPrefix + elementNum);
		this.element.value = curselected.associatedValue;
		this.lastsearch = this.element.value;
		this.close();
	},
	
	handleKeyStroke: function(e){
		var event = new Event(e);

		// perform new search
		var search = this.element.value.trim();
		if (search == this.lastsearch) return; // input didnt change
		if (search.length < 2) return; // do not complete if string is too short

		// wait before making request, maybe user has not finished typing
		$clear(this.requestTimer);
		this.requestTimer = (function(){

			this.lastsearch = search;
			this.request.send({'q': search});

		}).bind(this).delay(0);
	},
	
	showCompletions: function(airports) {
		this.close(); // we make a new div
		this.active = true;
		this.currentSelection = 0;

		if (!airports || airports.length == 0) return; // we dont have any results

		// creater container div		
		this.completionDiv = new Element('div');
		this.completionDiv.addClass('airportCompletion');
		var refpos = this.element.getPosition();
		var refsize = this.element.getSize();
		this.completionDiv.setStyles({
			'z-index': 1000,
			position: 'absolute',
			top: refpos.y + refsize.size.y + 2,
			left: refpos.x
		});
    
    // put header into container
    new Element('div').addClass('airportCompletionHeader').setText('Bitte wählen Sie einen Ort') .injectTop(this.completionDiv);
		
		// put results into container
		this.listSize = 0; // new list, size = 0
		// insert all found airports by code
		if (airports.code) {
			airports.code.each((function(elem) {
				this.listSize++;

				resultElement = this.setupNewElement(elem);
				resultElement.addClass('listElement');
				resultElement.setText(elem.iatacode + ' - ' + elem.airport + ' - ' + (elem.city?elem.city + ' - ':'') + elem.country);

				var elementNumber = this.listSize;
				resultElement.addEvent('click', (function() {
					this.selectElement(elementNumber);
				}).bind(this));
				resultElement.injectInside(this.completionDiv);
			}).bind(this));
		}
		
		// insert all found airports by name
		var lastcountry = '';
		if (airports.name) {
			airports.name.each((function(elem) {
				this.listSize++;
				if (elem.country != lastcountry) {
					// create new country header
					var countryHeader = new Element('div');
					countryHeader.addClass('countryHeader');
					countryHeader.setText(elem.country);
					lastcountry = elem.country;
					countryHeader.injectInside(this.completionDiv);
				}
				
				resultElement = this.setupNewElement(elem);
				resultElement.setText((elem.city?elem.city + ' - ':'') + elem.airport + ' (' + elem.iatacode + ')');
				resultElement.addClass('listElement');

				var elementNumber = this.listSize;
				resultElement.addEvent('click', (function() {
					this.selectElement(elementNumber);
				}).bind(this));
				resultElement.injectInside(this.completionDiv);
			}).bind(this));
		}
		

		this.completionDiv.injectTop(document.body);
	},
	
	setupNewElement: function(elem) {
		var resultElement = new Element('div');
		resultElement.id = this.listElementsIdPrefix + this.listSize;
		resultElement.associatedValue = (elem.airport && elem.airport != 'N/A')?elem.airport:elem.city;
		
		return resultElement;
	},
	
	close: function() {
		// abort search - if ongoing
		$clear(this.requestTimer);
		// close completion box if opened
		if (this.completionDiv != null) {
			this.completionDiv.remove();
		}
		this.completionDiv = null;
		this.active = false;
	}
});

AirportAutocomplete.bind = function(element) {
	$(element).completer = new AirportAutocomplete(element);
}

var StackableOverlay = {
	overlayDivName: '__stackableOverlay_',
	contentDivName: '__stackableOverlay_Content_',
	currentLevel: 0,
	originalXY: new Array()
};

/**
 * Returns div to put content into for given level. If no level
 * parameter is passed, then the topmost level is considered.
 * 
 * @param int level
 */
StackableOverlay.getContentDiv = function(level) {
	if (!level || level > this.currentLevel) level = this.currentLevel;
	
	if (level < 1) return null; // currently there is no div displayed
	
	return $(this.contentDivName + level);
};


StackableOverlay.getOverlayDiv = function(level) {
	if (!level || level > this.currentLevel) level = this.currentLevel;
	
	if (level < 1) return null; // currently there is no overlay displayed
	
	return $(this.overlayDivName + level);
};

/**
 * Creates a new overlay and returns inner content div, to put content into
 * 
 * @param function onOverlayCreate called after the overlay was created. Overlay div is passed to given function for effects and event-binding
 * @param function onContentCreate called after content div was created. Behaves like onOverlayCreate
 */
StackableOverlay.pushOverlay = function (onOverlayCreate, onContentCreate) {
	// create new div layer and insert into dom
	this.currentLevel++;
	var curLevel = this.currentLevel;
	this.originalXY.push({
		x: Window.getScrollLeft(),
		y: Window.getScrollTop()
	});
	
	var overlayDiv = new Element('div');
	var pageDim = $$('body')[0].getSize().size;

	overlayDiv.id = this.overlayDivName + curLevel;
	overlayDiv.setStyles({
		opacity: 0,
		position: 'absolute',
		top: 0,
		left: 0,
		width: pageDim.x<Window.getWidth()?Window.getWidth():pageDim.x,
		height: pageDim.y<Window.getHeight()?Window.getHeight():pageDim.y
	});
	overlayDiv.setStyle('z-index', curLevel * 100);
	overlayDiv.setStyle('background-color', '#ffffff');
	overlayDiv.injectTop($$('body')[0]);

	// call callback for effects
	if (typeof onOverlayCreate == 'function') {
		onOverlayCreate(overlayDiv);
	} else {
		overlayDiv.setStyles({
			opacity: 100,
			'background-color': '#fff'
		});
	}

	// create content div
	var innerdiv = new Element('div');
	innerdiv.id = this.contentDivName + curLevel;
	innerdiv.setStyles({
		opacity: 0,
		position: 'absolute'
	});
	innerdiv.setStyle('z-index', curLevel * 100 + 1);
	innerdiv.injectAfter(overlayDiv);

	// call callback for effects
	if (typeof onContentCreate == 'function') {
		onContentCreate(innerdiv);
	} else {
		innerdiv.setStyle('opacity', 100);
	}

	return innerdiv;
}



/**
 * Remove topmost overlay, call functions onOverlayRemove and
 * on ContentRemove if given before removement. As parameter the
 * div is passed (for effect etc)
 * 
 * @param function onOverlayRemove
 * @param function onContentRemove
 */
StackableOverlay.popOverlay = function(onOverlayRemove, onContentRemove) {

	var content = $(this.contentDivName + this.currentLevel), overlay = $(this.overlayDivName + this.currentLevel);
	this.currentLevel--;
	this.originalXY.pop(); // remove coordinates for scrolling
	
	if (typeof onContentRemove == 'function') {
		onContentRemove(content);
	}
	content.remove(); // remove all displayed content within content div
	
	if (typeof onOverlayRemove == 'function') {
		onOverlayRemove(overlay);
	}
	overlay.remove(); // remove overlay from html
}

StackableOverlay.getCurrentZIndex = function() {
	return this.currentLevel * 1000 + 10;
}

/**
 * Get reveal position for overlay on given level
 * Returns object with x, y coordinates
 * 
 * @param int level
 */
StackableOverlay.getRevealPosition = function(level) {
	if (!level || level > this.currentLevel) level = this.currentLevel;
	if (level < 1 || this.originalXY.length < level) return null;

	return this.originalXY[level - 1];
}

/**
 * Scrolls screen to original position as the current layer was created
 */
StackableOverlay.scrollToRevealPosition = function () {
	if (this.originalXY.length < 1) return; // we have no coordinates to scroll to
	
	var pos = this.originalXY[this.originalXY.length - 1];

	var scroll = new Fx.Scroll(window, {
		wait: false,
		duration: 500,
		transition: Fx.Transitions.Quad.easeInOut
	});
	scroll.scrollTo(pos.x, pos.y);
}

/**
 * tableHighlighter
 */
// Hightlight table rows
var tableHighlighter = new Class({	
	
	options: {
			rowColourClass: 'highlighted',
			rowHoverColourClass: 'hoverHighlighted',
			highlightRow: 'even',
			everyOther: 0
	},
	
	initialize: function( id, options ) {
		
		this.setOptions( options );
		
		if( this.options.highlightRow == 'odd' ){
			this.options.everyOther = 1;
		}
		
		this.rows = $(id).getElementsByTagName('tr');
		this.rowsLength = this.rows.length;
		
		this.addHighlighting();
				
	},
	
	addHighlighting: function(){
		
		var hoverClass = this.options.rowHoverColourClass;
			
		for( var i = 0; i < this.rowsLength; i++ ){

			$( this.rows[i] ).addEvents({
				'mouseover': function(){ this.addClass( hoverClass ); },
				'focus': function(){ this.addClass( hoverClass ); },
				'mouseout': function(){ this.removeClass( hoverClass ); },
				'blur': function(){ this.removeClass( hoverClass ); }
			});
			
			if( this.options.everyOther != 0 ){
				this.rows[i].addClass( this.options.rowColourClass );
				this.options.everyOther = -1;
			}
			
			this.options.everyOther++;
			
		}
		
	}
	
});

tableHighlighter.implement(new Options);

/**
 * Search requests
 */

function startFlightRequest() {
  $('btnFindFlights').focus();
    
	var mydiv = StackableOverlay.pushOverlay(function(elem) {
        elem.effects({fps: 25, duration: 500, transition: Fx.Transitions.Quart.easeOut}).start({
				'background-color': '#eaf8ff',
				opacity: 0.8
		});
	}, function(elem) {
		var revpos = StackableOverlay.getRevealPosition();
		if (!revpos) return;
		elem.setStyles({
			left: revpos.x,
			top: revpos.y,
			opacity: 100
		});
	});
    var waitBox = $('flightSearchWaitBox');
    var revpos = StackableOverlay.getRevealPosition();
    var waitBoxDim = waitBox.getStyles('width','height');
    waitBoxDim.height = waitBoxDim.height.toInt();
    waitBoxDim.width = waitBoxDim.width.toInt();
    if (!waitBoxDim.height || waitBoxDim.height < 100) waitBoxDim.height = 300; // sanity checks
    if (!waitBoxDim.width || waitBoxDim.width < 100) waitBoxDim.width = 500;
    waitBox.setStyles({
        top: Math.round(Window.getHeight() / 2 - waitBoxDim.height / 2) - 50,
        left: Math.round(Window.getWidth() / 2 - waitBoxDim.width / 2),
        display: 'block',
        position: 'absolute'
    });

    waitBox.injectAfter(mydiv);
    
    startPrepareSearch();
}

var cur_provider;
var cur_provider_complete;
var flightSearchInfo; // found flights will be stored in here
var progressBar_maxlen = null;
function startPrepareSearch() {
    setProgressBar(0.1);
    cur_provider = 1;
    cur_provider_complete = 0;
    // always run two provider requests simulateously
    prepareFlightProvider();
    prepareFlightProvider();
}

function setProgressBar(pct) {
    var bar = $('progressBarValue');
    if (!progressBar_maxlen) {
        // init progressBar
        progressBar_maxlen = $('progressBarValue').getParent().getStyle('width').toInt();
    }
    
    bar.setStyle('width', Math.round(progressBar_maxlen * pct) + 'px');
}

function prepareFlightProvider() {
    if (cur_provider > num_provider) return;

    $('flightSearchForm_provider').value = cur_provider;
    new Ajax(flight_search_url, {data: $('flightSearchForm'), onComplete: function(result) {
        cur_provider_complete++;
        setProgressBar(cur_provider_complete / num_provider);
        
        if (cur_provider_complete >= num_provider) {
            $('flightSearchForm_provider').value = 'all';

            (function(){  

            
            new Ajax(flight_search_url, {
                data: $('flightSearchForm'),
                onSuccess: showFlightSearchResults,
                onComplete: function() {

                    $('flightSearchWaitBox').setStyles({
                            display: 'none'
                    });
                    StackableOverlay.popOverlay();

                }                
            }).request();
            
            
            
            }).delay(0); // sleep 2 sec

        } else {
            prepareFlightProvider();
        }
	}}).request();

    cur_provider++;
}

var searchResults = null;
var maxPrice = 1000;
var minPrice = 0;
// price filter
var acceptedMaxPrice = 99999;
var acceptedTaxInclOnly = false; // flights tax incl only
var acceptedDirectOnly = false; // show only flights without flightlegs
// time filter, in milliseconds
var acceptedOutTimeFrom = 0, acceptedOutTimeTo = 86400000, acceptedRetTimeFrom = 0, acceptedRetTimeTo = 86400000;
var acceptedOutTimeIsDeparture = true, acceptedRetTimeIsDeparture = true; // time filter departure or arrival time?
function showFlightSearchResults(results) {
    results = Json.evaluate(results, true);
    if (!results) return;
    if (!results.flights || results.flights.length == 0) {
        alert('Wir konnten zu Ihrer Anfrage keine Flüge finden!');
        return;
    }

    searchResults = results;

    sortFlightResults();

    if ($('searchresults')) $('searchresults').remove();
    
    var resultDiv = new Element('div');
    resultDiv.id = 'searchresults';
    resultDiv.injectAfter($('flightSearchPanel'));

    buildFlightSearchResultToolbar(resultDiv);

    buildFlightSearchResultElementTable();
}

function sortFlightResults() {
    maxPrice = 0;
    minPrice = 1000;
    searchResults.flights.sort(function(a, b) {
       if (a.price > maxPrice) maxPrice = a.price.toInt();
       if (a.price < minPrice) minPrice = a.price.toInt();
       return a.price - b.price; 
    });
}

function buildFlightSearchResultToolbar(parent) {
    var toolbar_container = $('flightResultsToolbarDiv');
    if (toolbar_container) toolbar_container.remove();
    
    toolbar_container = new Element('div');
    toolbar_container.id = 'flightResultsToolbarDiv';
    toolbar_container.addClass('block');
    toolbar_container.addClass('blue-bg');
    toolbar_container.injectTop(parent);

    // title
    new Element('h2').setText('Optionen - Ergebnisse filtern').injectInside(toolbar_container);

    var toolbar = new Element('div');
    toolbar.addClass('padding10');
    toolbar.addClass('clearfix');
    // show toolbar
    toolbar.injectInside(toolbar_container);
    
    // slider max price
    var fn_checkbox_tax = function(e) { // ie workaround, bind click event to label and checkbox
        e = new Event(e);
        if (acceptedTaxInclOnly != e.target.checked) 
            acceptedTaxInclOnly = e.target.checked;
        buildFlightSearchResultElementTable();
    }; 
    var fn_checkbox_direct = function(e) { // ie workaround, bind click event to label and checkbox
        e = new Event(e);
        if (acceptedDirectOnly != e.target.checked) 
            acceptedDirectOnly = e.target.checked;
        buildFlightSearchResultElementTable();
    }; 
    var slidercontainer = new Element('div');
    slidercontainer.addClass('trio');
    new Element('h3').setText('Maximaler Preis').injectInside(slidercontainer);
    // checkboxes - use click instead of change for ie
    new Element('input').setProperties({
        type: 'checkbox',
        id: 'checkbox_taxincl'
    }).addEvent('click', fn_checkbox_tax).injectInside(slidercontainer);
    new Element('label').setProperty('for', 'checkbox_taxincl').setText('nur Tax incl.').addEvent('click', fn_checkbox_tax).injectInside(slidercontainer);

    new Element('input').setProperties({
        type: 'checkbox',
        id: 'checkbox_directonly'
    }).addEvent('click', fn_checkbox_direct).injectInside(slidercontainer);
    new Element('label').setProperty('for', 'checkbox_directonly').setText('nur Direktflüge').addEvent('click', fn_checkbox_direct).injectInside(slidercontainer);
    // slider
    var sliderArea = new Element('div').injectInside(slidercontainer);
    sliderArea.id = 'sliderPriceArea';
    sliderArea.addClass('gutter');
    var sliderKnob = new Element('div').injectInside(sliderArea);
    sliderKnob.id = 'sliderPriceKnob';
    sliderKnob.addClass('knob');
    var selectedVal = new Element('div').injectInside(slidercontainer);
    slidercontainer.injectInside(toolbar);

    var mySlide = new Slider(sliderArea, sliderKnob, {
        start: minPrice,
        end: maxPrice,
    	onChange: function(step){
    		selectedVal.setText((step.toInt()) + " EUR");
    	},
        onComplete: function(step) {
            acceptedMaxPrice = step.toInt();
            buildFlightSearchResultElementTable();
        }
    }).setMin(Math.round((maxPrice + minPrice) / 2));    

    // slider time outward flight
    var fn_radio_out_departure = function(e) { // ie workaround, bind click event to label and radiobutton - change event broken
        var departure = $('radio_out_dep').checked;
        if (acceptedOutTimeIsDeparture != departure) 
            acceptedOutTimeIsDeparture = departure;
        buildFlightSearchResultElementTable();
    }; 
    var fn_create_radio_box = function(elemid, elemname, elemvalue, setchecked) { // horrible ie bugs: http://webbugtrack.blogspot.com/2007/10/bug-235-createelement-is-broken-in-ie.html
        var elem;
        if (!window.ie) {
            elem = new Element('input').setProperties({
                id: elemid,
                name: elemname,
                type: 'radio',
                value: elemvalue
            });
            if (setchecked) elem.checked = true;
        } else {
            // ie bug - setting name attribute not working - aargh
            var checked_tmp = "";
            if (setchecked) checked_tmp = ' checked="checked"';
            elem = document.createElement('<input type="radio" value="' + elemvalue + '" name="' + elemname + '" id="' + elemid + '"' + checked_tmp + ' />');
            elem = new Element(elem); // wrap in mootools element class for the nice stuff
        }
        return elem;
    }
    slidercontainer = new Element('div');
    slidercontainer.addClass('trio');
    new Element('h3').setText('Hinflug-Uhrzeit eingrenzen').injectInside(slidercontainer);
    fn_create_radio_box('radio_out_dep', 'radio_out_deparr', '1', true).addEvent('click', fn_radio_out_departure).injectInside(slidercontainer);
    new Element('label').setProperty('for', 'radio_out_dep').setText('Startzeit').addEvent('click', fn_radio_out_departure).injectInside(slidercontainer);
    fn_create_radio_box('radio_out_arr', 'radio_out_deparr', '0', false).addEvent('click', fn_radio_out_departure).injectInside(slidercontainer);
    new Element('label').setProperty('for', 'radio_out_arr').setText('Landezeit').addEvent('click', fn_radio_out_departure).injectInside(slidercontainer);

    sliderArea = new Element('div').injectInside(slidercontainer);
    sliderArea.id = 'sliderOutFlightArea';
    sliderArea.addClass('gutter');
    var sliderKnobFrom = new Element('div').injectInside(sliderArea);
    sliderKnobFrom.id = 'sliderOutFlightKnobFrom';
    sliderKnobFrom.addClass('knob');
    var sliderKnobTo = new Element('div').injectInside(sliderArea);
    sliderKnobTo.id = 'sliderOutFlightKnobFrom';
    sliderKnobTo.addClass('knob');
    var selectedOutTime = new Element('div').injectInside(slidercontainer);
    slidercontainer.injectInside(toolbar);

    var mySlide = new Slider(sliderArea, sliderKnobFrom, {
        start: 0,
        end: 96,
        knobheight: 15,
    	onChange: function(step){
            adjustFlightTime(selectedOutTime, step.minpos, step.maxpos);
    	},
        onComplete: function(step) {
            acceptedOutTimeFrom = step.minpos * 15 * 60000;
            acceptedOutTimeTo = step.maxpos * 15 * 60000;
            buildFlightSearchResultElementTable();
        }
    }, sliderKnobTo).setMin(24).setMax(84);    

    // slider time return flight
    var fn_radio_ret_departure = function(e) { // ie workaround, bind click event to label and radiobutton - change event broken
        var departure = $('radio_ret_dep').checked;
        if (acceptedRetTimeIsDeparture != departure) 
            acceptedRetTimeIsDeparture = departure;
        buildFlightSearchResultElementTable();
    }; 
    slidercontainer = new Element('div');
    slidercontainer.addClass('trio');
    new Element('h3').setText('Rückflug-Uhrzeit eingrenzen').injectInside(slidercontainer);
    fn_create_radio_box('radio_ret_dep', 'radio_ret_deparr', '1', true).addEvent('click', fn_radio_ret_departure).injectInside(slidercontainer);
    new Element('label').setProperty('for', 'radio_ret_dep').setText('Startzeit').addEvent('click', fn_radio_ret_departure).injectInside(slidercontainer);
    fn_create_radio_box('radio_ret_arr', 'radio_ret_deparr', '0', false).addEvent('click', fn_radio_ret_departure).injectInside(slidercontainer);
    new Element('label').setProperty('for', 'radio_ret_arr').setText('Landezeit').addEvent('click', fn_radio_ret_departure).injectInside(slidercontainer);

    sliderArea = new Element('div').injectInside(slidercontainer);
    sliderArea.id = 'sliderRetFlightArea';
    sliderArea.addClass('gutter');
    sliderKnobFrom = new Element('div').injectInside(sliderArea);
    sliderKnobFrom.id = 'sliderRetFlightKnobFrom';
    sliderKnobFrom.addClass('knob');
    sliderKnobTo = new Element('div').injectInside(sliderArea);
    sliderKnobTo.id = 'sliderRetFlightKnobFrom';
    sliderKnobTo.addClass('knob');
    var selectedRetTime = new Element('div').injectInside(slidercontainer);
    slidercontainer.injectInside(toolbar);

    var mySlide = new Slider(sliderArea, sliderKnobFrom, {
        start: 0,
        end: 96,
        knobheight: 15,
    	onChange: function(step){
            adjustFlightTime(selectedRetTime, step.minpos, step.maxpos);
    	},
        onComplete: function(step) {
            acceptedRetTimeFrom = step.minpos * 15 * 60000;
            acceptedRetTimeTo = step.maxpos * 15 * 60000;
            buildFlightSearchResultElementTable();
        }
    }, sliderKnobTo).setMin(24).setMax(84);    

    (new Element('br')).addClass('clear').injectInside(toolbar);
}

function adjustFlightTime(displayElement, timeFrom, timeTo) {
    timeFrom = timeFrom * 15; // convert to minutes
    var from_min = timeFrom % 60;
    var from_hr = (timeFrom - from_min) / 60;
    timeTo = timeTo * 15; // convert to minutes
    var to_min = timeTo % 60;
    var to_hr = (timeTo - to_min) / 60;
    displayElement.setText('Zwischen ' + string_pad_left(from_hr) + ':' + string_pad_left(from_min) + ' und ' + string_pad_left(to_hr) + ':' + string_pad_left(to_min) + ' Uhr');
}

function string_pad_left(str) {
    str = '00' + str;
    return str.substr(str.length - 2, 2);
}


function buildFlightSearchResultElementTable() {
    var resultDiv = $('searchresults');
    var flightTable = $('flightResultsTableDiv');
    if (flightTable) {
        flightTable.empty();
    } else {
        flightTable = new Element('div');
        flightTable.id = 'flightResultsTableDiv';
        flightTable.addClass('block');
        flightTable.addClass('blue-bg');
        flightTable.injectInside(resultDiv);
    }
    new Element('h2').setText('Gefundene Billigflüge').injectInside(flightTable);
    var flightTable_table = new Element('div');
    flightTable_table.addClass('clearfix');
    flightTable_table.addClass('flug-angebote');
    flightTable_table.addClass('padding10');
    
    // because of f****** ie bugs we are building the table by htmlsource
    var tableHtml = '<table id="flightResultsTable" class="ergebnisse" cellpadding="0" cellspacing="0" border="0">';
    tableHtml += '<thead><tr><td class="price">Preis in EUR</th>';
    tableHtml += '<td class="route">Abreise - Ankunft</th>';
    tableHtml += '<td class="stops">Stops</th>';
    tableHtml += '<td class="airline">Airline</th>';
    tableHtml += '<td class="anbieter">Anbieter</th>';
    tableHtml += '<td class="link">&nbsp;</th></tr></thead><tbody id="highlight">';

    rowhighlight = true;
    searchResults.flights.each(function(elem) {
        tableHtml += buildFlightSearchResultElement(elem, searchResults.request);
    });
    tableHtml += '</tbody></table>';

    flightTable.setHTML(tableHtml);

    // init row highlightning
    var th = new tableHighlighter( 'highlight' );

//    flightTable = new Element('table');
//    flightTable.id = 'flightResultsTable';
//    
//    var row = new Element('tr');
//    row.injectInside(flightTable);
//    // header rows
//    new Element('th').setText('').injectInside(row);
//    new Element('th').setText('').injectInside(row);
//    new Element('th').setText('').injectInside(row);
//    new Element('th').setText('').injectInside(row);
//    new Element('th').setText('').injectInside(row);
//    new Element('th').setText('').injectInside(row);
//    
//    searchResultsFiltered.flights.each(function(elem) {
//        buildFlightSearchResultElement(flightTable, elem, searchResults.request);
//    });
//    
//    flightTable.injectTop(document.body);
}

var rowhighlight = true;
function buildFlightSearchResultElement(result, requestinfo) {
    if (result.price > acceptedMaxPrice) return ''; // price too high see filter
    if (acceptedTaxInclOnly && result.price_tax_service < 1) return ''; // no tax included
    var tax_incl_str = "&nbsp;"; if (result.price_tax_service > 0) tax_incl_str = "Tax incl.";
    if (acceptedDirectOnly && (result.flightlegs_out > 0 || result.flightlegs_ret > 0)) return ''; // flight with legs
    var tmp_millis;
    if (acceptedOutTimeIsDeparture || !result.date_out_to) { // consider departure or arrival time? or is it oneway only?
        tmp_millis = (result.date_out_from % 86400) * 1000; // get time out of full date        
    } else {
        tmp_millis = (result.date_out_to % 86400) * 1000; // get time out of full date        
    }
    if (tmp_millis != 0) {
        // is time out of selected range?
        if (tmp_millis > acceptedOutTimeTo || tmp_millis < acceptedOutTimeFrom) return '';
    }
    if (acceptedRetTimeIsDeparture || !result.date_ret_to) { // consider departure or arrival time? or is it oneway only?
        tmp_millis = (result.date_ret_from % 86400) * 1000; // get time out of full date
    } else {
        tmp_millis = (result.date_ret_to % 86400) * 1000; // get time out of full date
    }
    if (tmp_millis != 0) {
        // is time out of selected range?
        if (tmp_millis > acceptedRetTimeTo || tmp_millis < acceptedRetTimeFrom) return '';
    }

    rowhighlight = !rowhighlight;
    var addclass = rowhighlight?' class="highlighted"':'';
    return '<tr' + addclass + '><td class="price"><span>&euro;' + parseFloat(result.price).toFixed(2).toString().replace('.', ',') + '</span><br />' + tax_incl_str + '</td><td class="route">' 
        + requestinfo.airport_from + " " + extractTimeFromTimeStamp(result.date_out_from) + " - " + requestinfo.airport_to + " " + extractTimeFromTimeStamp(result.date_out_to)
        + (result.date_ret_from?("<br />" + requestinfo.airport_to + " " + extractTimeFromTimeStamp(result.date_ret_from) + " - " + requestinfo.airport_from + " " + extractTimeFromTimeStamp(result.date_ret_to)):'')
        + '</td><td class="stops">' + result.flightlegs_out + (result.flightlegs_ret?"<br />" + result.flightlegs_ret:'') + '</td>'
        +'<td class="airline">' + result.operator + '</td><td class="anbieter">' + flightProvider[result.provider] + '</td><td class="link"><img src="/assets/templates/billigflieger/images/icon-flight.gif" alt="Flug buchen" class="mini-icon" /><a target="_blank" href="' + result.link + '">Zum Angebot</a></td></tr>';

//    var row = new Element('tr');
//    row.injectInside(parent);
//    // content rows
//    new Element('td').setText(parseFloat(result.price).toFixed(2).toString().replace('.', ',')).injectInside(row);
//    new Element('td').setText(requestinfo.airport_from + " - " + requestinfo.airport_to).injectInside(row);
//    new Element('td').setText(result.flightlegs).injectInside(row);
//    new Element('td').setText(result.operator).injectInside(row);
//    new Element('td').setText(flightProvider[result.provider]).injectInside(row);
//    new Element('td').setHTML('<a href="' + result.link + '">Zum Anbieter</a>').injectInside(row);
}

/**
 * extract and format timestamp
 * @param int ts unix timestamp
 */
function extractTimeFromTimeStamp(ts) {
    ts = parseInt((ts % 86400) / 60); // extract minutes
    if (ts == 0) return ''; // no time given
    var min = ts % 60;
    var hr = (ts - min) / 60;
    return pad_string(hr) + ':' + pad_string(min);
}

function pad_string(value, length) {
	value = String(value);
	length = parseInt(length) || 2;
	while (value.length < length)
		value = "0" + value;
	return value;
};

  function dateFromSearchBoxToTimestamp(returnflight) {
    var boxpfx = returnflight?'ret':'out';
    return new Date($(boxpfx + '_year').value, $(boxpfx + '_month').value - 1, $(boxpfx + '_day').value);
  }
  
  function setDateFromSearchBox(dateObj, returnflight) {
    var boxpfx = returnflight?'ret':'out';
	$(boxpfx + '_day').value = dateObj.getDate();
	$(boxpfx + '_month').value = (dateObj.getMonth() + 1);
	$(boxpfx + '_year').value = window.ie?dateObj.getYear():(dateObj.getYear() + 1900);
  }
  
  // if a date changes, then adjust the other date too. 
  var out_datechanged = false;
  var ret_datechanged = false;
  function adjustSelectedDates(evt, target) {
    if (!target) {
        evt = new Event(evt);                        
        target = evt.target.id.substr(0, 3);
    }
    var date_out = dateFromSearchBoxToTimestamp(false);
    var date_ret = dateFromSearchBoxToTimestamp(true);
    // is it the outward or return flight?
    if (target == 'ret') {
        ret_datechanged = true;
        // adjust outward flight date
        if (out_datechanged) {
            // user already selected out_date, so adjust only if it lies behind ret_date
            if (date_out > date_ret) {
                date_out = new Date(date_ret.getTime() - 259200000); // 259200000 = 3 * 24 * 60 * 60 * 1000 = 3 days
                setDateFromSearchBox(date_out, false);
            }
        } else {
            // as long as user doesnt touch the other date, always adjust +3 days
            date_out = new Date(date_ret.getTime() - 259200000); // 259200000 = 3 * 24 * 60 * 60 * 1000 = 3 days
            setDateFromSearchBox(date_out, false);
        }
    } else {
        // no dry - same as for returnflight - copy paste
        out_datechanged = true;
        // adjust return flight date
        if (ret_datechanged) {
            // user already selected ret_date, so adjust only if it lies before out_date
            if (date_out > date_ret) {
                date_ret = new Date(date_out.getTime() + 259200000); // 259200000 = 3 * 24 * 60 * 60 * 1000 = 3 days
                setDateFromSearchBox(date_ret, true);
            }
        } else {
            // as long as user doesnt touch the other date, always adjust +3 days
            date_ret = new Date(date_out.getTime() + 259200000); // 259200000 = 3 * 24 * 60 * 60 * 1000 = 3 days
            setDateFromSearchBox(date_ret, true);
        }
    }
  }




