function formToJSON(form, options) {
	elements = $(form).getElements();
	if (typeof options != 'object') options = { hash: !!options };
	else if (Object.isUndefined(options.hash)) options.hash = true;
	var key, value, submitted = false, submit = options.submit;

	var data = elements.inject({ }, function(result, element) {
		if (!element.disabled && element.name) {
			key = element.id;
			value = $(element).getValue();
			if (value != null && (element.type != 'submit' || (!submitted &&
			submit !== false && (!submit || key == submit) && (submitted = true)))) {

				key = ( !Object.isUndefined(options.prefix) ) ? key.replace(options.prefix,"") : key;

				if( Object.isArray(options.exclude) )
				if( options.exclude.indexOf(key) != -1 )
				return result;

				if( key.indexOf(".") != -1 ) {
					var processkey = key;
					var tree = "";
					while( processkey.indexOf(".") != -1 ) {
						var newkey = processkey.substring( 0,processkey.indexOf(".") );
						processkey = processkey.replace( newkey + ".", "" );

						tree += (tree == "") ? newkey : "." + newkey;

						if( eval("result." + tree) == undefined || eval("result." + tree) == null )
						eval("result." + tree + " = new Object()") ;

						if( processkey.indexOf(".") == -1 )
						if( processkey in eval( "result." + tree ) ) {
							if ( !Object.isArray( eval( "result." + tree + "." + processkey ) ) )
							eval("result." + tree + "." + processkey + " = [ result." + tree + "." + processkey + "]");

							eval("result." + tree + "." + processkey + ".push(value)");
						} else
						eval("result." + tree + "." + processkey + " =  value");
					}
				} else
				if (key in result) {
					if ( !Object.isArray( result[key] ) )
					result[key] = [ result[key] ];

					result[key].push(value);
				} else
				result[key] = value;
			}
		}

		return result;
	});
	return options.hash ? data : Object.toQueryString(data);
};


var ProFiller = (function(){
	
	var ProFiller = Class.create();
	
	ProFiller.Version = "2.2.4";
	
	ProFiller.options = {
		reset: true
	};	
	
	ProFiller.prototype = {
		initialize: function(form, options){
			this.options = {};
			Object.extend(this.options, ProFiller.options);
			Object.extend(this.options, options || {});
			
			this.form = $(form);
			this.elements = this.form.getElements();
		},
		
		fill: function(data){
			
			var value, name, type;

			if(this.options.reset) this.form.reset();
			
			this.elements.each(function(elem){
				name = elem.readAttribute('name');
				value = this._getValue(name, data);
				type = elem.readAttribute('type');
				if(Object.isArray(value)){
					for(var i=0;i<value.length;i++){
						this._setValue(elem, type, value[i]);
					}
				} else this._setValue(elem, type, value);
			}.bind(this));
			
			this.form.watch();
			
			return this.form;
		},
		
		_getValue: function(name, hash){
			var data = $H(hash);
			var names = Object.isArray(name) ? name : name.match(/([\w-:\.]+)/g);
			var value = data.get(names[0]);
			if(names.length>1){
				names.shift();
				return this._getValue(names, value);
			}
			return value;
		},
		
		_setValue: function(elem, type, value){
			var elemValue = elem.readAttribute('value');
			switch(type){
				case 'radio':
					(elemValue == value) ? elem.setValue(value) : false;
				break;
				
				case 'checkbox':
					(elemValue == value) ? elem.setValue(value) : false;
				break;
				
				default:
					if(value) elem.setValue(value);
				break;
			}
		}
	};
	
	Element.addMethods('FORM', {
		fill: function(form, data ,resetBeforeFill){
			var reset = Object.isUndefined(resetBeforeFill) ? true : resetBeforeFill;
			return new ProFiller(form,{reset: reset}).fill(data);
		},
		watch: function(form){
			var form = $(form);
			form.store('profiller', {
				'form': form.serialize()
			});
			return form;
		},		
		changed: function(form){
			var form = $(form);
			var storage = form.retrieve('profiller', {'form': form.serialize()});
			return storage.form !== form.serialize();
		}
	});
	
	return ProFiller;
})();

function FormFiller(form) { return new ProFiller(form); }
function Filler(form){ return new ProFiller(form); }
