( function($){

		$.fn.suggester = function(options) {
            
            /**
             * For later IE6 hacks...
             */
            var isIE6 = /msie|MSIE 6/.test(navigator.userAgent);

			/**
			 * Suggester input objects
			 */
			var suggesterInputFirst = undefined;
			var suggesterInputSecond = undefined;

			/**
			 * For situation when suggester shouldn show up
			 */
			var suggesterShowUp = true;

			/**
			 * Is set to first or second every time user changes input. In one-input suggester, only first matters.
			 */
			var suggesterInput = 'first';

			/**
			 * Containers for user selected location codes
			 */
			var suggesterFirstLandCode = undefined;
			var suggesterFirstLocCode = undefined;
            var suggesterFirstGroupCode = undefined;
			var suggesterSecondLandCode = undefined;
			var suggesterSecondLocCode = undefined;
            var suggesterSecondGroupCode = undefined;

			/**
			 * test
			 */
			var suggesterSelectedItem = undefined;

			/**
			 * Position of actualy used suggester. (set while input is focused)
			 */
			var suggesterPosition = {'top':'0', 'left':'0'};

			/**
			 * Width of actualy used suggester. (the same as input)
			 */
			var suggesterWidth = '0';

			/**
			 * If suggester is reading asynchronous data, this value is true to prevent reading data too often
			 */
			var suggesterOnRoute = false;

			/**
			 * Used to query suggester requests. If user change suggester phrase to fast,
			 * it should update suggester content automaticaly without need of key pressing.
			 */
			var suggesterRequestQuery = undefined;

			/**
			 * Container for user written suggestion to compare with new one onChange
			 */
			var lastPhrase = '';

			/**
			 * Container for very actual phrase.
			 */
			var actualPhrase = '';

			/**
			 * Phrase which the request is send for. if suggest phrase was changed, lastResponseData should be updated.
			 * This is the base phrase, 3 letters long. (may differ by setting the letters2activate)
			 */
			var lastResponsePhrase = undefined;

			/**
			 * Responded data to use in suggesting process.
			 */
			var lastResponseData = undefined;

			/**
			 * Suggester default settings
			 */
			var defaults = {

				/**
				 * Suggester server-side url
				 */
				requestUrl:'/proxy.php?pickup=',

                /**
                 * Suggester validation url
                 */
                 validationUrl: undefined,

				/**
				 * Suggester request timeout in seconds
				 */
				requestTimeout: 5,

				 /**
				  * Minimum number of letters needed to activate suggester
				  */
				letters2activate: 3,

				/**
				 * If set to true, removes white chars from user phrase internaly (no changes to visual representation)
				 */
				trimPhrase: true,

				/**
				 * Sets focus on designated suggester input after page finishes to load.
				 */
				focusOn: false,

				/**
				 * Width (in pixels) of suggesters list. Set to 0 to make suggester auto-determinate the value.
				 */
				width: 0,

				/**
				 * Width offset to shrink/enlarge suggester list after auto-determining the width. may be subzero.
				 */
				widthOffset: 0,

				/**
			     * Top offset to change suggester position after auto-determining the y-pos. may be subzero.
			     */
			    topOffset: 0,

				/**
				 * Shows and hides suggester list with effect.
				 */
				suggesterFade: false,

				/**
				 * Enable to override dropoff location whenever pickup location was chosen
				 */
				dropoffOverride: true,

				/**
				 * If true, json response data will be cleared from any illegal characters
				 */
				clearResponseData: false,

				/**
				 * If true, suggester input fields will have browser default autocomplete set to off
				 */
				disableAutocomplete: true,

				/**
				 * If true, suggester list will disapear on Escape key pressed.
				 */
				hideOnEsc: true,

                /**
                 * TODO: If true, suggester will ask on every change of phrase (not only on 3 letter long phrase)
                 */
                askAlways: true,
                    
                /**
                 * Set input field names.
                 */
				input_loc_name: 'loc_name',
				input_loc_code: 'loc_code',
				input_land_name: 'land',
				input_land_code: 'land_code',
                input_group_code: 'v_group',

				/**
				 * Set hidden input name and id values.
				 */
				pickup_loc_name: 'suggester_pickup',
				pickup_loc_code: 'suggester_first_loc_code',
				pickup_land_name: 'suggester_first_land_name',
				pickup_land_code: 'suggester_first_land_code',
                pickup_group_code: 'suggester_first_group_code',

				dropoff_loc_name: 'suggester_dropoff',
				dropoff_loc_code: 'suggester_second_loc_code',
				dropoff_land_name: 'suggester_second_land_name',
				dropoff_land_code: 'suggester_second_land_code',
                dropoff_group_code: 'suggester_second_group_code',

                /**
                 * Submit button selector. If set, suggester will try to do the validation and call callbackOnSubmit function afterwards.
                 */
                submitButton: undefined,

                /**
                 * Callback on enter.
                 */
                callbackOnEnter: function(){},

                /**
                 * Callback on submit.
                 */
                callbackOnSubmit: function(){},


				/******************************************
				 * Filters - optionaly shows/hides some information in list on special demand.
				 * (for eg. hotels doesn't need country caption)
				 *****************************************/

				/**
			 	* Turn on/off showing of country caption in suggester list.
			 	*/
				filterShowCaption: true,

				/**
				 * Adds embos to part of suggested text
				 */
				filterShowEmboss: true,

				/**
				 * Hide aliases if they have the same name as location.
				 */
				filterHideEqualAlias: true,

				/**
			     * Turn on/off showing loc_code, even if code.length != 3
			     **/
			    filterAlwaysShowLocCode: false
			};

			/**
			 * Initial setup
			 */
			var options = $.extend(defaults, options);

			/**
			 * It checks if user clicked outside suggester list and hides suggester then
			 */
			var blurize = function(event){
				hideSuggester();
			};

			/**
			 * Blocks enter from submiting the form.
			 * @param {Object} event
			 */
			var onEnter = function(event){
				if ( event.keyCode == 13 ) {
					// if something in both was selected, set hidden value and submit form.
					// if just one input was filled, set the same as in other one to it.
					var id = $("#suggester_list").find(".selected").attr("id");
					if (id) {
						var selected = returnSelectedInfo(id);
						setSuggesterVars(selected[options.input_land_code], selected[options.input_loc_code], selected[options.input_loc_name], selected[options.input_land_name], selected[options.input_group_code]);
						hideSuggester();
						if (suggesterInput == 'first'){
							$(suggesterInputSecond).focus();
						}
					} else {
						//var tabindex = $().attr("tabindex");
						if (suggesterInput == 'first'){
							// console.debug("enter on first: " + lastPhrase);
							var tabindex = $(suggesterInputFirst).attr("tabindex");
							if ( tabindex > 0 && lastPhrase.length == options.letters2activate){
								//d("onEnter input first");
								var phrase = $(suggesterInputFirst).val();
								if ( lastResponseData != undefined ){
									if (lastResponseData.length > 0) {
										if (lastPhrase.toLowerCase() == lastResponseData[0][options.input_loc_code].toLowerCase()){
                                            setSuggesterVars ( lastResponseData[0][options.input_land_code], lastResponseData[0][options.input_loc_code], lastResponseData[0][options.input_loc_name], lastResponseData[0][options.input_land_name], lastResponseData[0][options.input_group_code]);
											suggesterShowUp = false;
											hideSuggester();
											suggesterInput = 'second';
											tabindex++;
											//$(suggesterInputFirst).parents().find("form").find("input[tabindex="+tabindex+"]").select();
                                            $(suggesterInputSecond).select();
										}
									}
								} else {
									return false;
								}
							}
						} else {
							if (suggesterInput == 'second'){
								//console.debug("enter on second: " + lastPhrase);
								var phrase = $(suggesterInputSecond).attr("value");
								if (phrase.length == options.letters2activate){
									if ( lastResponseData != undefined ){
										if (lastResponseData.length > 0) {
											if (phrase.toLowerCase() == lastResponseData[0][options.input_loc_code].toLowerCase()){
												setSuggesterVars ( lastResponseData[0][options.input_land_code], lastResponseData[0][options.input_loc_code], lastResponseData[0][options.input_loc_name], lastResponseData[0][options.input_land_name], lastResponseData[0][options.input_land_code], lastResponseData[0][options.input_group_code]);
												suggesterShowUp = false;
												hideSuggester();
											}
										}
									} else {
										return false;
									}
								}
								if (phrase.length > options.letters2activate){
                                    validate();
                                    //options.callbackOnEnter();
									//$(suggesterInputSecond).parents().find("form").submit();
								} else {
									return false;
								}
							}
						}
					}
					event.preventDefault();
					return false; // TODO: finish onEnter
				}
			};

			/**
			 * Key listener to determine suggesters next step AKA inside router
			 */
			var keyListener = function(event)
			{
				// hide suggester on ESC
				if (event.keyCode == 27 && options.hideOnEsc) {
					hideSuggester();
					return false;
				}

				if ( event.keyCode == 9 ){
					hideSuggester();
					return;
				}

				// change suggester after any change
				//if (actualInputValue != lastPhrase && lastResponseData != undefined && !suggesterOnRoute) {
				if ( ( $("#suggester_list").length > 0 ) && !suggesterOnRoute) {
					// on key up
    				if (event.keyCode == 38) {
						suggesterCursorUp();
						return false;
					}

					// on key down
					if (event.keyCode == 40) {
						suggesterCursorDown();
						return false;
					}
				}

				if ( ( event.keyCode >= 65 && event.keyCode <= 90 ) || event.keyCode == 8 || event.keyCode == 40) {
				// get actual user written string from input
				var actualInputValue = $(this).val();

				// clean remembered vars for actualy changed input
				cleanSuggesterVars(suggesterInput);

//				mirror("lastPhrase", actualInputValue);
//				mirror("lastResponseData", lastResponseData);
//				mirror("lastResponsePhrase", lastResponsePhrase);
//				mirror("suggesterOnRoute", suggesterOnRoute);

				// TODO: removed for now.
				//if (defaults.trimPhrase) actualInputValue = jQuery.trim(actualInputValue);

				if ( actualInputValue.length >= options.letters2activate )
				{
					$(this).addClass('suggester_active');

					var actualDataPhrase = actualInputValue.substr(0, options.letters2activate).toLowerCase();
//					if (lastResponsePhrase != undefined) {
					var lastDataPhrase = lastResponsePhrase;
//					}

					// update suggester data if phrase was changed
					if (actualDataPhrase !== lastDataPhrase)
					{
						// update suggester data (load from server)
						updateSuggesterData(actualDataPhrase);

						// remember actual 3L phrase
						lastResponsePhrase = actualDataPhrase;
					} else {
						// show suggester without refreshing data
						showSuggester(actualInputValue);
					}

				} else {
					$(this).removeClass('suggester_active');
					//if ( actualInputValue.length < defaults.letters2activate)
					hideSuggester();
				}

				// remember as last used phrase (whole word)
				lastPhrase = actualInputValue;
				}
				if (!suggesterOnRoute) {
					suggesterShowUp = true;
				}
			};

            var jumpUp = function(){
                var selected  = $("#suggester_list").find(".selected");
                var st = 0;
                if (selected.length == 1){
                    if (isNaN(selected.position().top)) {
                        st = 0;
                    } else {
                        st = selected.position().top;
                    }
                }
                var sl = $("#suggester_list").scrollTop();
                if ((st + sl) <= $("#suggester_list").scrollTop()) {
                    $("#suggester_list").scrollTop(st + sl); 
                } else {
                    //$("#suggester_list").scrollTop(0); 
                }
            };

            var jumpDown = function(){
                var selected  = $("#suggester_list").find(".selected");
                var st = 0;
                if (selected.length == 1){
                    if (isNaN(selected.position().top)) {
                        st = 0;
                    } else {
                        st = selected.position().top;
                    }
                }
                var sl = $("#suggester_list").scrollTop();
                if ((st + sl) >= $("#suggester_list").scrollTop()) {
                   $("#suggester_list").scrollTop(st + sl); 
                } else {
                    //$("#suggester_list").scrollTop(0); 
                }
            };

            var suggesterCursorUp = function() {
                var choices = $("#suggester_list").find('.choice');
                var selected  = $("#suggester_list").find(".selected");
                var index = $(choices).index($(selected));

                if (index < 0) {
                    $("#suggester_list > .choice:last").addClass('selected');
                } else {
                    $(selected).removeClass('selected');
                    $(choices).eq(index - 1).addClass('selected');    
                }
                jumpUp();
            };

			var suggesterCursorDown = function()
			{
				var choices = $("#suggester_list").find('.choice');
				var selected  = $("#suggester_list").find(".selected");
				var index = $(choices).index($(selected));

				if (index < 0){
					$("#suggester_list > .choice:first").addClass('selected');
				} else {
					if ((index + 1) < $(choices).length){
						$(selected).removeClass('selected');
						$(choices).eq(index + 1).addClass('selected');
					} else {
						$(selected).removeClass('selected');
						$("#suggester_list > .choice:first").addClass('selected');
					}
				}
                jumpDown();
			};

			/**
			 * Sends request and returns response from designated url
			 */
            var updateSuggesterData = function(phrase){
                var rqUrl = options.requestUrl + phrase;

                // set suggesterOnRoute to not request while requesting already
                if (!suggesterOnRoute) {
                    suggesterOnRoute = true;

                    $.ajax({
                        url: rqUrl,
						timeout: (options.requestTimeout * 1000),
                        dataType: "text",
                        data: 'phrase='+phrase,
                        type: 'POST',
                        success: function(response){

							// if data is obsolete, do request for newest.
							if (suggesterRequestQuery) {
								temp = suggesterRequestQuery;
								//mirror('suggesterRequestQuery', suggesterRequestQuery);
								resetSuggesterQuery();
								suggesterOnRoute = false;
								updateSuggesterData(temp);
								showSuggester(phrase);
							}

                            // remove some junk from response
                            var text = response.replace(/createRPCDone/g, "");
							//var text = response;

                            // validate text to be realy JSON
                            if (options.clearResponseData) {
                            	text = !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(text.replace(/"(\\.|[^"\\])*"/g, ''))) && eval('(' + text + ')');
							}

                            // update stored suggests
							lastResponseData = eval( text );

                            suggesterOnRoute = false;

							showSuggester(lastPhrase);
							suggesterShowUp = true;
                        },
                        error: function(response){
                            suggesterOnRoute = false;
							resetSuggesterQuery();
                        }
                    });
                } else {
					// add request to query for further send
					querySuggesterRequest(phrase);
				}
            };

			/**
			 * Adds phrase to query for further use
			 * @param {Object} phase
			 */
			var querySuggesterRequest = function(phrase)
			{
				suggesterRequestQuery = phrase;
			};

			/**
			 * Resets suggester request query
			 */
			var resetSuggesterQuery = function()
			{
				suggesterRequestQuery = undefined;
			};

			/**
			 * Returns location data for designated location code
			 * @param {Object} code
			 */
			var returnSelectedInfo = function(code)
			{
				for (i in lastResponseData){
					// one place from list
					if (lastResponseData[i][options.input_loc_code] == code) {
						return lastResponseData[i];
					}
				}
				return false;
			};

			/**
			 * Set focus on first suggester input
			 */
			var setStartFocus = function()
			{
				if (options.focusOn.length > 0) $(options.focusOn).focus();
			};

			/**
			 * Puts prepared html list under input box
			 */
			var showSuggester = function(phrase)
			{
                if(suggesterShowUp){

				// prepare suggests
				var choices_counter = prepareSuggests(phrase);

				//$("#suggester_list").css('height', '20px');

				// show suggests
				//$("#suggester_list").slideDown('normal'); //css('display', 'block');

				if (choices_counter > 0) {
					setSuggesterPosition();
					$("#suggester_list").css('left', suggesterPosition.left);
					$("#suggester_list").css('top', suggesterPosition.top);
                    $("#suggester_list").css('width', suggesterWidth);

					if (options.suggesterFade){
						$("#suggester_list").fadeIn();
					} else {
						$("#suggester_list").show();
					}
                    
                    // ;( IE6 SUCKS!
                    if (isIE6 === true) {
                        var suggesterHeight = $("#suggester_list").height();
                        //$('#suggester_list_back').remove();
                        suggesterWidth = (parseInt(suggesterWidth) + 1) + 'px';
                        $("#suggester_list_back").css('left', suggesterPosition.left).css('top', suggesterPosition.top).css('width', suggesterWidth).css('height', suggesterHeight).css('display', 'block');
                    }

					// reset suggester list position
					//setSuggesterPosition();
                    $("#"+suggesterInput+"_suggester_list > .choice:first").each(function(){
                        $(this).addClass('selected');
                    });

					// bind mouseOver and mouseClick to suggester list
					$("#suggester_list > .choice").hover( function(){
						// remove hidden part - reset suggesterSelectedLocation
						//cleanSuggesterVars(suggesterInput); - commented @ yanoo 2009 10 13
						// remove visual part - .selected class from .choice div
						$("#suggester_list").removeClass('selected');
						$(this).addClass('selected');
					}, function(){
						$(this).removeClass('selected');
					});

					// set item click
					$("#suggester_list .choice").bind('click', function(){
						// TODO: later on it has to be changed to function which sets all needed hidden variables

						var selected = returnSelectedInfo($(this).attr('id'));
						//if (typeof selected == 'object') {
						setSuggesterVars(selected[options.input_land_code], selected[options.input_loc_code], selected.loc_name, selected[options.input_land_name], selected[options.input_group_code]);
							//setSuggesterPhrase();
						hideSuggester();

						// jump to second suggester field after chosing in first
						if (suggesterInput == 'first'){
							$(suggesterInputSecond).focus();
						}

						//}
					});
				} else {
                    hideSuggester();
                }
			  }
			};

			var prepareSuggests = function(phrase){

				var choices_counter = 0;

                //var phrase = lastResponsePhrase;
                //var data = lastResponseData;

                // create suggester list if it not exists
                if ($("#suggester_list").length == 0) {
                    //suggesterInputFirst.after('<div id="suggester_list"></div>');
					//if ($("#endPage")){
                        //$('#endPage').before('<div class="suggester_list" id="suggester_list"></div>');
//                    } else {
                        $('body').append('<div class="suggester_list" id="suggester_list"></div>');
//                    }
                }

                // reset suggester list content
                $("#suggester_list").html('');
                var suggester_list_html = '';

                // container to store last country code
                var lastCountryCode = "";
                var lastLocationCode = "";
                var lastGroupCode = "";

				var firstCountryCode = "";
				var firstLocationCode = "";
                var firstGroupCode = "";

                // parse every element in suggester data to retrieve items (locations) to show
                for (i in lastResponseData) {

                    // relocate data in row (for different data sources)

					// do not show location when phrase is longer than 3 (IATA) and begin of phrase is the same as location code.
					if (phrase.length > 3 && phrase.substr(0,3).toUpperCase() === lastResponseData[i][options.input_loc_code] && i == 0)
					{
						continue;
					}

					// remember first location code
					if (i == 0){
						firstCountryCode = lastResponseData[i][options.input_land_code];
						firstLocationCode = lastResponseData[i][options.input_loc_code];
                        firstGroupCode = lastResponseData[i][options.input_group_code];
					}

					// sometimes return data has empty fields, dunno why
					if ( lastResponseData[i].loc_name == undefined) {
						continue;
					}

                    var location_name = lastResponseData[i].loc_name;
                    var location_code = lastResponseData[i][options.input_loc_code];
                    var location_alias = lastResponseData[i][options.input_group_code];

                    var rgx = new RegExp(phrase, 'gi');

                    var name_niddle = location_name.match(rgx);
                    var code_niddle = location_code.match(rgx);
                    var alias_niddle = location_alias.match(rgx);

                    if (name_niddle != null || code_niddle != null || alias_niddle != null) {

                        /* FILTER filterNameNoWrap */
                        //location_name = location_name.replace(/\s/, '&nbsp;');

                        /* FILTER filterShowEmboss */
                        if (options.filterShowEmboss) {
                            if (name_niddle)  {
								location_name = location_name.replace(rgx, '<span class="emboss">' + name_niddle + '</span>');
							}
                            if (code_niddle) {
								location_code = location_code.replace(rgx, '<span class="emboss">' + code_niddle + '</span>');
							}
                            if (alias_niddle) {
								location_alias = location_alias.replace(rgx, '<span class="emboss">' + alias_niddle + '</span>');
							}
                        }

                        /* FILTER filterShowCaption */
                        if (options.filterShowCaption) {

                            // add country strip if it is different as last one

							//	if (lastCountryCode !== lastResponseData[i].land_code && i != 0 &&  ){
							if (lastCountryCode != lastResponseData[i][options.input_land_code]) {

								// hide caption for phrase when location name and location iata are the same
								//if ( ! ( phrase.length == 3 &&  ( phrase.substr(0, 3).toUpperCase() == lastResponseData[i].loc_code || phrase.substr(0,3).toUpperCase() == lastResponseData[i].loc_name.toUpperCase() ) ) )
								if ( ! ( i == 0 && phrase.length == 3 &&  ( lastPhrase.substr(0, 3).toUpperCase() == lastResponseData[i][options.input_loc_code] || phrase.substr(0,3).toUpperCase() == lastResponseData[i][options.input_loc_name].toUpperCase() ) ) )
								{
									//$("#suggester_list").append('<div class="caption"><span>' + lastResponseData[i][options.input_land_name] + '</span></div>');
									suggester_list_html += '<div class="caption"><span>' + lastResponseData[i][options.input_land_name] + '</span></div>';
								}
								choices_counter++; // increment for further comparation
							}
                            lastCountryCode = lastResponseData[i][options.input_land_code];
                        }

                        // create list of accepted locations to show
                        var choice = '<div class="choice" id="' + lastResponseData[i][options.input_loc_code] + '" title="' + lastResponseData[i][options.input_loc_name] + '"><span class="name">' + location_name + '</span>';
                        // add location code only if this is IATA (3 letters)
                        if (lastResponseData[i][options.input_loc_code].length == 3 || options.filterAlwaysShowLocCode ) {
							choice += '<span class="code">' + location_code + '</span>';
						}
                        // add alias only if it is different than location name
                        if (lastResponseData[i][options.input_loc_name] != lastResponseData[i][options.input_group_code]) {
							choice += '<span class="alias">' + location_alias + '</span>';
						}
                        choice += '</div>';

						// check for earlier loc_code in array and don't show the same one

						if ( i == 0 && lastResponseData[1] != undefined){
							if ( lastResponseData[0][options.input_loc_code] != lastResponseData[1][options.input_loc_code] ) {
								//$("#suggester_list").append(choice);
								suggester_list_html += choice;
							}
						} else {
							//$("#suggester_list").append(choice);
							suggester_list_html += choice;
						}
						choices_counter++;
                    }
                }
                $("#suggester_list").append(suggester_list_html);
                if ( !isNaN(choices_counter) && choices_counter > 12){
                    $("#suggester_list").css('overflow', 'visible').css('overflow-y', 'scroll').css('height', '200px').css('width', '100px');
                    // FIXME: set width of suggester list
                } else {
                    $("#suggester_list").css('overflow-y', 'auto').css('height', 'auto');
                }
				return choices_counter;
            };

			/**
			 * This function creates (if lack of) hidden input add fill it with user
			 * settings like the information that user chose from suggester or not.
			 * @param {Object} variable
			 */
			var setSuggesterVars = function(land_code, loc_code, loc_name, land_name, group_code){
				switch (suggesterInput){
					case 'first' :  {
						setSuggesterVarsFirst(land_code, loc_code, loc_name, land_name, group_code);
						var dropoffOverride = options.dropoffOverride;
						if (checkInputNotSet('second') && dropoffOverride) {
							setSuggesterVarsSecond(land_code, loc_code, loc_name, land_name, group_code);
						}
						break;
					}
					case 'second' : {
						setSuggesterVarsSecond(land_code, loc_code, loc_name, land_name, group_code);
						if (checkInputNotSet('first')) {
							setSuggesterVarsFirst(land_code, loc_code, loc_name, land_name, group_code);
						}
						break;
					}
				}
			};

			/**
			 * Check if another input was already set
			 * @param {Object} input
			 */
			var checkInputNotSet = function(input){
				switch(input){
					case 'first': {
						return ( suggesterFirstLandCode && suggesterFirstLocCode ) ? false : true;
						break;
					}
					case 'second': {
						return ( suggesterSecondLandCode && suggesterSecondLocCode ) ? false : true;
						break;
					}
				}
			};

			/**
			 * Set all values to first suggester input
			 * @param {Object} land_code
			 * @param {Object} loc_code
			 * @param {Object} loc_name
			 * @param {Object} land_name
			 * @param {Object} group_code
			 */
            var setSuggesterVarsFirst = function(land_code, loc_code, loc_name, land_name, group_code){
                // if there is no input for variables yet, create one and put there actual user settings
                if ($('input#'+options.pickup_land_code).length == 0) {
                    $('.suggester').filter('.first').after('<input type="hidden" id="'+options.pickup_land_code+'" name="'+options.pickup_land_code+'" value="" />');
                }
                if ($('input#'+options.pickup_land_name).length == 0) {
                    $('.suggester').filter('.first').after('<input type="hidden" id="'+options.pickup_land_name+'" name="'+options.pickup_land_name+'" value="" />');
                }
                if ($('input#'+options.pickup_loc_code).length == 0) {
                    $('.suggester').filter('.first').after('<input type="hidden" id="'+options.pickup_loc_code+'" name="'+options.pickup_loc_code+'" value="" />');
                }
                if ($('input#'+options.pickup_group_code).length == 0) {
                    $('.suggester').filter('.first').after('<input type="hidden" id="'+options.pickup_group_code+'" name="'+options.pickup_group_code+'" value="" />');
                }
				suggesterFirstLandCode = land_code;
				suggesterFirstLandName = land_name;
				suggesterFirstLocCode = loc_code;
                suggesterFirstGroupCode = group_code;
                $("input#"+options.pickup_land_code).val(land_code);
                $("input#"+options.pickup_land_name).val(land_name);
                $("input#"+options.pickup_loc_code).val(loc_code);
                $("input#"+options.pickup_group_code).val(group_code);
                setSuggesterPhrase(loc_name, 'first');
            };

			/**
			 * Set all values to second suggester input
			 * @param {Object} land_code
			 * @param {Object} loc_code
			 * @param {Object} loc_name
			 */
            var setSuggesterVarsSecond = function(land_code, loc_code, loc_name, land_name, group_code){
                if ($('input#'+options.dropoff_land_code).length == 0) {
                    $('.suggester').filter('.second').after('<input type="hidden" id="'+options.dropoff_land_code+'" name="'+options.dropoff_land_code+'" value="" />');
                }
                if ($('input#'+options.dropoff_land_name).length == 0) {
                    $('.suggester').filter('.second').after('<input type="hidden" id="'+options.dropoff_land_name+'" name="'+options.dropoff_land_name+'" value="" />');
                }
                if ($('input#'+options.dropoff_loc_code).length == 0) {
                    $('.suggester').filter('.second').after('<input type="hidden" id="'+options.dropoff_loc_code+'" name="'+options.dropoff_loc_code+'" value="" />');
                }
                if ($('input#'+options.dropoff_group_code).length == 0) {
                    $('.suggester').filter('.first').after('<input type="hidden" id="'+options.dropoff_group_code+'" name="'+options.dropoff_group_code+'" value="" />');
                }
				suggesterSecondLandCode = land_code;
				suggesterSecondLandName = land_name;
				suggesterSecondLocCode = loc_code;
                suggesterSecondGroupCode = group_code;
                $("input#"+options.dropoff_land_code).val(land_code);
                $("input#"+options.dropoff_land_name).val(land_name);
                $("input#"+options.dropoff_loc_code).val(loc_code);
                $("input#"+options.dropoff_group_code).val(group_code);
                setSuggesterPhrase(loc_name, 'second');
            };

			/**
			 * Cleans user chosen location
			 * @param {Object} input
			 */
			var cleanSuggesterVars = function(input)
			{
				switch(input){
					case 'first': {
							suggesterFirstLandCode = undefined;
							suggesterFirstLandName = undefined;
							suggesterFirstLocCode = undefined;
                            suggesterFirstGroupCode = undefined;
							$('#'+options.pickup_land_code).val('');
							$('#'+options.pickup_land_name).val('');
							$('#'+options.pickup_loc_code).val('');
                            $('#'+options.pickup_group_code).val('');
						break;
					}
					case 'second': {
							suggesterSecondLandCode = undefined;
							suggesterSecondLandName = undefined;
							suggesterSecondLocCode = undefined;
                            suggesterSecondGroupCode = undefined;
							$('#'+options.dropoff_land_code).val('');
							$('#'+options.dropoff_land_name).val('');
							$('#'+options.dropoff_loc_code).val('');
                            $('#'+options.dropoff_group_code).val('');
						break;
					}
				}
			};

			/**
			 * Fills actual suggester input with designated phrase
			 */
			var setSuggesterPhrase = function(phrase, input)
			{
				var which = (input) ? input : suggesterInput;
				switch (which) {
					case 'first': { $(suggesterInputFirst).val(phrase); break; }
					case 'second': { $(suggesterInputSecond).val(phrase); break; }
				}
			};

			/**
			 * Hide suggester
			 */
			var hideSuggester = function()
			{
				if (options.suggesterFade){
					$("#suggester_list").fadeOut("normal", function(){
						$(this).remove();
					});
				} else {
				//$("#suggester_list").slideUp("fast", function(){
					$("#suggester_list").remove();
				//});
				}
                if (isIE6 === true) {
                    hideIFrameBG();
                }
			};

			/**
			 * Sets position of suggester list
			 */
			var setSuggesterPosition = function(){
			    if (suggesterInput == 'first') {
				     suggesterPosition = $(suggesterInputFirst).offset();
				     suggesterWidth = (options.width > 0) ? options.width : $(suggesterInputFirst).innerWidth();
				     suggesterWidth += options.widthOffset;

				     suggesterPosition.top += suggesterInputFirst.outerHeight();
				     suggesterPosition.top += options.topOffset;

				     suggesterPosition.left += parseInt($(suggesterInputFirst).css('borderLeftWidth'));
		    	} else {
				     suggesterPosition = $(suggesterInputSecond).offset();
				     suggesterWidth = (options.width > 0) ? options.width : $(suggesterInputSecond).innerWidth();
				     suggesterWidth += options.widthOffset;

				     suggesterPosition.top += suggesterInputSecond.outerHeight();
				     suggesterPosition.top += options.topOffset;

				     suggesterPosition.left += parseInt($(suggesterInputSecond).css('borderLeftWidth'));
				}
		   };

            var createIFrameBG = function(){
                if ( $("#suggester_list_back").length == 0 ){
                    var iframe = '<iframe src="" id="suggester_list_back" frameborder="no" style="border:0; z-index:10; background: rgb(255, 255, 255) none repeat scroll 0% 0%; visibility: visible; position: absolute; left: -100px; top: -100px; width: 10px; height: 10px; display: none;"></iframe>';
                    $('body').append(iframe);
                }
            };

            var hideIFrameBG = function(){
                $("#suggester_list_back").css('width', '10px').css('height', '10px').css('left', '-100px').css('top', '-100px');
            }

			/**
			 *
			 */
			var setFocus = function()
			{
				suggesterInput = ($(this).hasClass('second') ) ? 'second' : 'first';
				//setSuggesterPosition();
				// TODO: set keyup event here to trigger suggester preparation and show off
				//showSuggester($(this).val());
				//$(this).keyup();

//				mirror('suggesterInput', suggesterInput);
//				mirror('suggesterPosition', suggesterPosition.left+'x'+suggesterPosition.top);
			};

            var validate = function(){
                // get params to validate
                var pickup_phrase = ($("#suggester_pickup").val() || '');
                var dropoff_phrase = ($("#suggester_dropoff").val() || '');

                var pckloc = ($("#suggester_first_loc_code").val() || '');
                var drploc = ($("#suggester_second_loc_code").val() || '');

                var pcklnd = ($("#suggester_first_land_code").val() || '');
                var drplnd = ($("#suggester_second_land_code").val() || '');
                // send params to validator

                $.ajax({
                    url: options.validationUrl,
                    dataType: "json",
                    type: "POST",
                    data: ({ pickup: pickup_phrase, dropoff: dropoff_phrase, pckloc: pckloc, drploc: drploc, pcklnd: pcklnd, drplnd: drplnd }),
                    success: function(msg){
                        options.callbackOnSubmit(msg);
                        // show suggester list if message != OK
                        if (msg.message != 'OK'){
                            if (msg.pickup.loc_code == '' || msg.dropoff.loc_code == '') {
                                suggesterInput = 'first';
                                updateSuggesterData(pickup_phrase);
								showSuggester(pickup_phrase);
                            }
                        }
                    }
                });
            }

			/**
			 * Mirrors value to designated place onscreen.
			 * @param {Object} key
			 * @param {Object} value
			var mirror = function(key, value)
			{
				var k = "#"+key;
				$(k).html(key +": "+value);
			};*/

			/**
			 * Main loop
			 */
			return this.each(function(){

                    if (isIE6 === true){
                        createIFrameBG();
                    }

                    if ( options.disableAutocomplete ){
                        $(this).attr("autocomplete", "off");
                    }

                    if (options.submitButton){
                        $(options.submitButton).bind('click', validate);
                    }

                    // Bind callback to onEnter
                    $(this).bind('keypress', onEnter);

                    // Bind callback to every key pressed (UP)
                    $(this).bind('keyup', keyListener);

                    // hide suggester when somebody click someware outside the suggester list
                    $("html").bind('click', blurize);

                    // Set suggester inputs as first and second and remember them as objects inside
                    if (suggesterInputFirst)
                    {
                        $(this).attr("name", options.dropoff_loc_name);
                        suggesterInputSecond = $(this);
                        $(suggesterInputSecond).addClass("second");
                    } else {
                        $(this).attr("name", options.pickup_loc_name);
                        suggesterInputFirst = $(this);
                        $(suggesterInputFirst).addClass("first");
                    }

                    $(this).bind('focus', setFocus);
                    //$(this).bind('blur', hideSuggester);

                    /**
                     * Set focus on chosen (first) input in form if its selector is set
                     */
                    setStartFocus();
			});
		};
})(jQuery);

