Form = function(frm)
{
	if(is(frm))
	{
		if(!is(frm.tagName,'string') || frm.tagName.toUpperCase() !='FORM')
			return Error.IllegalArgument(new Error(), 'HTML Form Element' , frm);
	}
	else
		return new Form(new Elm.form());
	
	XO.x(frm,{
		serialize:function()
		{
			var data=[];
			this.namedItems().each(function(k,frm)
			{
				if(is(frm[this].serialize,'function'))
					data.push(frm[this].serialize());
			},this);
			
			return data.filterFalse().join('&');
		},
		ajax:function(){},
		json:function(){},
		namedItems:function()
		{
			var names=[];
			XUtil.toArray(frm.elements).each(function()
			{
				if(!names.has(this.name))
					names.push(this.name);
			});
			return names;
		}
	});
	
	frm.namedItems().each(function(k)
	{
		if(!is(frm[this].serialize,'function'))
		{
			switch(frm[this].type)
			{
				case 'text':
				case 'textarea':
					Form.FormInputText(frm[this]);
					break;
				case 'select':
				case 'select-one':
					Form.FormSelect(frm[this]);
					break;
				case 'checkbox':
					Form.FormCheckbox(frm[this]);
					break;
				case 'hidden':
					Form.FormInput(frm[this]);
					break;
				case undefined:
					if(is(frm[this][0]) && is(frm[this][0].type) && frm[this][0].type.toUpperCase() == 'RADIO')
						Form.FormRadio(frm[this]);
					break;
			}
		}
	});
	
	return frm;
};

Form.FormInput = function(inp)
{
	XO.x(inp,{
		serialize:function()
		{ 
			if(is(this.name))
			{
				return this.name+'='+encodeURIComponent(this.val());
				//ref: http://xkr.us/articles/javascript/encode-compare/
			}
		},
		
		val:function()
		{ 
			return '_VALUE_'; 
		}
	});
	
	Elm.api(inp);
	
	return inp;
};

Form.FormInput_SingularText = function(inp)
{
	Form.FormInput(inp);
	XO.x(inp,
	{
		//ref: http://blog.vishalon.net/Post/57.aspx
		getCaret:function()
		{
			var caret = 0;
			if (document.selection) //ie
			{
				this.focus ();
				var sel = document.selection.createRange();
				sel.moveStart ('character', -this.value.length);
				caret = sel.text.length;
			}
			else if (this.selectionStart || this.selectionStart == '0') //ff
				caret = this.selectionStart;
		
			return (caret);
		},
		setCaret:function(at)
		{
			if(this.setSelectionRange)
			{
				this.focus();
				this.setSelectionRange(at,at);
			}
			else if (ctrl.createTextRange) 
			{
				var range = this.createTextRange();
				range.collapse(true);
				range.moveEnd('character', at);
				range.moveStart('character', at);
				range.select();
			}
		},
		insert:function(open,end)
		{
			var isIE = (document.all)? true : false;
			var open = (open)? open : "";
			var end = (end)? end : "";
			
			if (isIE)
			{
				this.focus();
				var curSelect = document.selection.createRange();
				curSelect.text = open + curSelect.text + end;
			}
			else if (!isIE && typeof this.selectionStart != "undefined")
			{
				var selStart = this.value.substr(0, this.selectionStart);
				var selEnd = this.value.substr(this.selectionEnd, this.value.length);
				var curSelection = this.value.replace(selStart, '').replace(selEnd, '');
				this.value = selStart + open + curSelection + end + selEnd;
			}
			else
			{
				this.value += open + end;
			}
		}
	});
	return inp;
};


Form.FormInputText = function(inp)
{
	Form.FormInput_SingularText(inp);
	XO.x(inp,
	{
		val:function(set)
		{
			if(!is(set))
				return this.value;
			else
			{
				this.value=set;
				return set;
			}
		}
	});
	return inp;
}

Form.FormSelect = function(inp)
{
	Form.FormInput(inp);
	XO.x(inp,{
		getLabel:function(v)
		{
			if(!is(v) && v!=0) v = this.val();
			for(var i =0;i<this.options.length;i++)
				if(this.options[i].value==v)
					return this.options[i].text;
			return false;
		},
		val:function(set)
		{
			if(!is(set))
			{
				return this.options[this.selectedIndex].value;
			}
			
			
			XUtil.toArray(this.options).each(function(i)
			{
				if(this.value == set)
				{
					this.parentNode.selectedIndex = i;
				}
			});
			
			return this.val();
		}
	});
	return inp;
};

Form.FormRadio = function(inp)
{
	Form.FormInput(inp);
	XO.x(inp,
	{
		name:(function(elm){ return elm[0].name;})(inp),
		val:function(set)
		{
			var options = XUtil.toArray(this);
			for(var i=0;i<options.length;i++)
			{
				if(!is(set))
				{
					if(options[i].checked == true)
						return options[i].value;
				}
				else
				{
					if(options[i].value == set)
					{
						options[i].checked=true;
						return set;
					}
				}
			}
			return '';
		}
	});
	return inp;
};


Form.FormCheckbox = function(inp)
{
	Form.FormInput(inp);
	XO.x(inp,
	{
		val:function(set)
		{
			if(!is(set,'undefined'))
			{
				this.checked = !!set;
				return this.checked;
			}
			else
					return this.checked ? 'on' : '';
		}
	});
	return inp;
};
