(function($) {

	$.fn.multistep = function(backEndURL, options)
	{
	  var settings = $.extend({language: ""
	    , nextStep: function() { return false; }
	    , beforeLoad: function(destElement) { }
	    , afterLoad: function(destElement) { }
	  }, options);
	  
	  var that = this;
	  var $form = null;
	  var $inputs = this;
	  
	  var i = 0;
	  $inputs
	    .change(function() { inputChanged(this); })
	    .each(function() {
	      //if (this.options.length > 0)
	      if (i > 0 && (this.options.length == 0 || this.options.selectedIndex < 0 || (this.options.length > 0 && this.options[this.options.selectedIndex].value == "")))
	      {
	        this.disabled = true;
	      }
	      i++;
	    });
	    
	  
	  /**
	  * This function is the core of multistep. Called on input change. Does the
	  * following:
	  *
	  *   1. Gets the next set of arguments to make an ajax call with via a callback.
	  *   2. Disables inputs past the current input that's loading.
	  *   3. Makes the ajax call.
	  *   4. loads the results into the destination select box.
	  *   5. Runs a callback after the destination select is loaded.
	  */
	  function inputChanged(sourceElement)
	  {
	    var params = settings.nextStep(sourceElement);
	    if (!params)
	      return;
	    
	    // Find destination element.
	    destElement = null;
	    var destElements = $inputs.filter("[name='" + params.destName + "']");
	    if (destElements.length == 0)
	      throw new Error("multistep: could not find dest element '" + params.destName + "'");
	    else
	      var destElement = destElements[0];
	    
	    // Disable and reset inputs past the destination input.
	    var destIndex = 0;
	    for (destIndex = 0; destIndex < $inputs.length; destIndex++) {
	      if (destElement && destElement.id == $inputs[destIndex].id)
	        break;
	    }
	    
	    for (var i = destIndex; i < $inputs.length; i++){
	      disableInput($inputs[i]);
	    }
	
	    // Ignore invalid selections
	    if (sourceElement.value == "") {
	      return;
	    }
	    
	    settings.beforeLoad(destElement);
	    
	    if (params.data.action) {
	      if (settings.language != "")
	        params.data.ln = settings.language;
	      
	      $.get(backEndURL, params.data, function(results) {
	        $(destElement).empty();
	        for (var i = 0; i < results.length; i++) {
	          destElement.options[i] = new Option(results[i].name, results[i].id);
	        }
	        destElement.disabled = false;
	        settings.afterLoad(destElement);
	      }, "json");
	    } else {
	      $(destElement).empty();
	      destElement.disabled = false;
	      settings.afterLoad(destElement);
	    }
	  }
	  
	  function disableInput(input)
	  {
	    input.disabled = true;
	    if (input.tagName.toLowerCase() == "select" && input.length > 0)
	      input.selectedIndex = 0;
	  }
	}
	
})(jQuery);
