function getter(e,f,g,c){function d(a){a=$[e][f][a]||[];return typeof a=="string"?a.split(/,?\s+/):a}var b=d("getter");if(c.length==1&&typeof c[0]=="string")b=b.concat(d("getterSetter"));return $.inArray(g,b)!=-1};
$.widget=function(a,b){var c=a.split(".")[0];a=a.split(".")[1];$.fn[a]=function(d){var e=typeof d=="string",f=Array.prototype.slice.call(arguments,1);if(e&&d.substring(0,1)=="_")return this;if(e&&getter(c,a,d,f)){var h=$.data(this[0],a);return h?h[d].apply(h,f):undefined}return this.each(function(){var g=$.data(this,a);!g&&!e&&$.data(this,a,new $[c][a](this,d))._init();g&&e&&$.isFunction(g[d])&&g[d].apply(g,f)})};$[c]=$[c]||{};$[c][a]=function(d,e){var f=this;this.namespace=c;this.widgetName=a;this.widgetEventPrefix= $[c][a].eventPrefix||a;this.widgetBaseClass=c+"-"+a;this.options=$.extend({},$.widget.defaults,$[c][a].defaults,$.metadata&&$.metadata.get(d)[a],e);this.element=$(d).bind("setData."+a,function(h,g,i){if(h.target==d)return f._setData(g,i)}).bind("getData."+a,function(h,g){if(h.target==d)return f._getData(g)}).bind("remove",function(){return f.destroy()})};$[c][a].prototype=$.extend({},$.widget.prototype,b);$[c][a].getterSetter="option"}; $.widget.prototype={_init:function(){},destroy:function(){this.element.removeData(this.widgetName).removeClass(this.widgetBaseClass+"-disabled "+this.namespace+"-state-disabled").removeAttr("aria-disabled")},option:function(a,b){var c=a,d=this;if(typeof a=="string"){if(b===undefined)return this._getData(a);c={};c[a]=b}$.each(c,function(e,f){d._setData(e,f)})},_getData:function(a){return this.options[a]},_setData:function(a,b){this.options[a]=b;if(a=="disabled")this.element[b?"addClass":"removeClass"](this.widgetBaseClass+ "-disabled "+this.namespace+"-state-disabled").attr("aria-disabled",b)},enable:function(){this._setData("disabled",false)},disable:function(){this._setData("disabled",true)},_trigger:function(a,b,c){var d=this.options[a];a=a==this.widgetEventPrefix?a:this.widgetEventPrefix+a;b=$.Event(b);b.type=a;if(b.originalEvent){a=$.event.props.length;for(var e;a;){e=$.event.props[--a];b[e]=b.originalEvent[e]}}this.element.trigger(b,c);return!($.isFunction(d)&&d.call(this.element[0],b,c)===false||b.isDefaultPrevented())}}; $.widget.defaults={disabled:false};


// jquery.jsonp 1.1.3 (c)2010 Julian Aubourg | MIT License
// http://code.google.com/p/jquery-jsonp/
(function(d){var b=function(n){return n!==undefined&&n!==null},m=function(p,n,o){b(p)&&p.apply(n,o)},e=function(n){setTimeout(n,0)},f="",a="&",k="?",l="success",g="error",i=d("head"),h={},c={callback:"C",url:location.href},j=function(s){s=d.extend({},c,s);var r=s.beforeSend,A=0;s.abort=function(){A=1};if(b(r)&&(r(s,s)===false||A)){return s}var q=s.success,o=s.complete,v=s.error,C=s.dataFilter,G=s.callbackParameter,w=s.callback,D=s.cache,n=s.pageCache,t=s.url,I=s.data,x=s.timeout,z,H,F,E;t=b(t)?t:f;I=b(I)?((typeof I)=="string"?I:d.param(I)):f;b(G)&&(I+=(I==f?f:a)+escape(G)+"=?");!D&&!n&&(I+=(I==f?f:a)+"_"+(new Date()).getTime()+"=");z=t.split(k);if(I!=f){H=I.split(k);E=z.length-1;E&&(z[E]+=a+H.shift());z=z.concat(H)}F=z.length-2;F>0&&(z[F]+=w+z.pop());var p=z.join(k),B=function(J){b(C)&&(J=C.apply(s,[J]));m(q,s,[J,l]);m(o,s,[s,l])},y=function(J){m(v,s,[s,J]);m(o,s,[s,J])},u=h[p];if(n&&b(u)){e(function(){b(u.s)?B(u.s):y(g)});return s}e(function(){if(A){return}var J=d("<iframe style='display:none' />").appendTo(i),L=J[0],N=L.contentWindow||L.contentDocument,P=N.document,K,Q,R=function(S,T){n&&!b(T)&&(h[p]=f);K();y(b(T)?T:g)},M=function(T){N[T]=undefined;try{delete N[T]}catch(S){}},O=w=="E"?"X":"E";if(!b(P)){P=N;N=P.getParentNode()}P.open();N[w]=function(S){A=1;n&&(h[p]={s:S});e(function(){K();B(S)})};N[O]=function(S){(!S||S=="complete")&&!A++&&e(R)};s.abort=K=function(){clearTimeout(Q);P.open();M(O);M(w);P.write(f);P.close();J.remove()};P.write(['<html><head><script src="',p,'" onload="',O,'()" onreadystatechange="',O,'(this.readyState)"><\/script></head><body onload="',O,'()"></body></html>'].join(f));P.close();x>0&&(Q=setTimeout(function(){!A&&R(f,"timeout")},x))});return s};j.setup=function(n){d.extend(c,n)};d.jsonp=j})(jQuery);

if(!this.JSON){this.JSON={}}(function(){function f(n){return n<10?'0'+n:n}if(typeof Date.prototype.toJSON!=='function'){Date.prototype.toJSON=function(key){return isFinite(this.valueOf())?this.getUTCFullYear()+'-'+f(this.getUTCMonth()+1)+'-'+f(this.getUTCDate())+'T'+f(this.getUTCHours())+':'+f(this.getUTCMinutes())+':'+f(this.getUTCSeconds())+'Z':null};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf()}}var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==='string'?c:'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+string+'"'}function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==='object'&&typeof value.toJSON==='function'){value=value.toJSON(key)}if(typeof rep==='function'){value=rep.call(holder,key,value)}switch(typeof value){case'string':return quote(value);case'number':return isFinite(value)?String(value):'null';case'boolean':case'null':return String(value);case'object':if(!value){return'null'}gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==='[object Array]'){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||'null'}v=partial.length===0?'[]':gap?'[\n'+gap+partial.join(',\n'+gap)+'\n'+mind+']':'['+partial.join(',')+']';gap=mind;return v}if(rep&&typeof rep==='object'){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==='string'){v=str(k,value);if(v){partial.push(quote(k)+(gap?': ':':')+v)}}}}else{for(k in value){if(Object.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?': ':':')+v)}}}}v=partial.length===0?'{}':gap?'{\n'+gap+partial.join(',\n'+gap)+'\n'+mind+'}':'{'+partial.join(',')+'}';gap=mind;return v}}if(typeof JSON.stringify!=='function'){JSON.stringify=function(value,replacer,space){var i;gap='';indent='';if(typeof space==='number'){for(i=0;i<space;i+=1){indent+=' '}}else if(typeof space==='string'){indent=space}rep=replacer;if(replacer&&typeof replacer!=='function'&&(typeof replacer!=='object'||typeof replacer.length!=='number')){throw new Error('JSON.stringify');}return str('',{'':value})}}if(typeof JSON.parse!=='function'){JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==='object'){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v}else{delete value[k]}}}}return reviver.call(holder,key,value)}cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4)})}if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){j=eval('('+text+')');return typeof reviver==='function'?walk({'':j},''):j}throw new SyntaxError('JSON.parse');}}}());


(function(){
    var fgSDKSuggest  = {
        getId: function(){
            return this._getData('id');
        },
        setId: function(value){
            this._setData('id', value);
        },
        getRequestStack: function(){
            return this._getData('requestStack');
        },
        setRequestStack: function(value){
            this._setData('requestStack', value);
        },
        getResponse: function(){
            return this._getData('response');
        },
        setResponse: function(value){
            this._setData('response', value);
        },
        getLastRequestValue: function(){
            return this._getData('lastRequestValue');
        },
        setLastRequestValue: function(value){
            this._setData('lastRequestValue', value);
        },
        getWrapperObj: function(){
            return this._getData('wrapperObj');
        },
        setWrapperObj: function(value){
            this._setData('wrapperObj', value);
        },
        getLastKeyup: function(){
            return this._getData('lastKeyup'); 
        },
        setLastKeyup: function(value){
            this._setData('lastKeyup', value); 
        },
        getKeyupDelay: function(){
            return this._getData('keyupDelay'); 
        },
        setKeyupDelay: function(value){
            this._setData('keyupDelay', value); 
        },
        getDefaultPlace: function(){
            return this._getData('defaultPlace'); 
        },
        setDefaultPlace: function(value){
            this._setData('defaultPlace', value); 
        },
        getSelectedItem: function(){
            return this._getData('selectedItem');
        },
        setSelectedItem: function(value){
            this._setData('selectedItem', value);
            var json = {};
            for(var p in value){
                if(p !== 'element')
                    json[p] = value[p];
                
            }
            if(value == null){
                this.element.val('');
            }
            var jsonString = JSON.stringify(json);
            $('#hiddenInput'+this.getId()).val(jsonString); 
            var callback = this._getData('onSelectItem');
            if($.isFunction(callback))
                callback(value, jsonString);
        },
        getSelectedIndex: function(){
            return this._getData('selectedIndex');
        },
        setSelectedIndex: function(value){
            this._setData('selectedIndex', value); 
        },
        getParentForm: function(){
            return this._getData('parentForm');
        },
        setParentForm: function(value){
            this._setData('parentForm', value); 
        },
        getInputName: function(){
            return this._getData('inputName');
        },
        setInputName: function(value){
            this._setData('inputName', value); 
        },
        getInputValue: function(){
            return this.element.val();
        },
        setInputValue: function(value){
            this.element.val(value);
        },
        getLatLngValue: function(){
            if(this.getSelectedItem() != null)
                return this.getSelectedItem().Latitude.toString()+','+this.getSelectedItem().Longitude.toString();
            else
                return null;
        },
        getLevel: function () { 
            return this._getData('level'); 
        },
        setLevel: function (x) {
            var greenlevels = this._getData('greenlevels');
            var level = Math.floor(Math.min(greenlevels.length-1, Math.max(0,x)));
            this._setData('level', level);
            this.element.css({background: greenlevels[level]});
            this._trigger('change', 0, level);
        },
        getMicrotime: function(){
            var now = new Date().getTime() / 1000;
            return now;
        },
        getResultCount: function(){
            var data = this.getResponse();
            if(data !== null)
                return data.resultCount;
            else
                return 0;
        },
        _initSuggest: function(){
            var bounds = this.element.position();
            var obj = this.element;
            var wrapperOptions = this._getData('wrapper');
            var $hiddeninput = $('<input />').attr({type: 'hidden', name: '', id:'hiddenInput'+this.getId(), name: this.getInputName()}).appendTo(this.getParentForm());
            
            var $wrapper = $('<div />').attr({id: this.getId(), className: 'fgSDK-suggestwrapper'}).css({
                    left:bounds.left, 
                    top: (bounds.top+obj.height()+wrapperOptions.topMargin)
                }).appendTo('body');
            jQuery.data($wrapper[0], 'context', this);
            this.setWrapperObj($wrapper);
        },
        _initDefaultValues: function(){
            var values = this.getDefaultPlace();    
            if(values.Address === 'undefined')
                throw new Exception('Invalid Default values');
                
            this.setSelectedItem(values);
            this.element.val(values.Address);
            
        },
        _init: function() {
            this.setId('fgSDKSuggest'+Math.floor(Math.random()*1000000));                                   
            this.setRequestStack(0);
            this.setSelectedIndex(-1);
            
            this.setResponse(null);
            if(this.getParentForm() == null)
                throw new Exception('parentForm option must not be null');
            if(this.getInputName() == null)
                throw new Exception('inputName option must not be null');

            this._initSuggest();

                
            if(this.getDefaultPlace() !== null){
                this._initDefaultValues();
            }
            this.element.addClass('fgSDK-inputfield');
            
            this.element.blur(function(){
                $(this).fgSDKSuggest('onBlurInputField');
                $(this).removeClass('focus');
                if($(this).val() == ''){
                    $(this).fgSDKSuggest('setSelectedItem', null);
                }
            });
            this.element.focus(function(){
                $(this).fgSDKSuggest('onFocusInputField');
                $(this).addClass('focus');
            });
            this.element.click(function(){
                this.select(); 
            });
            this.element.keydown(function(event){
                
                    var keyCode = $.ui.keyCode;
                    switch( event.keyCode ) {
                        case keyCode.PAGE_UP:
                            //self._move( "previousPage", event );
                            break;
                        case keyCode.PAGE_DOWN:
                            //self._move( "nextPage", event );
                            break;
                        case keyCode.UP:
                        case keyCode.DOWN:
                            var hasResult = $(this).fgSDKSuggest('hasResult');
                            if(hasResult){
                                $(this).fgSDKSuggest('handleArrowKeys', event.keyCode);
                                event.preventDefault();
                            }
                        break;
/*                        case keyCode.LEFT:
                        case keyCode.RIGHT:
                            event.preventDefault();
                            break;*/
                        case keyCode.ENTER:
                            $(this).fgSDKSuggest('hideWrapper', event.keyCode);
                            $(this).fgSDKSuggest('handleEnter');
                            event.preventDefault();
                        break;
                        case keyCode.TAB:
                            $(this).fgSDKSuggest('handleEnter'); 
                            break;
                        case keyCode.ESCAPE:
                            $(this).fgSDKSuggest('hideWrapper', event.keyCode);
                            event.preventDefault();
                            break;
                        case 16:
                        case 17:
                        case 18:
                        case 36:
                        case 35:
                            break;
                        default:
                            $(this).fgSDKSuggest('hideWrapper');
                            $(this).fgSDKSuggest('handleKeyup', event);
                            break;
                    }
                }
            );
        },
        hasResult: function(){
            var data = this.getResponse();
            return data !== null && data.resultCount > 0;    
        },
        off: function() {
            this.element.css({background: 'none'});
            this._trigger('done');
            this.destroy(); // use the predefined function
        },
        handleKeyup: function(o){
            var keytime = this.getMicrotime();
            this.setLastKeyup(keytime);
            setTimeout("jQuery.data($('#"+this.getId()+"')[0], 'context').element.fgSDKSuggest('onKeyupCallback', "+keytime+");", this.getKeyupDelay());
        },
        handleEnter: function(o){
            if(this.getResultCount() == 1){
                this.setSelectedIndex(0);
                this.markSelectedItem();
            }
        },
        showWrapper: function(){
            this.getWrapperObj().show();
        },
        hideWrapper: function(){
            this.getWrapperObj().hide();
        },
        parseResponse: function(){
            var data = this.getResponse();
            this.setLastRequestValue(data.requestValue);
            data.resultCount = parseInt(data.resultCount);
        },
        populateResponse: function(){
            var wrapper = this.getWrapperObj();
            var data = this.getResponse();
            this.hideWrapper();
            if(data.resultCount > 0){
                var $list = $('<ul />').addClass('fgSDK-suggestlist');
                for(n=0;n<data.geoResults.length;n++){
                    var $item = $('<li />').addClass('fgSDK-suggestitem').html(data.geoResults[n].Address).appendTo($list);
                    $item.mouseover(this.onItemMouseOver);
                    $item.mouseout(this.onItemMouseOut);
                    
                    jQuery.data($item[0], 'rawResult', data.geoResults[n]);
                    jQuery.data($item[0], 'indexPosition', n);
                    jQuery.data($item[0], 'wrapperContextID', this.getId());
                    data.geoResults[n].element = $item;
                }
                wrapper.html($list);
                this.showWrapper();
            }
            else{
                this.hideWrapper();
            }
        },
        clearSelection: function(){
            var data = this.getResponse();
            for(n=0;n<data.geoResults.length;n++)
                data.geoResults[n].element.removeClass('selected');
        },
        onKeyupCallback: function(time){
            if(time == this.getLastKeyup()){
                this.doRequest();           
            }   
        },
        onItemMouseOver: function(){
            var wrapperID = jQuery.data(this, 'wrapperContextID');
            var context = jQuery.data($('#'+wrapperID)[0], 'context');
            var index = jQuery.data(this, 'indexPosition');
            
            context.element.fgSDKSuggest('setSelectedIndex', index);
            context.element.fgSDKSuggest('markSelectedItem');      
        },
        onItemMouseOut: function(){
            $(this).removeClass('selected');
        },
        onSelectItem: function(item){
                
        },
        onRequestCompleted: function(data, stackNumber){
            this.setSelectedIndex(-1);
            if(this.getRequestStack() > stackNumber){
            //ignore
            }
            else{
                this.setResponse(data);
                this.parseResponse();
                this.populateResponse();
                $(this.element).removeClass('progress');
                $(this.element).focus();
            }
        },
        onBeforeRequest: function(options){
            var requestStack = this.getRequestStack();
            this.setRequestStack(requestStack+1);
            $(this.element).removeClass('focus');
            $(this.element).addClass('progress');
        },
        onFocusInputField: function(){
            var bounds = this.element.position();
            var obj = this.element;            
            
             var wrapperOptions = this._getData('wrapper'); 
            var wrapper = this.getWrapperObj();            
            wrapper.css({
                    left:bounds.left, 
                    top: (bounds.top+obj.height()+wrapperOptions.topMargin)});
        },
        onBlurInputField: function(){
            this.hideWrapper();
        },
        handleArrowKeys: function(key){
            var keyCode = $.ui.keyCode;
            var currentIndex = this.getSelectedIndex();
            var maxIndex = this.getResultCount()-1;
            switch(key){
                case keyCode.UP:
                    if(currentIndex <= 0)
                        this.setSelectedIndex(maxIndex);
                    else
                        this.setSelectedIndex(currentIndex-1);
                                                         
                break;
                case keyCode.DOWN:
                    if(currentIndex == maxIndex)
                        this.setSelectedIndex(0);
                    else    
                        this.setSelectedIndex(currentIndex+1);
                break;
            }
            this.markSelectedItem();
        },
        markSelectedItem: function(){
            this.clearSelection();
            var currentIndex = this.getSelectedIndex();
            var data = this.getResponse();
            data.geoResults[currentIndex].element.addClass('selected');
            data.geoResults[currentIndex].element.addClass('selected');
            this.setSelectedItem(data.geoResults[currentIndex]);
            this.element.val(this.getSelectedItem().Address);
        },
        doRequest: function(){
            var requestStack = this.getRequestStack();
            var request = this._getData('request');
            var defData = request.data;
            var newData = {target: this.element.val()};
            
            if(this.element.val().length <= this._getData('minLength'))
                return;
            
            var data = $.extend(defData, newData);
            
           /* $.ajax({
                url: request.URL,
                dataType: 'jsonp',
                data: data,
                context: this,
                stackNumber: requestStack+1,
                success: function(data) {
                    //console.log(this);
                    this.element.fgSDKSuggest('onRequestCompleted', data, this.stackNumber);
                }          
            }); */
            $.jsonp({
                url: request.URL,
                data: data,
                context: this,
                stackNumber: requestStack+1,
                success: function(data, textStatus) {
                    this.context.element.fgSDKSuggest('onRequestCompleted', data, this.stackNumber);
                },
                complete: function(options, textStatus){
                    
                },
                beforeSend: function(options){
                    options.context.element.fgSDKSuggest('onBeforeRequest', options);
                },
                error: function(d,msg) {
                    alert("Could not find user "+userId); 
                }            
            });              
            
            
        }
    };

    $.widget("ui.fgSDKSuggest", fgSDKSuggest);
    $.ui.fgSDKSuggest.getter = ['hasResult', 'getSelectedItem', 'getLatLngValue'];
    $.ui.fgSDKSuggest.defaults = {
        minLength : 2,
        keyupDelay: 400,
        parentForm: null,
        inputName: null,
        request: {
            URL: 'http://service.fahrgemeinschaft.de/suggest',
            data: {
                output: 'jsonp'
            }
        },
        wrapper: {
            topMargin: 2
        },
        defaultPlace: null,
        onSelectItem: null
    };

})();



