

;(function($) {
	
$.fn.extend({
	autocomplete: function(urlOrData, options) {
		var isUrl = typeof urlOrData == "string";
		options = $.extend({}, $.Autocompleter.defaults, {

                        reloadData: typeof options.onChangeTerm == "function",
                        moreParams: $v$.tools.getAsObject(options.moreParams),

			url: isUrl ? urlOrData : null,
			data: isUrl ? null : urlOrData,
			delay: isUrl ? $.Autocompleter.defaults.delay : 10,
			max: options && !options.scroll ? 10 : 150
		}, options);

		
		options.highlight = options.highlight || function(value) { return value; };

		
		options.formatMatch = options.formatMatch || options.formatItem;
		
		return this.each(function() {
			new $.Autocompleter(this, options);
		});
	},

	hideResultsNow: function() {
		return this.trigger("hideResultsNow");
	},
	getContainer: function() {
		return this.triggerHandler("getContainer");
	},
	getInput: function() {
		return this.triggerHandler("getInput");
	},
	generateCacheKey: function(p, obj) {      
		return this.trigger("generateCacheKey", [p, obj]);
	},

	result: function(handler) {
		return this.bind("result", handler);
	},
	search: function(handler) {
		return this.trigger("search", [handler]);
	},
	flushCache: function() {
		return this.trigger("flushCache");
	},
	setOptions: function(options){
		return this.trigger("setOptions", [options]);
	},

	setACData: function(data, term){
		return this.trigger("setACData", [data, term]);
	},

	unautocomplete: function() {
		return this.trigger("unautocomplete");
	}
});

$.Autocompleter = function(input, options) {

	var KEY = {
		UP: 38,
		DOWN: 40,
		DEL: 46,
		TAB: 9,
		RETURN: 13,
		ESC: 27,
		COMMA: 188,
		PAGEUP: 33,
		PAGEDOWN: 34,
		BACKSPACE: 8
	};

	
	var $input = $(input).attr("autocomplete", "off").addClass(options.inputClass);

	var timeout;
	var previousValue = "";
	var cache = $.Autocompleter.Cache(options);
	var hasFocus = 0;
	var lastKeyPressCode;
	var config = {
		mouseDownOnSelect: false
	};
	var select = $.Autocompleter.Select(options, input, selectCurrent, config);
	
	var blockSubmit;
	
	
	$.browser.opera && $(input.form).bind("submit.autocomplete", function() {
		if (blockSubmit) {
			blockSubmit = false;
			return false;
		}
	});

	
	$input.bind(($.browser.opera ? "keypress" : "keydown") + ".autocomplete", function(event) {
		
		
		hasFocus = 1;
		

		lastKeyPressCode = event.keyCode;
		switch(event.keyCode) {
		
			case KEY.UP:
				event.preventDefault();
				if ( select.visible() ) {
					select.prev();
				} else {
					onChange(0, true);
				}
				break;
				
			case KEY.DOWN:
				event.preventDefault();
				if ( select.visible() ) {
					select.next();
				} else {
					onChange(0, true);
				}
				break;
				
			case KEY.PAGEUP:
				event.preventDefault();
				if ( select.visible() ) {
					select.pageUp();
				} else {
					onChange(0, true);
				}
				break;
				
			case KEY.PAGEDOWN:
				event.preventDefault();
				if ( select.visible() ) {
					select.pageDown();
				} else {
					onChange(0, true);
				}
				break;
			
			
			case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA:
			case KEY.TAB:
			case KEY.RETURN:            
				if( selectCurrent() ) {
					
					event.preventDefault();
					blockSubmit = true;
					return false;
				}
            hideResultsNow();
				break;
				
			case KEY.ESC:
				select.hide();
				break;
				
			default:
				clearTimeout(timeout);
				timeout = setTimeout(onChange, options.delay);
				break;
		}
	}).focus(function(){
		
		
		hasFocus++;

	}).bind("generateCacheKey", function() {
      var q = arguments[1];
      var obj = arguments[2];
      obj.key = generateCacheKey(q);
      return;
	}).bind("hideResultsNow", function() {
		if (hasFocus > 0)
         return;
      hideResultsNow();
	}).bind("getContainer", function() {      
      return select.getContainer();
	}).bind("getInput", function() {
      return $input;

	}).blur(function() {
		hasFocus = 0;
		if (!config.mouseDownOnSelect) {
			hideResults();
		}
	}).click(function() {
		
		if ( hasFocus++ > 1 && !select.visible() ) {
			onChange(0, true);
		}
	}).bind("search", function() {
		
		var fn = (arguments.length > 1) ? arguments[1] : null;
		function findValueCallback(q, data) {
			var result;
			if( data && data.length ) {
				for (var i=0; i < data.length; i++) {
					if( data[i].result.toLowerCase() == q.toLowerCase() ) {
						result = data[i];
						break;
					}
				}
			}
			if( typeof fn == "function" ) fn(result);
			else $input.trigger("result", result && [result.data, result.value]);
		}
		$.each(trimWords($input.val()), function(i, value) {
			request(value, findValueCallback, findValueCallback);
		});
	}).bind("flushCache", function() {
		cache.flush();

	}).bind("setACData", function() {
      var data = arguments[1];
      var term = arguments[2];
		var parsed = options.parse && options.parse(data) || parse(data);
      parsed.useMore = data.useMore;
		cache.add(generateCacheKey(term), parsed);
		receiveData(term, parsed);

	}).bind("setOptions", function() {
		$.extend(options, arguments[1]);
  		
		if ( "data" in arguments[1] )
			cache.populate();
	}).bind("unautocomplete", function() {
		select.unbind();
		$input.unbind();
		$(input.form).unbind(".autocomplete");
	});
	
	

        function setSingelSelection(form, name, value)
        {
				if (options.onChangeValue && typeof options.onChangeValue == "function")
				{
					var fn = options.onChangeValue.getBinding($input);
					fn(name, value);
				}
           var input = form.find("input[name='"+name+"']");
           var inputExists = (input.length > 0);

           if (!inputExists)
           {
              input = $v$.tools.createEl("input");
              input.type = "hidden";
              input.name = name;
              if (value)
                 input.value = value;
              form.prepend(input);
           }

           for (var i=0; i<input.length; i++)
           {
             if (input[i].type != "hidden" && !value)
                continue;

             $(input[i]).val(value);
             if (input[i].type != "hidden" && value)
             {
                if (typeof options.onFillField == "function")
                   options.onFillField(input);
             }
           }
        }

        function clearSelection(form)
        {
            for (var i=0; i<options.addParams.length;i++)
               setSingelSelection(form, options.addParams[i], "");
            for (var param in options.selectParams)
               setSingelSelection(form, param, "");
        }
        function setSelection(selection, form)
        {
            for (var i=0; i<options.addParams.length;i++)
               setSingelSelection(form, options.addParams[i], selection.data[i+1]);

            for (var param in options.selectParams)
               setSingelSelection(form, param, options.selectParams[param]);
        }

	function selectCurrent() {
		var selected = select.selected();
		if( !selected )

		{
         if (lastKeyPressCode != KEY.RETURN)
			clearSelection($(input.form));

			return false;

                }

		
		var v = selected.result;
		previousValue = v;
		
		if ( options.multiple ) {
			var words = trimWords($input.val());
			if ( words.length > 1 ) {
				var seperator = options.multipleSeparator.length;
				var cursorAt = $(input).selection().start;
				var wordAt, progress = 0;
				$.each(words, function(i, word) {
					progress += word.length;
					if (cursorAt <= progress) {
						wordAt = i;
						return false;
					}
					progress += seperator;
				});
				words[wordAt] = v;
				
				
				v = words.join( options.multipleSeparator );
			}
			v += options.multipleSeparator;
		}
		
		$input.val(v);

      setSelection(selected, $(input.form));

		hideResultsNow();
		$input.trigger("result", [selected.data, selected.value]);

      if (options.autoSubmit)
         $(input.form).submit();

		return true;
	}
	
	function onChange(crap, skipPrevCheck) {
		if( lastKeyPressCode == KEY.DEL ) {

		}
		
		var currentValue = $input.val();
		
		if ( !skipPrevCheck && currentValue == previousValue )
			return;

         if (lastKeyPressCode != KEY.UP &&
				 lastKeyPressCode != 40 &&
				 lastKeyPressCode != 38 &&
				 lastKeyPressCode != 37 &&
				 lastKeyPressCode != 39 &&
				 lastKeyPressCode != KEY.DOWN &&
				 lastKeyPressCode != KEY.ESC &&
				 lastKeyPressCode != KEY.PAGEUP &&
				 lastKeyPressCode != KEY.PAGEDOWN)
                clearSelection($(input.form));

		previousValue = currentValue;
		
		currentValue = lastWord(currentValue);

      currentValue = $.trim(currentValue);
      while (currentValue.indexOf("  ") > -1)
      {
         currentValue = currentValue.replace("  ", " ");
      }

		if ( currentValue.length >= options.minChars) {
			$input.addClass(options.loadingClass);
			if (!options.matchCase)
				currentValue = currentValue.toLowerCase();
			request(currentValue, receiveData, hideResultsNow);

if (options.autoSelect && select.getList())
{
  var items = select.getList().children("li");
  for (var i=0; i<items.length; i++)
  {
     if ($(items[i]).text().toLowerCase() == currentValue.toLowerCase())
    {
        setSelection(select.find(items[i]), $(input.form));
        break;
     }
  }
}

		} else {
			stopLoading();
			select.hide();
		}
	};
	
	function trimWords(value) {
		if (!value)
			return [""];
		if (!options.multiple)
			return [$.trim(value)];
		return $.map(value.split(options.multipleSeparator), function(word) {
			return $.trim(value).length ? $.trim(word) : null;
		});
	}
	
	function lastWord(value) {
		if ( !options.multiple )
			return value;
		var words = trimWords(value);
		if (words.length == 1) 
			return words[0];
		var cursorAt = $(input).selection().start;
		if (cursorAt == value.length) {
			words = trimWords(value)
		} else {
			words = trimWords(value.replace(value.substring(cursorAt), ""));
		}
		return words[words.length - 1];
	}
	
	
	function autoFill(q, sValue){
		
		if( options.autoFill && (lastWord($input.val()).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != KEY.BACKSPACE ) {
			
			$input.val($input.val() + sValue.substring(lastWord(previousValue).length));
			
			$(input).selection(previousValue.length, previousValue.length + sValue.length);
		}
	};

	function hideResults() {
		clearTimeout(timeout);
		timeout = setTimeout(hideResultsNow, 200);
	};

	function hideResultsNow() {
		var wasVisible = select.visible();
		select.hide();
		clearTimeout(timeout);
		stopLoading();
		if (options.mustMatch) {
			
			$input.search(
				function (result){
					
					if( !result ) {
						if (options.multiple) {
							var words = trimWords($input.val()).slice(0, -1);
							$input.val( words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator : "") );
						}
						else {
							$input.val( "" );
							$input.trigger("result", null);
						}
					}
				}
			);
		}
	};

	function receiveData(q, data) {      
		if ( data && data.length && hasFocus ) {
			stopLoading();
			select.display(data, q);
			autoFill(q, data[0].value);
			select.show();
		} else {
			hideResultsNow();
		}
	};


	function generateCacheKey(q) {
      var keyPrefix = $(input).data(options.keyPrefixDataName);
      if (!keyPrefix || keyPrefix == "")
         keyPrefix = "~~~~EMPTY~~~~";

      return keyPrefix+q;
	};


	function request(term, success, failure) {
		if (!options.matchCase)
			term = term.toLowerCase();



		var data = cache.load(generateCacheKey(term));

		
		if (data && data.length) {
			success(term, data);
		
		} else if( (typeof options.url == "string") && (options.url.length > 0) ){
			
			var extraParams = {
				timestamp: +new Date()
			};
			$.each(options.extraParams, function(key, param) {
				extraParams[key] = typeof param == "function" ? param() : param;
			});
			
			$.ajax({
				
				mode: "abort",
				
				port: "autocomplete" + input.name,
				dataType: options.dataType,
				url: options.url,
				data: $.extend({
					q: lastWord(term),
					limit: options.max
				}, extraParams),
				success: function(data) {
					var parsed = options.parse && options.parse(data) || parse(data);
					cache.add(term, parsed);
					success(term, parsed);
				}
			});

		} else if (options.reloadData ) {
                        var fn = options.onChangeTerm.getBinding($input, term);
                        fn();

		} else {
			
			select.emptyList();
			failure(term);
		}
	};
	
	function parse(data) {
		var parsed = [];

		for (var i=0; i < data.length; i++) {


			var row = data[i];

			if (row) {

				parsed[parsed.length] = {
					data: row,
					value: row[0],
					result: options.formatResult && options.formatResult(row, row[0]) || row[0]
				};
			}
		}
		return parsed;
	};

	function stopLoading() {
		$input.removeClass(options.loadingClass);
	};

};

$.Autocompleter.defaults = {

   onFillField: null,
   onChangeTerm: null,
   onChangeValue: null,
   onBeforeShow: null,
   moreURL: "",
   moreParams: {},
   selectParams: {},
   moreText: "",
   moreValueParam: "",
   addParams: [],
   autoSubmit: true,
   autoSelect: false,
   keyPrefixDataName: 'ac_keyprefix',
   leftDelta: 0,

	inputClass: "ac_input",
	resultsClass: "ac_results",
	loadingClass: "ac_loading",
	minChars: 1,
	delay: 400,
	matchCase: false,
	matchSubset: true,
	matchContains: false,
	cacheLength: 10,
	max: 100,
	mustMatch: false,
	extraParams: {},
	selectFirst: true,
	formatItem: function(row) { return row[0]; },
	formatMatch: null,
	autoFill: false,
	width: 0,
	multiple: false,
	multipleSeparator: ", ",
	highlight: function(value, term) {


		return value.replace(new RegExp("^(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "i"), "<strong>$1</strong>");

	},
    scroll: true,
    scrollHeight: 180
};

$.Autocompleter.Cache = function(options) {

	var data = {};
	var length = 0;
	
	function matchSubset(s, sub) {
		if (!options.matchCase) 
			s = s.toLowerCase();
		var i = s.indexOf(sub);
		if (options.matchContains == "word"){
			i = s.toLowerCase().search("\\b" + sub.toLowerCase());
		}
		if (i == -1) return false;
		return i == 0 || options.matchContains;
	};
	
	function add(q, value) {
		if (length > options.cacheLength){
			flush();
		}
		if (!data[q]){ 
			length++;
		}
		data[q] = value;
	}
	
	function populate(){
		if( !options.data ) return false;
		
		var stMatchSets = {},
			nullData = 0;

		
		if( !options.url ) options.cacheLength = 1;
		
		
		stMatchSets[""] = [];
		
		
		for ( var i = 0, ol = options.data.length; i < ol; i++ ) {
			var rawValue = options.data[i];
			
			rawValue = (typeof rawValue == "string") ? [rawValue] : rawValue;
			
			var value = options.formatMatch(rawValue, i+1, options.data.length);
			if ( value === false )
				continue;
				
			var firstChar = value.charAt(0).toLowerCase();
			
			if( !stMatchSets[firstChar] ) 
				stMatchSets[firstChar] = [];

			
			var row = {
				value: value,
				data: rawValue,
				result: options.formatResult && options.formatResult(rawValue) || value
			};
			
			
			stMatchSets[firstChar].push(row);

			
			if ( nullData++ < options.max ) {
				stMatchSets[""].push(row);
			}
		};

		
		$.each(stMatchSets, function(i, value) {
			
			options.cacheLength++;
			
			add(i, value);
		});
	}
	
	
	setTimeout(populate, 25);
	
	function flush(){
		data = {};
		length = 0;
	}
	
	return {
		flush: flush,
		add: add,
		populate: populate,
		load: function(q) {
			if (!options.cacheLength || !length)
				return null;
			
			if( !options.url && options.matchContains ){
				
				var csub = [];
				
				for( var k in data ){
					
					
					if( k.length > 0 ){
						var c = data[k];
						$.each(c, function(i, x) {
							
							if (matchSubset(x.value, q)) {
								csub.push(x);
							}
						});
					}
				}				
				return csub;
			} else 
			
			if (data[q]){
				return data[q];
			} else
			if (options.matchSubset) {
				for (var i = q.length - 1; i >= options.minChars; i--) {
					var c = data[q.substr(0, i)];
					if (c) {
						var csub = [];
						$.each(c, function(i, x) {
							if (matchSubset(x.value, q)) {
								csub[csub.length] = x;
							}
						});
						return csub;
					}
				}
			}
			return null;
		}
	};
};

$.Autocompleter.Select = function (options, input, select, config) {
	var CLASSES = {
		ACTIVE: "ac_over"
	};
	
	var listItems,
		active = -1,
		data,
		term = "",
		needsInit = true,
		element,
		list;

	var list = list;

	
	
	function init() {
		if (!needsInit)
			return;
		element = $("<div/>")
		.hide()
		.addClass(options.resultsClass)
		.css("position", "absolute")
		.appendTo(document.body);
	
		list = $("<ul/>").appendTo(element).mouseover( function(event) {
			if(target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') {
	            active = $("li", list).removeClass(CLASSES.ACTIVE).index(target(event));
			    $(target(event)).addClass(CLASSES.ACTIVE);            
	        }
		}).click(function(event) {

                        if ($(target(event)).hasClass("ac_more"))
                        {
                            if (options.moreEvent != null)
                            {
                                var moreEvent = options.moreEvent;
                                var value = $(input).val();
                                return moreEvent(value);
                            }
                            location = createMoreURL();
                            return true;
                        }

			$(target(event)).addClass(CLASSES.ACTIVE);
			select();
			
			input.focus();
			return false;
		}).mousedown(function() {
			config.mouseDownOnSelect = true;
		}).mouseup(function() {
			config.mouseDownOnSelect = false;
		});
		
		if( options.width > 0 )
			element.css("width", options.width);
			
		needsInit = false;
	} 
	
	function target(event) {
		var element = event.target;
		while(element && element.tagName != "LI")
			element = element.parentNode;
		
		if(!element)
			return [];
		return element;
	}

	function moveSelect(step) {
		listItems.slice(active, active + 1).removeClass(CLASSES.ACTIVE);
		movePosition(step);
        var activeItem = listItems.slice(active, active + 1).addClass(CLASSES.ACTIVE);
        if(options.scroll) {
            var offset = 0;
            listItems.slice(0, active).each(function() {
				offset += this.offsetHeight;
			});
            if((offset + activeItem[0].offsetHeight - list.scrollTop()) > list[0].clientHeight) {
                list.scrollTop(offset + activeItem[0].offsetHeight - list.innerHeight());
            } else if(offset < list.scrollTop()) {
                list.scrollTop(offset);
            }
        }
	};
	
	function movePosition(step) {
		active += step;
		if (active < 0) {
			active = listItems.size() - 1;
		} else if (active >= listItems.size()) {
			active = 0;
		}
	}
	
	function limitNumberOfItems(available) {
		return options.max && options.max < available
			? options.max
			: available;
	}
	

      
        function getValues ()
        {
            var result = [];

            var form = $(input).parents('form:first');
            var $inputs = $ ( "input, textarea, select", form);
            $inputs.each(function(i, el)
            {
               if ((el.type != "checkbox") ||
                  ($(el).is(':checked')))
               {
                  result[[el.name]] = $(el).val();
               }
            });

            return result;
        }


        function createMoreURL()
        {
           var params = $.extend({}, getValues(), options.moreParams);
           params[options.moreValueParam] = $(input).val();
           
           return  options.moreURL + "?" + $oe$.obj.toQueryString(params, false, escape);
        }

	function fillList() {
		list.empty();
		var max = limitNumberOfItems(data.length);

      if (!data.useMore)
         max = 1000;

		for (var i=0; i < max; i++) {
			if (!data[i])
				continue;
			var formatted = options.formatItem(data[i].data, i+1, max, data[i].value, term);
			if ( formatted === false )
				continue;
			var li = $("<li/>").html( options.highlight(formatted, term) ).addClass(i%2 == 0 ? "ac_even" : "ac_odd").appendTo(list)[0];
			$.data(li, "ac_data", data[i]);

                        if (i==max-1 && max < data.length && data.useMore)
                        {
                           i++;
                           var className = i%2 == 0 ? "ac_even ac_more" : "ac_odd ac_more";
                           formatted = options.formatItem([options.moreText], i+1, max, options.moreText, term);
                           li = $("<li/>").html(formatted).addClass(className).appendTo(list)[0];
                        }

		}
		listItems = list.find("li");
		if ( options.selectFirst ) {
			listItems.slice(0, 1).addClass(CLASSES.ACTIVE);
			active = 0;
		}
		
		if ( $.fn.bgiframe )
			list.bgiframe();
	}
	
	return {

		getList: function() {
                   return list;
                },
		getContainer: function() {         
                   return element;
                },
		find: function(item) {
                   return $.data(item, "ac_data");
                },

		display: function(d, q) {
			init();
			data = d;
			term = q;
			fillList();
		},
		next: function() {
			moveSelect(1);
		},
		prev: function() {
			moveSelect(-1);
		},
		pageUp: function() {
			if (active != 0 && active - 8 < 0) {
				moveSelect( -active );
			} else {
				moveSelect(-8);
			}
		},
		pageDown: function() {
			if (active != listItems.size() - 1 && active + 8 > listItems.size()) {
				moveSelect( listItems.size() - 1 - active );
			} else {
				moveSelect(8);
			}
		},
		hide: function() {
			element && element.hide();
			listItems && listItems.removeClass(CLASSES.ACTIVE);
			active = -1;
		},
		visible : function() {
			return element && element.is(":visible");
		},
		current: function() {
			return this.visible() && (listItems.filter("." + CLASSES.ACTIVE)[0] || options.selectFirst && listItems[0]);
		},
		show: function() {
      
			var offset = $(input).offset();         

         var padding = parseInt($(input).css("padding-left"));
         if (options.onBeforeShow && typeof options.onBeforeShow == "function")
         {
            var fn = options.onBeforeShow.getBinding($(input));
            var currentValue =  $(input).val();
            if (!options.matchCase)
   				currentValue = currentValue.toLowerCase();
            var width = typeof options.width == "string" || options.width > 0 ? options.width : $(input).width() + padding;
            fn($(input), options, currentValue, width);
         }

			element.css({



				width: typeof options.width == "string" || options.width > 0 ? options.width : $(input).width() + padding,

				top: offset.top + input.offsetHeight,
				left: offset.left

            , left: offset.left + options.leftDelta

			}).show();
            if(options.scroll) {
                list.scrollTop(0);
                list.css({
					maxHeight: options.scrollHeight,
					overflow: 'auto'
				});
				
                if($.browser.msie && typeof document.body.style.maxHeight === "undefined") {
					var listHeight = 0;
					listItems.each(function() {
						listHeight += this.offsetHeight;
					});
					var scrollbarsVisible = listHeight > options.scrollHeight;
                    list.css('height', scrollbarsVisible ? options.scrollHeight : listHeight );
					if (!scrollbarsVisible) {
						
						listItems.width( list.width() - parseInt(listItems.css("padding-left")) - parseInt(listItems.css("padding-right")) );
					}
                }
                
            }
		},
		selected: function() {
			var selected = listItems && listItems.filter("." + CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);
			return selected && selected.length && $.data(selected[0], "ac_data");
		},
		emptyList: function (){
			list && list.empty();
		},
		unbind: function() {
			element && element.remove();
		}
	};
};

$.fn.selection = function(start, end) {
	if (start !== undefined) {
		return this.each(function() {
			if( this.createTextRange ){
				var selRange = this.createTextRange();
				if (end === undefined || start == end) {
					selRange.move("character", start);
					selRange.select();
				} else {
					selRange.collapse(true);
					selRange.moveStart("character", start);
					selRange.moveEnd("character", end);
					selRange.select();
				}
			} else if( this.setSelectionRange ){

			} else if( this.selectionStart ){
				this.selectionStart = start;
				this.selectionEnd = end;
			}
		});
	}
	var field = this[0];
	if ( field.createTextRange ) {
		var range = document.selection.createRange(),
			orig = field.value,
			teststring = "<->",
			textLength = range.text.length;
		range.text = teststring;
		var caretAt = field.value.indexOf(teststring);
		field.value = orig;
		this.selection(caretAt, caretAt + textLength);
		return {
			start: caretAt,
			end: caretAt + textLength
		}
	} else if( field.selectionStart !== undefined ){
		return {
			start: field.selectionStart,
			end: field.selectionEnd
		}
	}
};

})(jQuery);

if (!$oe$ || !$ || !$oe$.ui)
   throw new Error ("Core libs missing");

(function ()
{
   
   var SB_DEFAULT_SELECTOR_CLASS = "bgfocus";
   var SB_DEFAULT_CLASS       = "bgfocusimg";
   var SB_ITEM_CLASS          = "subnav";
   var SB_SPECIALITEM_CLASS   = "subnav_selectbox";
   var SB_SPECIAL_BUTTON      = "#selectbox_btn";
   var SB_SPECIAL_BUTTON_LINK = "#selectbox_btn_link";
   var SB_ID_POSTFIX          = "toSearch";
   var SB_SPEZIALS_SELECTOR   = "#subnav li:last";
   var SB_CONTAINER_SELECTOR  = "#searchbox";
   var SB_ACTIVE_CLASS        = "on";
   var SB_NAME_PARAM          = "name";
   var SB_CI_PARAM            = "ci";
   var SB_CIID_PARAM          = "ciid";
   var SB_KGS_PARAM           = "kgs";
   var SB_BUAB_PARAM          = "buab";
   var SB_ZIP_PARAM           = "plz";
   var SB_DISTRICT_PARAM      = "district";
   
   
    
   var SB_S_KW  = "std_suchwort", SB_S_CI = "std_ort", 
   SB_S_CIR = "std_ortmerken";
   var SB_A_NA  = "adv_nachname", SB_A_ST = "adv_strasse", SB_A_NO = "adv_nr",
   SB_A_ZIP = "adv_plz", SB_A_CI  = "adv_ort";
   var SB_R_KW  = "umkreis_suchwort", SB_R_CI = "umkreis_ort", 
   SB_R_ST  = "umkreis_strasse", SB_R_NO = "umkreis_nr";
   var SB_B_TI  = "busbahn_zeit", SB_B_CI = "busbahn_startort";
   var SB_N_TI  = "notapo_uhrzeit";
   var SB_C_CI  = "geld_suchort", SB_C_ST  = "geld_strasse", 
   SB_C_NO  = "geld_nr";
   var SB_M_CI  = "kino_film_standort";
   var SB_P_ST  = "notapo_strasse", SB_P_NO  = "notapo_nr", 
   SB_P_CI  = "notapo_ort";
   var SB_Z_ST  = "plz_strasse", SB_Z_NO  = "plz_nr", 
   SB_Z_CI  = "plz_ort", SB_Z_ZIP = "plz_plz";
   var SB_J_KW  = "stellen_was", SB_J_CI  = "stellen_ort", 
   SB_J_CIR = "stellen_ortmerken"
   var SB_E_KW  = "veranst_wen_was", SB_E_CI  = "veranst_ort";            
   var SB_AC_ST = "vorw_strasse", SB_AC_No  = "vorw_nr",
   SB_AC_CI = "vorw_ort" ;
   var SB_WIZ_KW = "Privatperson_Name";
    
   
   var INPUTS_NO = {};
   INPUTS_NO[SB_S_CI]   = [SB_A_ZIP, SB_Z_ZIP];
   INPUTS_NO[SB_R_CI]   = [SB_A_ZIP, SB_Z_ZIP];
   INPUTS_NO[SB_B_CI]   = [SB_A_ZIP, SB_Z_ZIP];
   INPUTS_NO[SB_C_CI]   = [SB_A_ZIP, SB_Z_ZIP];
   INPUTS_NO[SB_M_CI]   = [SB_A_ZIP, SB_Z_ZIP];
   INPUTS_NO[SB_P_CI]   = [SB_A_ZIP, SB_Z_ZIP];
   INPUTS_NO[SB_J_CI]   = [SB_A_ZIP, SB_Z_ZIP];
   INPUTS_NO[SB_E_CI]   = [SB_A_ZIP, SB_Z_ZIP];
   INPUTS_NO[SB_AC_CI]  = [SB_A_ZIP, SB_Z_ZIP];
   INPUTS_NO[SB_A_ZIP]  = [SB_S_CI, SB_R_CI, SB_B_CI, SB_C_CI, SB_M_CI, SB_P_CI, SB_J_CI, SB_E_CI, SB_AC_CI];    
   INPUTS_NO[SB_Z_ZIP]  = [SB_S_CI, SB_R_CI, SB_B_CI, SB_C_CI, SB_M_CI, SB_P_CI, SB_J_CI, SB_E_CI, SB_AC_CI];           
   var INPUTS = {};
   INPUTS[SB_S_KW]  = [SB_A_NA, SB_R_KW, SB_J_KW, SB_E_KW];
   INPUTS[SB_S_CI]  = [SB_R_CI, SB_C_CI, SB_M_CI, SB_P_CI, SB_J_CI, SB_E_CI, SB_AC_CI, SB_A_CI, SB_Z_CI]
   INPUTS[SB_S_CIR] = [SB_J_CIR];
   INPUTS[SB_A_NA]  = [SB_S_KW , SB_R_KW, SB_J_KW, SB_E_KW];
   INPUTS[SB_A_CI]  = [SB_S_CI, SB_Z_CI, SB_R_CI, SB_C_CI, SB_M_CI, SB_P_CI, SB_J_CI, SB_E_CI, SB_AC_CI];
   INPUTS[SB_A_ST]  = [SB_R_ST, SB_C_ST, SB_P_ST, SB_Z_ST, SB_AC_ST]; 
   INPUTS[SB_A_NO]  = [SB_R_NO, SB_C_NO, SB_P_NO, SB_Z_NO, SB_AC_No];
   INPUTS[SB_A_ZIP] = [SB_Z_ZIP];
   INPUTS[SB_R_KW]  = [SB_A_NA, SB_S_KW, SB_J_KW, SB_E_KW];
   INPUTS[SB_R_CI]  = [SB_S_CI, SB_C_CI, SB_M_CI, SB_P_CI, SB_J_CI, SB_E_CI, SB_AC_CI, SB_A_CI, SB_Z_CI];
   INPUTS[SB_R_ST]  = [SB_A_ST, SB_C_ST, SB_P_ST, SB_Z_ST, SB_AC_ST]; 
   INPUTS[SB_R_NO]  = [SB_A_NO, SB_C_NO, SB_P_NO, SB_Z_NO, SB_AC_No];
   INPUTS[SB_B_TI]  = [SB_N_TI];
   INPUTS[SB_C_CI]  = [SB_S_CI, SB_R_CI, SB_M_CI, SB_P_CI, SB_J_CI, SB_E_CI, SB_AC_CI, SB_A_CI, SB_Z_CI];
   INPUTS[SB_C_ST]  = [SB_R_ST, SB_P_ST, SB_A_ST, SB_Z_ST, SB_AC_ST]; 
   INPUTS[SB_C_NO]  = [SB_A_NO, SB_R_NO, SB_P_NO, SB_Z_NO, SB_AC_No];
   INPUTS[SB_M_CI]  = [SB_S_CI, SB_R_CI, SB_C_CI, SB_P_CI, SB_J_CI, SB_E_CI, SB_AC_CI, SB_A_CI, SB_Z_CI];
   INPUTS[SB_N_TI]  = [SB_B_TI];
   INPUTS[SB_P_CI]  = [SB_S_CI, SB_R_CI, SB_M_CI, SB_C_CI, SB_J_CI, SB_E_CI, SB_AC_CI, SB_A_CI, SB_Z_CI];
   INPUTS[SB_P_ST]  = [SB_R_ST, SB_C_ST, SB_A_ST, SB_Z_ST, SB_AC_ST]; 
   INPUTS[SB_P_NO]  = [SB_R_NO, SB_C_NO, SB_A_NO, SB_Z_NO, SB_AC_No];
   INPUTS[SB_Z_ST]  = [SB_R_ST, SB_C_ST, SB_P_ST, SB_A_ST, SB_AC_ST]; 
   INPUTS[SB_Z_NO]  = [SB_R_NO, SB_C_NO, SB_P_NO, SB_A_NO, SB_AC_No];
   INPUTS[SB_Z_CI]  = [SB_A_CI, SB_S_CI, SB_R_CI, SB_C_CI, SB_M_CI, SB_P_CI, SB_J_CI, SB_E_CI, SB_AC_CI];
   INPUTS[SB_Z_ZIP] = [SB_A_ZIP];
   INPUTS[SB_J_KW]  = [SB_A_NA, SB_R_KW, SB_S_KW, SB_E_KW];
   INPUTS[SB_J_CI]  = [SB_S_CI, SB_R_CI, SB_M_CI, SB_P_CI, SB_C_CI, SB_E_CI, SB_AC_CI, SB_A_CI, SB_Z_CI];
   INPUTS[SB_J_CIR] = [SB_S_CIR];
   INPUTS[SB_E_KW]  = [SB_A_NA, SB_R_KW, SB_J_KW, SB_S_KW];
   INPUTS[SB_E_CI]  = [SB_S_CI, SB_R_CI, SB_M_CI, SB_P_CI, SB_J_CI, SB_C_CI, SB_AC_CI, SB_A_CI, SB_Z_CI];
   INPUTS[SB_AC_ST] = [SB_R_ST, SB_C_ST, SB_P_ST, SB_Z_ST, SB_A_ST]; 
   INPUTS[SB_AC_No] = [SB_R_NO, SB_C_NO, SB_P_NO, SB_Z_NO, SB_A_NO];
   INPUTS[SB_AC_CI] = [SB_S_CI, SB_R_CI, SB_M_CI, SB_P_CI, SB_J_CI, SB_E_CI, SB_C_CI, SB_A_CI, SB_Z_CI];
          
   
     
   var SB_TYPES = {
      search_std       : {
         idSuffix    : "Standardsuche",
         fields      : [SB_S_KW, SB_S_CI, SB_S_CIR]                             
      }, 
      search_ext       : {
         idSuffix    : "ErweiterteSuche",
         fields      : [SB_A_NA, SB_A_ST, SB_A_NO, SB_A_ZIP, SB_A_CI]
      }, 
      search_radius    : {
         idSuffix    : "Umkreissuche",
         fields      : [SB_R_KW, SB_R_CI, SB_R_ST, SB_R_NO]
      }, 
      search_inverse   : {
         idSuffix : "Rueckwaertssuche",
         fields      : [SB_B_TI, SB_B_CI]
      }, 
      search_transport : {
         special  : true,
         idSuffix : "BusBahn",
         fields      : [SB_N_TI]
      }, 
      search_atm       : {
         special  : true,
         idSuffix : "Geldautomaten",
         fields      : [SB_C_CI, SB_C_ST, SB_C_NO]
      }, 
      search_cinema    : {
         special  : true,
         idSuffix : "Filme",
         fields      : [SB_M_CI]
      }, 
      search_pha       : {
         special  : true,
         idSuffix : "Notapotheken",
         fields      : [SB_P_ST, SB_P_NO, SB_P_CI]
      }, 
      search_zip       : {
         special  : true,
         idSuffix : "PLZ",
         fields      : [SB_Z_ST, SB_Z_NO, SB_Z_ZIP, SB_Z_CI]
      }, 
      search_job       : {
         special  : true,
         idSuffix : "Stellenagebote",
         fields      : [SB_J_KW, SB_J_CI, SB_J_CIR]
      }, 
      search_event     : {
         special  : true,
         idSuffix : "Veranstaltungen",
         fields      : [SB_E_KW, SB_E_CI]
      }, 
      search_areacode  : {
         special  : true,
         idSuffix : "Vorwahlen",
         fields      : [SB_AC_ST, SB_AC_No, SB_AC_CI]
      }
   };   
               
   
   var search = $oe$.getNamespace ("search");      
  
   
   var DEFAULT_OPTIONS =
   {   
      language  : "de",
      reg       : false,
      autoComplete:{
         delay      : 200,
         minChars   : 1,
         moreURL    : "",
         moreParams : "",
         moreEvent  : null,
         selectParams : "zvo_ok=4",
         matchSubset : false,
         onChangeTerm: null,
         selectFirst: false,
         autoSubmit: true,
         autoSelect: false
      },
      kwAutoComplete : {
         onChangeTerm: null,
         minChars: 1,
         delay: 200,
         matchSubset : false,
         selectFirst: false,
         autoSubmit: false
      }
   }


   
   
   
   this.getTypeByIdSuffix = function (idSuffix)
   {
      var t = false;
      for (var type in SB_TYPES)
      {                  
         if (SB_TYPES[type].idSuffix == idSuffix)            
         {
            return SB_TYPES[type];
         }
      }
      return null;
   }
   
   
   
   
  
         
   function SearchboxHandler (onClickFn, sbOptions, addParams, onAfterChangeFn)
   {
      var self = this;
      var onClick = onClickFn;
      var onAfterChange = onAfterChangeFn;
      var autoCompleter = null;
      var wizAutoCompleter = null;
      var wizKwAutoCompleter = null;
      var autoComplete = null;
      
      var kwAutoCompleter, kwAutoComplete;

      
      var adCache = {};
      
      this.types = SB_TYPES;
      
      if (!sbOptions)
         sbOptions = DEFAULT_OPTIONS;
      if (sbOptions.autoComplete)
         autoComplete = $.extend(DEFAULT_OPTIONS.autoComplete, sbOptions.autoComplete);
      if (sbOptions.kwAutoComplete)
         kwAutoComplete = $.extend(DEFAULT_OPTIONS.kwAutoComplete, sbOptions.kwAutoComplete);
            
      var options = $.extend(sbOptions, DEFAULT_OPTIONS);      
      this.options = options;
      
      
      if (autoComplete)
      {
         options.autoComplete = autoComplete;
         if (options.autoComplete.minChars < 1)
            options.autoComplete.minChars = DEFAULT_OPTIONS.autoComplete.minChars;
      }
      if (kwAutoComplete)
      {
         options.kwAutoComplete = kwAutoComplete;
         if (options.kwAutoComplete.minChars < 1)
            options.kwAutoComplete.minChars = DEFAULT_OPTIONS.kwAutoComplete.minChars;
      }
            
      var selectedItem = null;
      var noSelection = true;
      var prevSelectedItem = null;

      var selector = new SpecialSelectorHandler();
                  
      
      this.bindEvents = function ()
      {
                 

         var firstItem = null;
         var items = $("#subnav a, #subnav_selectbox a");
         for (var i=0; i<items.length; i++)
         {       
            var item = items[i];
            if (!item.id)
               continue;
               
            var arr = item.id.split("_");
            if (arr.length < 2 || arr[0] != SB_ID_POSTFIX)
               continue;
   
            var searchType = getTypeByIdSuffix(arr[1]);                      
            if (!searchType)
               continue;
            
            searchType.item = item;
            if (firstItem == null)
               firstItem = item;
                   
            $(item).bind ("click", self, onItemClick);
                        
            
            item.searchType = searchType;            
            
            
            if (($(item).parent()).hasClass(SB_ACTIVE_CLASS))      
               selectedItem = item;
         }
         
         
         selectItem();  

         
         selector.bindEvents();

         if (firstItem == null)
            return;

         if (selectedItem == null)
            selectedItem = firstItem;
         else
            noSelection = false;
         
         updateType (selectedItem.searchType, $(SB_CONTAINER_SELECTOR).html(), addParams);           
         doPostSelections();
      }
      
      
      this.select = function(type)
      {
         if (!type.item)
            return;

         if (type == prevSelectedItem.searchType)
            return;
         
         $(type.item).click();
      }
      
      
      function doPostSelections()
      {
         
         buildHiddenFields();
         bindInputDefaults();
         bindAutoCompleteFields();
         
         prevSelectedItem = selectedItem;

         onAfterItemChange(selectedItem.searchType);
      }
      
      
      this.getValues = function()
      {
         var result = [];
         var inputFields = $(SB_CONTAINER_SELECTOR + " input");
         for (var i=0; i<inputFields.length; i++)
         {
            var item = inputFields[i];
            
            if ($v$.tools.isCheckbox(item) && !item.checked)
               continue;

            result[item.name] = $(item).val();
         }
         return result;         
      }
      
      
      this.getValuesAsQueryString = function()
      {
         return $oe$.obj.toQueryString (this.getValues(), false, escape);
      }
     
      
      function selectItem()
      {         
         if (!selectedItem)
            return;

         var language = $v$.languages.getLanguage(options.language);

         if (!selectedItem.searchType.special)
         {
            ($(selectedItem).parent()).addClass(SB_ACTIVE_CLASS);
            $(SB_SPECIAL_BUTTON_LINK).html(language.search.special.linkText);
         }
         else
         {
            ($(SB_SPECIAL_BUTTON).parent()).addClass("on_last");
            $(SB_SPECIAL_BUTTON_LINK).html($(selectedItem).html());
         }
      }   

      
      function unselectItem()
      {         
         if (!prevSelectedItem || noSelection)
         {
            noSelection = false;
            return;
         }
         if (!prevSelectedItem.searchType.special)
            ($(prevSelectedItem).parent()).removeClass(SB_ACTIVE_CLASS);         
         else if (!selectedItem.searchType.special)
            ($(SB_SPECIAL_BUTTON).parent()).removeClass("on_last");         
      }   

      
      function onItemClick (item)
      {
         
         if (autoCompleter)
            autoCompleter.hideResultsNow();
         if(kwAutoCompleter)
            kwAutoCompleter.hideResultsNow();
         if (wizAutoCompleter)
            wizAutoCompleter.hideResultsNow();
         if(wizKwAutoCompleter)
            wizKwAutoCompleter.hideResultsNow();
         selector.hideSelectbox();
                                
         selectedItem = this;
         
         var searchTypeInfos = {
            lifeTime  : new Date().getTime()-selectedItem.searchType.lifeTime,
            filled    : selectedItem.searchType.filled ? true : false
         }
                         
         
         if ((!$oe$.val.isFunction(onClick)) || onClick(selectedItem.searchType, searchTypeInfos))
            internalSetHTML(selectedItem.searchType, selectedItem.searchType.html, selectedItem.searchType.addParams, true);

         return false;
      }
      
      function onAfterItemChange (item)
      {
         
         if ($oe$.val.isFunction(onAfterChange))
            onAfterChange(selectedItem.searchType);
      }

      
      function addHiddenFields(hiddens)
      {
         var forms =  $(SB_CONTAINER_SELECTOR + " fieldset");    
         for (i=0; i<forms.length; i++)
         {            
            for (var j=0; j<hiddens.length; j++)
            {
               if (i==0)
                  $(forms[i]).prepend(hiddens[j]);
               else
                  $(hiddens[j]).clone().prependTo(forms[i]);
            }
         }
      }
      
      
      function getHiddenFields()
      {
         var hiddens = [];
         var forms =  $(SB_CONTAINER_SELECTOR + " fieldset");    
         if (forms.length == 0)
            return hiddens;
         
         var inputs =  $(forms[0]).children("input[type='hidden']");    
         for (i=0; i<inputs.length; i++)
         {
            
            if (inputs[i].type != "hidden")
               continue;
           
            
            if (prevSelectedItem.searchType.addParams && 
               prevSelectedItem.searchType.addParams[inputs[i].name])
               continue;

            hiddens.push(inputs[i]);
         }
         return hiddens;
      }
      
      function updateType (searchType, html, addParams)
      {
         searchType.html = html;
         searchType.lifeTime = new Date().getTime();
         searchType.filled = true;
         searchType.addParams = addParams ? $v$.tools.getAsObject(addParams) : {};
      }      
      
      
      this.setHTML = function(type, html, addParams)
      {
         if (noSelection && prevSelectedItem.searchType == type)
            ;
         else if (type == prevSelectedItem.searchType)
            return;

         internalSetHTML(type, html, addParams);
      }
      
      function internalSetHTML (type, html, addParams, direkt)
      {
         updateType(type, html, addParams);

         if (selectedItem.searchType != type && !direkt)
            return;

         
         selectItem();
         unselectItem();
         
         var el, value, j, i;

         
         var values  = {};
         var checks  = {};         
         var hiddens = getHiddenFields();

         fields = prevSelectedItem.searchType.fields;
         for (i=0; i<fields.length; i++)
         {
            el = $("#"+fields[i])[0];

            if (!el || !el.id)
               continue;

            if ($(el).val())
            {
               value = $(el).val();
               if ($v$.tools.isCheckbox(el))
               {
                  if (!el.checked)
                     value = "";
                  else
                     checks[el.id] = el.checked;
               }
               values[el.id] = value;
            }
         }         
         
         
         $(SB_CONTAINER_SELECTOR).html(html);  
         
         
         addHiddenFields(hiddens);
         
         
         for (value in values)
         {
            var used = false;
            
            var isNumber = $v$.tools.isNumber(values[value]);
            if (isNumber)
            {  
               arr = INPUTS_NO[value];
               if (arr)
               {
                  arr.push(value);
                  for (j=0; j<arr.length; j++)
                  {
                     el = $("#"+arr[j]);            
                     if (!el || el.length != 1)
                        continue;
                     $(el[0]).val(values[value]);                 
                     used = true;
                     break;
                  }
               }
            }    
            
            
            if (used)
               continue;
 
            var arr;            
            
            arr = INPUTS[value];            
            if (!arr)
               continue;            
            arr.push(value);
            for (j=0; j<arr.length; j++)
            {
               el = $("#"+arr[j]);            
               if (!el || el.length != 1)
                  continue;
               
               if ($v$.tools.isCheckbox(el[0]))
                  el[0].checked = $oe$.val.isDefined (checks[value]);   
               else
                  $(el[0]).val(values[value]);     
            }         
         }
         doPostSelections();
      }            
      
      
      function buildHiddenFields ()
      {
         function createHiddenField(form, name, value)
         {
            if ($(form).find("input[name='"+name+"']").length > 0)
               return;
           
            var input = $v$.tools.createEl("input");
            input.type = "hidden";
            input.name = name;
            if (value)
               input.value = value;
            $(form).prepend(input);                       
         }
         
         var names = [SB_CIID_PARAM, SB_DISTRICT_PARAM ,SB_KGS_PARAM, SB_BUAB_PARAM, SB_ZIP_PARAM];
         var forms =  $(SB_CONTAINER_SELECTOR + " fieldset");             
            
         for (var i=0; i<forms.length; i++)
         {
            for (var j=0; j<names.length; j++)
               createHiddenField(forms[i], names[j]);
            
            for (param in selectedItem.searchType.addParams)
               createHiddenField(forms[i], param, selectedItem.searchType.addParams[param]);
            
            var params = $v$.tools.getAsObject(options.autoComplete.selectParams);
            for (param in params)
               createHiddenField(forms[i], param);            
         }
      }

      
      this.setAutoCompleteData = function (item, term, data, autoCompleteOptions, ad)
      {
         
         

         self.changeKwKeyPrefix(term);

         var values = [];

         $.each( data, function(entryIndex,entry )
         {
            var tmpData = $v$.tools.getAsObject(entry);
            var idx = values.length;
            values[idx] = [];
            values[idx][values[idx].length] = tmpData[SB_NAME_PARAM];
            values[idx][values[idx].length] = tmpData[SB_CIID_PARAM];
            values[idx][values[idx].length] = tmpData[SB_KGS_PARAM];
            values[idx][values[idx].length] = tmpData[SB_DISTRICT_PARAM];
            
            values[idx][values[idx].length] = tmpData[SB_ZIP_PARAM];
            values[idx][values[idx].length] = tmpData[SB_BUAB_PARAM];
         });

         values.useMore = autoCompleteOptions.useMore;
         if (ad){
            adCache[generateCacheKey(autoCompleter, term.toLowerCase())] = ad;
         }
         $(item).setACData(values, term);
      }

      function generateCacheKey(ac, term)
      {
         var obj = {};
         ac.generateCacheKey(term, obj);
         return obj.key;
      }

      
      this.generateAd = function (options)
      {
         var defaultOptions =
         {
            link : "#",
            name : "",
            address : "",
            src : "",
            text : "Mehr Informationen &ndash; hier klicken!",
            clickCallback : null,
            clickCallbackParam : ""
         };
         var opt, container, link, linkTag, addressTag, textLink, textTag, imgWidth = 100, imgHeight = 50;
         
         var imgContainerId = "__sbAdImgTag__" + parseInt(Math.random()*10000);
         try{
            opt = $.extend(defaultOptions, options);
            
            container = $('<div></div>').attr('class', 'content');
            
            link = $('<a></a>').attr('href', opt.link).html(opt.name);
            if($oe$.val.isFunction(opt.clickCallback)){
               link.click(function(){
                  opt.clickCallback(opt.clickCallbackParam)
               });
            }
            linkTag = $('<p></p>').attr('class', 'entryname').append(link);
            
            addressTag = $('<p></p>').attr('class', 'address').html(
               (! opt.address || opt.address == "" ? "&nbsp;" : opt.address)
               );
            
            if (opt.text && opt.text != ""){
               textLink = $('<a></a>').attr('href', opt.link).html(opt.text);
               if($oe$.val.isFunction(opt.clickCallback))
                  textLink.click(function(){
                     opt.clickCallback(opt.clickCallbackParam)
                  })
            }else{
               textLink = $('<span></span>').html("&nbsp;");
            }
            textTag = $('<p></p>').append(textLink);
            
            
            container.append(linkTag);
            if(addressTag){
               container.append(addressTag);
            }
            
            if (opt.src && opt.src != ""){
               container.append($('<p></p>').append($("<img>").attr({
                  src: opt.src,
                  width: imgWidth,
                  height: imgHeight,
                  alt: ""
               })));
            }
            else{
               container.append($('<p></p>').attr({
                  id: imgContainerId
               }).css({
                  height:imgHeight
               }));
            }
            if(textTag){
               container.append(textTag);
            }
            
            
            return container;
            
         }catch(ex){
            $oe$.log("Error SearchboxHandler.generateAd: "+ex)
         }
      }
      
      this.generateAdHint = function (options)
      {
         var defaultOptions =
         {
            headline : "",
            link: '#',
            text : "Mehr Informationen erhalten sie bei Ihrem Das &Ouml;rtliche Verlag",
            paddingTopBottom: 50,
            clickCallback : null,
            clickCallbackParam : ""
         }

         try{
            var options = $.extend(defaultOptions, options);

            var res = $('<div></div>').attr('class', 'content hint').css({
               'padding': options.paddingTopBottom + 'px 0'
            });
            res.append($('<p></p>').attr('class', 'headline').html(options.headline));
            if(options.text){
               var link = $('<a></a>').attr('href', options.link).html(options.text);
               if($oe$.val.isFunction(options.clickCallback))
                  link.click(function(){
                     options.clickCallback(options.clickCallbackParam)
                  });
               res.append($('<p></p>').append(link));
            }
            return res;
            
         }catch(ex){
            $oe$.log("Error SearchboxHandler.generateAdHint: "+ex)
         }
      }

      
      this.setAutoCompleteKeyword = function (item, term, data, ad)
      {
         self.changeKeyPrefix(term);

         var values = [];

         $.each( data, function(entryIndex, entry){
            var tmpData = $v$.tools.getAsObject(entry);
            var idx = values.length;
            values[idx] = [];
            values[idx][values[idx].length] = tmpData[SB_NAME_PARAM];
         });

         if (ad)
            adCache[generateCacheKey(kwAutoCompleter, term.toLowerCase())] = ad;

         $(item).setACData(values, term);
      }

      this.changeKwKeyPrefix = function (keyPrefix)
      {
         if(kwAutoCompleter)
            kwAutoCompleter.getInput().data("ac_keyprefix", keyPrefix);
      }

      this.changeKeyPrefix = function (keyPrefix)
      {
         autoCompleter.getInput().data("ac_keyprefix", keyPrefix);
      }

      function beforeShow(ac, opt, value, width)
      {              
         var fixAdWidth = 202;
         var el = ac.getContainer();
         if (!el.data('oetb_origWidth'))
            el.data('oetb_origWidth', width);
         var oldWidth = el.data('oetb_origWidth');
         var leftDelta = 0;

         
         $("#"+opt.adId).remove();
         el.width(oldWidth);

         var ad = adCache[generateCacheKey(ac, value.toLowerCase())];
         if (ad)
         {
            var adDiv = $("<div id=\""+opt.adId+"\" />").addClass("adcontainer").append(ad).width(fixAdWidth).css("float",opt.adFloating);
            el.children("ul").width(oldWidth).css("float",opt.adFloating);            
            el.append(adDiv);
            var adWidth = adDiv.outerWidth({
               margin:true
            });
            opt.width = oldWidth+adWidth;
            if (opt.adFloating == "right")
               leftDelta = -adWidth;
            opt.leftDelta = leftDelta;
            el.width(opt.width);
         }
         else
         {
            opt.width = oldWidth;
            opt.leftDelta = 0;
         }
      }
      
      
      function buildAcOptions(autoCompleteOptions, data)
      {         
         autoCompleteOptions = $v$.tools.getAsObject(autoCompleteOptions); 
         
         var language = $v$.languages.getLanguage(options.language);            
         var moreURL = autoCompleteOptions.moreURL;
         var params = $v$.tools.getAsObject(autoCompleteOptions.moreParams);
         params = $.extend({}, params);          
         params = $oe$.obj.extend(params, selectedItem.searchType.addParams);
         var selectParams = $v$.tools.getAsObject(autoCompleteOptions.selectParams);

         var addParams = [];
         addParams[addParams.length] = SB_CIID_PARAM;
         addParams[addParams.length] = SB_KGS_PARAM;
         addParams[addParams.length] = SB_DISTRICT_PARAM;
         
         addParams[addParams.length] = SB_ZIP_PARAM;
         addParams[addParams.length] = SB_BUAB_PARAM;

         var acOptions = $.extend({}, autoCompleteOptions);
         acOptions.addParams = addParams;
         acOptions.moreParams = params;
         acOptions.selectParams = selectParams;
         acOptions.moreText = language.search.more.linkText;
         acOptions.moreValueParam = SB_CI_PARAM;
         acOptions.cacheLength = 1000;
         acOptions.data = data;

         return acOptions;
      }

      
      function bindAutoCompleteFields()
      {
         
         function bindAutoCompleteFieldByType(inputType, autoComplete, kwContext)
         {
            if ($("#" + inputType).length == 0)
               return;
            if(kwContext){               
               var acOptions = $.extend({}, autoComplete);
               acOptions.onBeforeShow = beforeShow;
               acOptions.adFloating = "left";

               acOptions.adId = "oetb_entryAdKW";
               kwAutoCompleter = $("#" + inputType).autocomplete(autoComplete.data, acOptions);    
               $("#" + inputType).bind ("change", self, function(){
                  self.changeKeyPrefix(this.value)
               });
               self.changeKwKeyPrefix(autoComplete.keyPrefix);
               $("body").bind ("click", self, function(){
                  if(kwAutoCompleter)
                     kwAutoCompleter.hideResultsNow();
               });
               return;
            }
            var data = autoComplete.data;
            var acOptions = buildAcOptions(autoComplete);
            acOptions.onBeforeShow = beforeShow;
            acOptions.adFloating = "right";
            acOptions.adId = "oetb_entryAd";
            autoCompleter = $("#" + inputType).autocomplete(data, acOptions);
            $("#" + inputType).bind ("change", self, function(){
               self.changeKwKeyPrefix(this.value)
            });
            self.changeKeyPrefix(autoComplete.keyPrefix);

            wizAutoCompleter = $(".wiz_leftbox #Ort_PLZ").autocomplete(data, acOptions);
            $("body").bind ("click", self, function(){
               autoCompleter.hideResultsNow();
               wizAutoCompleter.hideResultsNow()
            });
         
            if(inputType === SB_WIZ_KW){
               wizKwAutoCompleter = $("#" + SB_WIZ_KW).autocomplete(data, acOptions);
            }
            $("body").bind ("click", self, function(){
               try{
                  if(kwAutoCompleter)   
                     kwAutoCompleter.hideResultsNow();
                  if(wizKwAutoCompleter)
                     wizKwAutoCompleter.hideResultsNow();
               }catch(ex){}
            });
         }

         
         var fields   = [SB_S_CI, SB_R_CI, SB_C_CI, SB_M_CI, SB_P_CI, SB_J_CI,
         SB_E_CI, SB_AC_CI, SB_A_CI, SB_Z_CI];
         var kwFields = [SB_S_KW, SB_A_NA, SB_R_KW, SB_J_KW, SB_E_KW, SB_WIZ_KW];
         var i;
         try{

            for (i = 0; i < fields.length; i++)
            {
               bindAutoCompleteFieldByType(fields[i], self.options.autoComplete);
            }

            for (i = 0; i < kwFields.length; i++)
            {
               bindAutoCompleteFieldByType(kwFields[i], self.options.kwAutoComplete, true);
            }            
         }catch(ex){
         
         }         
      }
            

      
      
      function bindInputDefaults()
      {
         $("."+SB_DEFAULT_SELECTOR_CLASS).defaultBg({
            className: SB_DEFAULT_CLASS
         });
      }
   }
   
   
   
   
   
  
   
   function SpecialSelectorHandler ()
   {   
      var self = this;
      var searchType = searchType;
      var onClick = onClick;
                  
            
      
      this.bindEvents = function ()
      {
         $(SB_SPECIAL_BUTTON).bind ("click", self, onClick);                                
         
         $(SB_SPECIAL_BUTTON).bind ("mouseleave", self, onMouseLeave);
      }
       
      
      function onClick (ev)
      {
         var left = parseFloat($(SB_SPECIAL_BUTTON).position().left);
         left += parseFloat($(SB_SPECIAL_BUTTON).css("margin-left"));
         var width = parseFloat($(SB_SPECIAL_BUTTON).width());
         width += parseFloat($(SB_SPECIAL_BUTTON).css("padding-left"));
         

         $("#"+SB_SPECIALITEM_CLASS).css("left", left);
         
         $("#"+SB_SPECIALITEM_CLASS).slideDown("normal");
         return false;
      }
      
      
      function onMouseLeave (ev)
      {                  
         hideSelectbox();
      }
      
      
      function hideSelectbox()
      {                  
         $("#"+SB_SPECIALITEM_CLASS).hide();
      }      
      
      this.hideSelectbox = hideSelectbox;
   }
   
   
   
   search.SearchboxHandler = SearchboxHandler;
   search.SB_TYPES = SB_TYPES;
   search.SB_ACTIVE_CLASS = SB_ACTIVE_CLASS;   
}());

