/**
 *
 */

function createDelegate(scope, func) {
	f=function() {
		scope[func]();
	};

	return f;
}

/**
 *
 *  Provides dummy suggestions for testing.
 *
 */

function DummySuggestions(query, callbackObj, callbackMember) {

	/**
	 *
	 */

	this.onTimer=function() {
		if (!this.aborted) {
			trace("delivering");

			var r=['the','suggestions','for',this.query];
			this.callbackObj[callbackMember](r);
		}

		else {
			trace("done but aborted");
		}
	}

	/**
	 *
	 */

	this.abort=function() {
		trace("aborting..");
		this.aborted=true;
	}

	/**
	 *  Construct
	 */

	this.query=query;
	this.dummyVar="dum";
	this.aborted=false;
	this.callbackObj=callbackObj;
	this.callbackMember=callbackMember;
	setTimeout(createDelegate(this,"onTimer"),3000);
	trace("creating suggestions..");
}

/**
 *
 *  Suggestions from google maps.
 *
 */

function GoogleGeoSuggestions(query, callbackObj, callbackMember) {

	/**
	 *
	 */

	this.onSuggestionsLoaded=function(result) {
		if (this.aborted)
			return;

		var r=[];

		if (!result || result.Status.code != 200) {
			trace("not found");
		} 
		
		else {
			var i;

			for (i=0; i<result.Placemark.length; i++) {
				var place=result.Placemark[i];

				var replaced=place.address;
				
				replaced=replaced.replace(", Sweden","");
				replaced=replaced.replace("Sweden","");
				replaced=replaced.replace(", Sverige","");
				replaced=replaced.replace("Sverige","");

				trace("place: "+place.address+" - "+replaced);

				if (replaced.length>0)
					r.push(replaced);
			}
		}

		trace("suggestions loaded...");

		this.callbackObj[callbackMember](r);
	}

//  '<b>Country code:</b> ' + place.AddressDetails.Country.CountryNameCode);

	/**
	 *
	 */

	this.abort=function() {
		trace("aborting..");
		this.aborted=true;
	}

	/**
	 *  Construct.
	 */

	trace("starting..");

	var scope=this;

	this.callbackObj=callbackObj;
	this.callbackMember=callbackMember;
	this.aborted=false;

	this.geocoder=new GClientGeocoder();
	this.geocoder.setBaseCountryCode("se");
	this.geocoder.getLocations(query+", Sweden",
		function(result) {
			scope.onSuggestionsLoaded(result);
		});
}

/**
 *
 *  Drop down suggestor.
 *
 */

function Suggestor(textInputId, selectInputId, suggestorClass) {

	/**
	 *
	 */

	this.setOnChange=function(obj, member) {
		this.callbackObj=obj;
		this.callbackMember=member;
	}

	/**
	 *
	 */

	this.onChange=function() {
		var v=this.getValue();

		if (v!=this.lastReported)
			if (this.callbackObj!=null && this.callbackMember!=null)
				this.callbackObj[this.callbackMember]();

		this.lastReported=v;
	}

	/**
	 *
	 */

	this.onAnimationInterval=function() {
		if (this.currentRequest==null)
			return;

		this.animationDots++;

		if (this.animationDots>3)
			this.animationDots=0;

		var s="",i;

		for (i=0; i<this.animationDots; i++)
			s+=".";

		this.selectInput.options[0]=
			new Option(s,null);
	}

	/**
	 *
	 */

	this.suggestionsLoaded=function(result) {
		var e;

		this.currentRequest=null;
		clearInterval(this.animationInterval);
		this.animationInterval=null;

		var l=this.selectInput.length;
		var i;

		for (i=0; i<l; i++)
			this.selectInput.remove(0);

		for (e=0; e<result.length; e++) {
			this.selectInput.options[this.selectInput.options.length]=
				new Option(result[e],result[e]);
		}

		this.onChange();
	}

	/**
	 *
	 */
	this.schedLoad=function() {
		trace("schedeuling load");

		if (this.currentSchedTimeout!=null) {
			trace("removeing old sched load");
			clearTimeout(this.currentSchedTimeout);
			this.currentSchedTimeout=null;
		}

		this.abortLoading();
		this.clearSuggestionList();

		this.selectInput.options[0]=
			new Option("-",null);

		this.currentSchedTimeout=setTimeout(createDelegate(this,"loadSuggestions"),500);
	}

	/**
	 *
	 */
	this.abortLoading=function() {
		if (this.currentRequest!=null) {
			this.currentRequest.abort();
			this.currentRequest=null;

			clearInterval(this.animationInterval);
			this.animationInterval=null;
		}
	}

	/**
	 *
	 */
	this.clearSuggestionList=function() {
		var l=this.selectInput.length;
		var i;

		for (i=0; i<l; i++)
			this.selectInput.remove(0);
	}

	/**
	 *
	 */

	this.loadSuggestions=function() {
		trace("loading, current="+this.currentRequest);

		this.abortLoading();
		this.clearSuggestionList();

		if (this.textInput.value.length>0) {
			this.animationInterval=setInterval(
				createDelegate(this,"onAnimationInterval"),100);

			this.onAnimationInterval();

			this.currentRequest=new this.suggestorClass(
				this.textInput.value,this,"suggestionsLoaded");
		}
	}

	/**
	 *
	 */

	this.setValue=function(v) {
		this.textInput.value=v;
	}

	/**
	 *
	 */

	this.getValue=function() {
		if (this.selectInput.length>0 && 
				this.textInput.value.length>0 &&
				this.selectInput.selectedIndex>=0) {
			return this.selectInput.options
				[this.selectInput.selectedIndex].value;
		}

		else
			return this.textInput.value;
	}

	/**
	 *
	 */

	this.updateVisibility=function() {
		if ((this.textFocus || this.selectFocus || this.selectMouseDown) 
				&& this.textInput.value.length>0) {
			this.selectInput.style.display="inline";
		}

		else {
			this.selectInput.style.display="none";
		}
	}

	/**
	 *
	 */

	this.setTextFromSelected=function() {
		trace("set from sel, last typed: "+this.lastTyped);

		if (this.selectInput.selectedIndex>=0)
			this.textInput.value=this.selectInput.
				options[this.selectInput.selectedIndex].value;

		else
			this.textInput.value=this.lastTyped;
	}

	/**
	 *
	 */

	this.textOnFocus=function() {
		this.textFocus=true;
		this.updateVisibility();
	}

	/**
	 *
	 */

	this.textOnBlur=function() {
		this.textFocus=false;

		this.updateVisibility();
		this.onChange();
	}

	/**
	 *
	 */

	this.textOnKeyDown=function(e) {
		var retval=true;

		if (window.event!=undefined)
			e=window.event;

		this.reloadOnKeyUp=false;

		if (e.keyCode==40) /* DOWN */ {
			if (this.currentRequest!=null)
				return false;

			if ((this.selectInput.selectedIndex<this.selectInput.length-1) &&
					(this.selectInput.length>0))
				this.selectInput.selectedIndex++;

			this.setTextFromSelected();
			this.onChange();
			retval=false;
		}

		else if (e.keyCode==38) /* UP */ {
			if (this.currentRequest!=null)
				return false;

			if (this.selectInput.selectedIndex>=0)
				this.selectInput.selectedIndex--;

			this.setTextFromSelected();
			this.onChange();
			retval=false;
		}

		else if (e.keyCode==37 || e.keyCode==39) {
		}

		else {
			this.reloadOnKeyUp=true;
		}

		this.updateVisibility();

		return retval;
	}

	/**
	 *
	 */

	this.textOnChange=function() {
		this.updateVisibility();
		this.onChange();
	}

	/**
	 *
	 */

	this.textOnKeyUp=function() {
		if (this.selectInput.selectedIndex<0)
			this.lastTyped=this.textInput.value;

		this.updateVisibility();

		if (this.reloadOnKeyUp) {
			this.onChange();
			this.schedLoad();
		}
	}

	/**
	 *
	 */

	this.selectOnFocus=function() {
		this.selectFocus=true;
		this.updateVisibility();
	}

	/**
	 *
	 */

	this.selectOnBlur=function() {
		this.selectFocus=false;
		this.updateVisibility();
	}

	/**
	 *
	 */

	this.selectOnMouseDown=function() {
		this.selectMouseDown=true;
		this.updateVisibility();
	}

	/**
	 *
	 */

	this.selectOnMouseUp=function() {
		this.selectMouseDown=false;
		this.updateVisibility();
	}

	/**
	 *
	 */

	this.selectOnChange=function() {
		if (this.selectInput.selectedIndex<0 || this.currentRequest!=null)
			return;

		this.selectInput.selectedIndex=
			this.selectInput.selectedIndex;

		this.setTextFromSelected();

		if (this.selectFocus)
			this.selectInput.blur();

		this.onChange();
	}

	/**
	 *
	 */

	this.selectOnClick=function() {
		if (this.selectFocus)
			this.selectInput.blur();
	}

	/**
	 *  Construct.
	 */

	this.textFocus=false;
	this.selectFocus=false;
	this.selectMouseDown=false;

	this.textInput=document.getElementById(textInputId);
	this.textInput.obj=this;
	this.textInput.onfocus=function() {this.obj.textOnFocus()};
	this.textInput.onblur=function() {this.obj.textOnBlur()};
	this.textInput.onkeydown=function(e) {return this.obj.textOnKeyDown(e)};
	this.textInput.onkeyup=function() {this.obj.textOnKeyUp()};
	this.textInput.onchange=function() {this.obj.textOnChange()};

	this.selectInput=document.getElementById(selectInputId);
	this.selectInput.obj=this;
	this.selectInput.onfocus=function() {this.obj.selectOnFocus()};
	this.selectInput.onblur=function() {this.obj.selectOnBlur()};
	this.selectInput.onmousedown=function() {this.obj.selectOnMouseDown()};
	this.selectInput.onmouseup=function() {this.obj.selectOnMouseUp()};
	this.selectInput.onchange=function() {this.obj.selectOnChange()};
	this.selectInput.onclick=function() {this.obj.selectOnClick()};

	this.textInput.disabled=false;
	this.onChange=function() {};
	this.reloadOnKeyUp=false;
	this.callbackObj=null;
	this.callbackMember=null;
	this.lastReported="";
	this.lastTyped=this.textInput.value;
	this.suggestorClass=suggestorClass;
	this.currentRequest=null;
	this.animationInterval=null;
	this.animationDots=0;
	this.currentSchedTimeout=null;

	this.updateVisibility();
	this.loadSuggestions();
}
