(function($) {
	$.fn.jSuggest = function(options) {
		// merge users option with default options
		var opts      = $.extend({}, $.fn.jSuggest.defaults, options);
		var jH        = ".jSuggestHover";
		var jsH       = "jSuggestHover";
		var iniVal    = this.value;
		var textBox   = this;
		var textVal   = this.value;
		var intUpDown = 0;
		var jCname    = "jSuggestContainer-"+$(this).attr('name');
		var jC        = "#"+jCname;
        if ($('#ort').val() != '' && opts.moreOpts == 1) {
            $.fn.jSuggest.getMoreOpts(jH,opts);
        }

		$('body').append('<div id="'+jCname+'" class="jSuggestContainer"></div>');
		$(jC).hide();

		$(this).bind("keydown", function(e){
		    //alert(e.keyCode);
			textBox = this;
			textVal = this.value;
			if ((e.keyCode == 9 || e.keyCode == 38 || e.keyCode == 39 || e.keyCode == 40 || e.keyCode == 13) && intUpDown == 0) {
			    intUpDown = 1;
				// if down arrow
				if (e.keyCode == 40) {
				    $.fn.jSuggest.down(jH,jsH,opts,textBox);
                    changeInterval = setInterval(function() {$.fn.jSuggest.down(jH,jsH,opts,textBox,jC)},opts.changeSpeed);
                    return false;
				}
				// if up arrow
				else if (e.keyCode == 38) {
				    $.fn.jSuggest.up(jH,jsH,opts,textBox);
                    changeInterval = setInterval(function() {$.fn.jSuggest.up(jH,jsH,opts,textBox,jC)},opts.changeSpeed);
                    return false;
				}
				// if enter key
				else if (e.keyCode == 13) {
					if ($(jH).length == 1 && $(jC).css('display')=='block') {
					    $.fn.jSuggest.complete(textBox,jH,opts);
						$(jC).hide();
						iniVal = textBox.value;
						return false;
					}
					$(jC).hide();
					iniVal = textBox.value;
				}
				// if right arrow
				else if (e.keyCode == 39 || e.keyCode == 9) {
					if ($(jH).length == 1 && $(jC).css('display')=='block') {
					    $.fn.jSuggest.complete(textBox,jH,opts);
						$(jC).hide();
						iniVal = textBox.value;
						return false;
					}
					$(jC).hide();
					iniVal = textBox.value;
				}
			}
		});
		/*
		$('#searchform').bind("submit", function(){
			if ($(jH).length == 1) {
			    $.fn.jSuggest.complete(textBox,jH,opts);
				$(jC).hide();
				iniVal = textBox.value;
				return false;
			}
			alert($(jC).css('display'));
			$(jC).hide();
			iniVal = textBox.value;
		});*/
		$(this).bind("keyup click", function(e){
            intUpDown = 0;
			textBox   = this;
			textVal   = this.value;
			if (this.value.length >= opts.minchar && $.trim(this.value)!="Search Terms") {
				var offSet = $(this).offset();

				$(jC).css({
					position: "absolute",
					top: offSet.top + $(this).outerHeight() + "px",
					left: offSet.left,
					width: $(this).outerWidth()-2 + "px",
					opacity: opts.opacity,
					zIndex: opts.zindex
				}).show();

				// if escape key
				if (e.keyCode == 27 ) {
					$(jC).hide();
				}
				// if down arrow
				else if (e.keyCode == 40) {
                    clearInterval(changeInterval);
				}
				// if up arrow
				else if (e.keyCode == 38) {
                    clearInterval(changeInterval);
				}
				else if (e.keyCode == 13 || e.keyCode == 9 || e.keyCode == 39) {
					$(jC).hide();
					iniVal = textBox.value;
				}
				// new query detected
				else if (textBox.value != iniVal){
					iniVal = textBox.value;
					if ($(".jSuggestLoading").length==0)
						$('<div class="jSuggestLoading">'+ opts.loadingText+'</div>').prependTo(jC);

					$(".jSuggestLoading").show();
					$(jC).find('ul').remove();

					if (opts.data == '')
						opts.data = $(this).serialize();
					else {
					    val = $(this).val();
						opts.val = opts.data + "=" + encodeURI(val);
					}
					// optimize server performance by loading at intervals
					if (opts.flughafen) {
					   opts.val += '&flughafen='+$('#flughafen').val();
					}
					setTimeout(function () {
						$.ajax({
							type: opts.type,
							url: opts.url,
							data: opts.val,
							success: function(msg){
								$(jC).find('ul').remove();
								$(jC).append(msg);
								$(jC+" ul li").bind("mouseover",	function(){
									$(jH).removeClass(jsH);
									$(this).addClass(jsH);
									textVal = $(this).text();
									if (opts.autoChange) {
				                       $.fn.jSuggest.complete(textBox,jH,opts,opts);
									}
								});
								$(jC+" ul li").click(function(){
									$(this).addClass(jsH);
					                $.fn.jSuggest.complete(textBox,jH,opts);
					                $('#searchform').submit();
								});
								$(".jSuggestLoading").hide();
							},
							error: function(){
								$(jC).find('ul').remove();
								$(".jSuggestLoading").hide();
							}
						});
					}, opts.delay);
				}
			}
			// if text is too short do nothing and hide everything
			else {
				$(jH).removeClass(jsH);
				$(jC).hide();
			}
			// no bubbling, click is binded to textBox to prevent document bind from firing
			return false;
		});

		// why no use $(this).blur ?, because jSuggest box is hidden before click fires so this is the only way to do it
		// alternate way is to say that text blur will fire before$("#jSuggestContainer ul li") click.
		$(document).bind("click", function(){
			$(jC).hide();
			iniVal = textBox.value;
		});

	};

	$.fn.jSuggest.down = function(jH,jsH,opts,textBox,jC) {
		if ($('.jElement').hasClass(jsH)) {
    	    indexAct    = $('.jElement').index($('.jSuggestHover'));
            indexNext   = indexAct+1;
            indexLast   = $('.jElement').index($('.jElement:last'));
            actElement  = $('.jElement').eq(indexAct);
            nextElement = (indexNext == indexLast+1) ? $('.jElement:first') : $('.jElement').eq(indexNext);
            var pos = $(nextElement).position();
            var top = (pos.top)-($(jC).outerHeight()-$(nextElement).outerHeight());
            var cTop = $(jC).scrollTop()-$(jC).height();
            var cBot = $(jC).scrollTop();
            var scroll = 0;
            if (top < cTop || top > cBot)
                scroll = 1;
            $.fn.jSuggest.change(jH,jsH,textBox,opts,nextElement,actElement,top,scroll);
		} else {
		    indexNext   = 0;
		    actElement  = 0;
            nextElement = $('.jElement').eq(0);
            var scroll = 0;
            var top = 0;
            $.fn.jSuggest.change(jH,jsH,textBox,opts,nextElement,actElement,top,scroll);
		}
		return false;
    };

    $.fn.jSuggest.up = function(jH,jsH,opts,textBox,jC) {
		if ($('.jElement').hasClass(jsH)) {
    	    indexAct    = $('.jElement').index($('.jSuggestHover'));
            indexNext   = indexAct-1;
            indexLast   = $('.jElement').index($('.jElement:first'));
            actElement  = $('.jElement').eq(indexAct);
            nextElement = (indexNext == indexLast-1) ? $('.jElement:last') : $('.jElement').eq(indexNext);
            var pos = $(nextElement).position();
            var top = (pos.top)-($(jC).outerHeight()-$(nextElement).outerHeight());
            var cTop = $(jC).scrollTop()-$(jC).height();
            var cBot = $(jC).scrollTop();
            var scroll = 0;
            if (top < cTop || top > cBot) {
                top = top+($(jC).outerHeight()-$(nextElement).outerHeight())
                scroll = 1;
            }
            $.fn.jSuggest.change(jH,jsH,textBox,opts,nextElement,actElement,top,scroll);
		} else {
            indexNext      = 0;
            actElement     = 0;
    	    nextElement    = $('.jElement').index($('.jElement:last'));
            var pos = $(nextElement).position();
            var top = pos.top;
            var cTop = $(jC).scrollTop()-$(jC).height();
            var cBot = $(jC).scrollTop();
            var scroll = 0;
            if (top < cTop || top > cBot)
                scroll = 1;
            $.fn.jSuggest.change(jH,jsH,textBox,opts,nextElement,actElement,top,scroll);
		}
		return false;
    };

    $.fn.jSuggest.change = function(jH,jsH,opts,textBox,nextElement,actElement,top,scroll) {
        if (actElement != 0)
            actElement.removeClass(jsH);
        $(nextElement).addClass(jsH);
        if (scroll == 1)
            $(jC).scrollTop(top)
		if (opts.autoChange) {
		    $.fn.jSuggest.complete(textBox,jH,opts);
        }
		return false;
    };

    $.fn.jSuggest.complete = function(textBox,jH,opts) {
		$(textBox).val($(jH).text());
        if ($(jH).attr('id') != '') {
            $('#moreOpts').html('');
            var num = Number($(textBox).val());
            if (num > 0 && num < 100000) {
                //alert('Number');
            } else {
                //alert('String');
            }
    		$('#ortsid').val($(jH).attr('id'));
    		if ($(textBox).attr('id') == 'rueckflug_startflughafen2') {
    		    $('#rueckflug_startflughafen').val($(jH).attr('id'));
    		} else if ($(textBox).attr('id') == 'abflug_zielflughafen2') {
    		    $('#abflug_zielflughafen').val($(jH).attr('id'));
    		}
        } else {
            if (opts.moreOpts == 1)
                $.fn.jSuggest.getMoreOpts(jH,opts);
        }
    };

    $.fn.jSuggest.getMoreOpts = function(jH,opts) {
        var content = '';
        $('#moreOpts').html('<h3>Bitte wählen Sie die entsprechende Postleitzahl und Ortsteil aus!</h3>');
        label1 = (opts.lang == 2) ? 'Zip Code' : 'PLZ';
        label2 = (opts.lang == 2) ? 'Destrict' : 'Ortsteil';
        option = (opts.lang == 2) ? 'Please Choose' : 'Bitte wählen';

        content += '<div id="lPlz" class="loading" class="select" style="margin-right:15px;"></div>';
        content += '<div id="cPlz" class="select" style="margin-right:15px;">';
        content += '    <label for="plz">'+label1+'</label>';
        content += '    <div class="hiddendiv" style="display:;" >';
        content += '        <select size="1" id="plz" name="plz">';
        content += '            <option value="">'+option+'</option>';
        content += '        </select>';
        content += '    </div>';
        content += '</div>';

        content += '<div id="lOrtsteil" class="loading" class="select"></div>';
        content += '<div id="cOrtsteil" class="select">';
        content += '    <label for="ortsteil">'+label2+'</label>';
        content += '    <div class="hiddendiv" style="display:;" >';
        content += '        <select size="1" id="ortsteil" name="ortsteil">';
        content += '            <option value="">'+option+'</option>';
        content += '        </select>';
        content += '    </div>';
        content += '</div>';

        $('#moreOpts').append(content);
        $('#cPlz,#cOrtsteil').hide();
        $.fn.jSuggest.getPlz(jH,opts,'');
        $.fn.jSuggest.getOrtsteil(jH,opts,'');
    };

    $.fn.jSuggest.getPlz = function(jH,opts,plz) {
        var query = 'ort='+$('#ort').val()+'&ortsteil='+$('#ortsteil').val()+'&selected='+plz+'&type=1&id=plz_input_&tag=option';

		// optimize server performance by loading at intervals
        setTimeout(function () {
            $.ajax({
                type: opts.type,
                url : opts.url,
                data: query,
                success: function(msg) {
					$('#plz').append(msg);
                    $('#plz').selectbox();
                    $('#lPlz').hide();
                    $('#cPlz').show();
                    $('#plz').change(function() {$.fn.jSuggest.changePlz(jH,opts);});
                },
                error: function() {
                }
            });
        }, opts.delay);
    };

    $.fn.jSuggest.changePlz = function(jH,opts) {
        $('#cOrtsteil').hide();
        $('#lOrtsteil').show();
        var ortsteil = $('#ortsteil').val();
        var content = '';
        label  = (opts.lang == 2) ? 'Destrict'      : 'Ortsteil';
        option = (opts.lang == 2) ? 'Please Choose' : 'Bitte wählen';
        content += '    <label for="ortsteil">'+label+'</label>';
        content += '    <div class="hiddendiv" style="display:;" >';
        content += '        <select size="1" id="ortsteil" name="ortsteil">';
        content += '            <option value="">'+option+'</option>';
        content += '        </select>';
        content += '    </div>';
        $('#cOrtsteil').html(content);
        $.fn.jSuggest.getOrtsteil(jH,opts,ortsteil);
    };

    $.fn.jSuggest.getOrtsteil = function(jH,opts,ortsteil) {
        var query = 'ort='+$('#ort').val()+'&plz='+$('#plz').val()+'&selected='+ortsteil+'&type=2&id=ortsteil_input_&tag=option';
        setTimeout(function () {
            $.ajax({
                type: opts.type,
                url : opts.url,
                data: query,
                success: function(msg) {
					$('#ortsteil').append(msg);
                    $('#ortsteil').selectbox();
                    $('#lOrtsteil').hide();
                    $('#cOrtsteil').show();
                    $('#ortsteil').change( function() {$.fn.jSuggest.changeOrtsteil(jH,opts);});
                },
                error: function(){
                }
            });
        }, opts.delay);
    };

    $.fn.jSuggest.changeOrtsteil = function(jH,opts) {
        $('#cPlz').hide();
        $('#lPlz').show();
        var plz = $('#plz').val();
        var content = '';
        label  = (opts.lang == 2) ? 'Zip Code'      : 'PLZ';
        option = (opts.lang == 2) ? 'Please Choose' : 'Bitte wählen';
        content += '    <label for="plz">'+label+'</label>';
        content += '    <div class="hiddendiv" style="display:;" >';
        content += '        <select size="1" id="plz" name="plz">';
        content += '            <option value="">'+option+'</option>';
        content += '        </select>';
        content += '    </div>';
        $('#cPlz').html(content);
        $.fn.jSuggest.getPlz(jH,opts,plz);
    };

    $.fn.jSuggest.debug = function(obj) {
        var txt = "";
        var txt = "";
        for (var area in obj) {
            txt += "<dl><dt>NEUER ABSCHNITT: " + area + "</dt>";
            if (typeof(obj[area]) == 'object') {
                for (var doc in obj[area]) {
                    if (typeof(area[doc]) != 'undefined')
                        txt += "<dd>" + doc + ": " + area[doc] + "</dd>";
                }
            } else {
                txt += "<dd>"+obj[area]+"</dd>";
            }
            txt += "</dl>";
        }
        alert(txt);
    };

	$.fn.jSuggest.defaults = {
		minchar: 3,
		opacity: 1.0,
		zindex: 20000,
		delay: 0,
		lang: 0,
		flughafen: true,
		loadingImg: 'ajax-loader.gif',
		loadingText: 'Loading...',
		autoChange: false,
		url: "",
		moreOpts: 0,
		type: "GET",
		changeSpeed: 100,
		data: ""
	};

})(jQuery);