// let's declare what we provide: a widget called Live Filter
dojo.provide("dojo.widget.LiveFilter")
dojo.provide("dojo.widget.HtmlLiveFilter")

// let's declare what we need: widget infrastructure and basic I/O facilities
dojo.require("dojo.widget.Widget");
dojo.require("dojo.io");

// the widget
dojo.widget.HtmlLiveFilter = function() {
    dojo.widget.HtmlWidget.call(this);
	this.widgetType = "LiveFilter";
	
	/* Parameters */
	
	// delay in ms after changes (we wait for more changes in this timeframe)
	this.delay    = 300;
	
	// id of an element we will use for results
	this.results  = "results";
	
	/* Internal state */
	
	// a form we are going to monitor and submit
	this.formNode = null;
	
	// timer id, when we wait for "delay"
	this.timer    = -1;
	
	// are we accessing a server at this moment?
	this.inflight = false;
	
	// were any changes made while we were accessing a server?
	this.resubmit = false;
	
	// process changes to form's controls
	this.onchange = function() {
		if(!this.inflight) {
			// we are free to access a server
			// let's clear any pending timers
			if(this.timer != -1) clearTimeout(this.timer);
			// set new timer, if this timer is uninterrupted, it will submit the form
			var _this = this;
			this.timer = setTimeout(function() { _this.submit(); }, this.delay);
		} else {
			// we are accessing a server at the moment => mark that changes were made
			this.resubmit = true;
		}
	}
	
	// submit the form
	this.submit = function() {
		// reset all internal variables
		this.timer    = -1;
		this.inflight = true;
		this.resubmit = false;
		// now we can call a server
		var _this = this;
		dojo.io.bind({
			url:		this.formNode.action,	// action is taken from the form
			method:		this.formNode.method,	// method is taken from the form
			formNode:	this.formNode,			// submit this form
			content:	{format: 'ahah'},		// tell it that we want AHAH
			load:		function(type, data)	{ _this.onload(data); },
			error:		function(type, error)	{ _this.onerror(type, error); }
		});
	}
	
	// we got results successfully
	this.onload = function(data) {
		// just assign results -- it's AHAH after all
		dojo.byId(this.results).innerHTML = data;
		// we are ready to call a server again
		this.inflight = false;
		if(this.resubmit) {
			// if the form was modified, while we waited for results => resubmit it
			this.resubmit = false;
			this.onchange();
		}
	}
	
	// we got some errors => show alert and reset variables
	this.onerror = function(type, error) {
		alert(String(type) + "\n" + String(error));
		this.inflight = false;
		this.resubmit = false;
	}
	
	// now let's process a form and grab some events
	this.buildRendering = function(args, frag) {
	
		// retrieve a form node
		this.formNode = frag["dojo:livefilter"]["nodeRef"];
		// sanity check
		if(this.formNode.tagName.toLowerCase() != "form"){
			dojo.raise("Attempted to use a non-form element.");
		}

		// watch controls for change to do live update		
		for(var i = 0; i < this.formNode.elements.length; i++){
			var elm = this.formNode.elements[i];
			
			// ignore disabled controls
			if(elm.disabled) continue;
			
			// process select controls
			if(elm.tagName.toLowerCase() == "select") {
				dojo.event.connect(elm, "onchange", this, "onchange");
				continue;
			}
			
			// process input controls
			if(elm.tagName.toLowerCase() == "input") {
				switch(elm.type.toLowerCase()) {
					case "text": case "password":
						// watch for "key up" event
						dojo.event.connect(elm, "onkeyup", this, "onchange");
						break;
					case "checkbox": case "radio":
						// watch for changes
						dojo.event.connect(elm, "onchange", this, "onchange");
						break;
					case "reset":
						// watch for resets
						dojo.event.connect(elm, "onclick", this, "onchange");
						break;
				}
			}
		}
	}
}

// let's inherit the rest from generic HTML widget
dojo.inherits(dojo.widget.HtmlLiveFilter, dojo.widget.HtmlWidget);

// register our widget
dojo.widget.tags.addParseTreeHandler("dojo:livefilter");

