;(function($){
	$.fn.serialform = function(options){
		var settings = $.extend({}, $.fn.serialform.defaults, options);
		var fxIn = settings.fxIn;
		var fxOut = settings.fxOut;
		var callback = settings.callback;
		var accepted = $.map(this, function(elem){ return elem.name;	});
		var cache = {};
		var root = this;
		settings.fxIn = settings.fxInLoad;
		settings.fxOut = settings.fxOutLoad;
		settings.callback = false;
		
		//fix ie bug ("change" event won't fire if focus is on the element)
		if ($.browser.msie) document.body.focus();
		
		$.extend(this, {
			init: function(){
				$("input, select").live("change", function(){
					if($.inArray(this.name, accepted) == -1) return;
					
					root.handle.call(this);

					if(settings.callback) settings.callback();
				});
				
				this.trigger('change');
				
				//restore value
				settings.fxIn = fxIn;
				settings.fxOut = fxOut;
				settings.callback = callback;
				if(settings.callback) settings.callback();
			},
			
			handle: function(){
				var isInput = this.tagName == "INPUT";
				var target = root.handleTarget(this);
				var action = isInput ? this.checked : true;
				
				if((this.type == "radio" || this.type == "select-one") && action){
					var current = root.current(this);
					if(current)	root.display(current, false);
					
					root.current(this, target);
				}
				
				if(target) root.display(target, action);
			},
			
			display: function(elem, action){
				if($.inArray(elem, cache) == -1) cache[elem] = $(elem);

				var $elem = cache[elem];
				if(!$elem.length) return;
				
				$elem[action ? settings.fxIn : settings.fxOut]();
			},
			
			current: function(elem, target){
				var storage = elem.form || document.body;
				return $.data(storage, elem.name, target ? target : undefined);
			},
			
			handleTarget: function(elem){
				var elem = elem.tagName == "SELECT" ? $(":selected", elem)[0] : elem;
				return settings.getTarget(elem) || false;
			}
		});

		this.init();
		return this;
	};

	$.fn.serialform.defaults = {
		fxIn: "fadeIn",
		fxOut: "hide",
		fxInLoad: "show",
		fxOutLoad: "hide",
		context: false,
		callback: function(){},
		getTarget: function(elem){
			// return elem.getAttribute('data');
			return elem.getAttribute('title');
		}
	};
})(jQuery);
