self.Form = function(form)
{
	var _form = form;
	
	var specialChars = function(str)
	{
		var chars;
		
		chars = []; // array de símbolos especiais
		chars.push({symbol: "+", code: "%2B"});
		
		for (var i = 0; i < chars.length; i++)
		{
			str = str.split(chars[i].symbol).join(chars[i].code);
		}
	
		return str;
	};
	
	/**
	 * Varre o "form" passado como parâmetro e monta a "query string" da URL.
	 * As tags que possuírem o atributo "dontsend" declarado, não serão concatenadas na URL.
	 * Quando um elemento posuir o atributo "all", no caso de "select", "radio" (não implementado) e "checkbox" (não implementado),
	 * serão enviados na URL todas as suas opções e seus valores.
	 * @autor: Leandro Zanol
	 * 
	 * @param HTMLFormElement form - Referência do formulário HTML.
	 * @param String url (opcional) - URL base para montar.
	 * @return String. A URL montada.
	 */
	this.buildURL = function(url)
	{
		var e, urlOut, separator, name, radio, type;
	
		e = _form.elements;
		urlOut = (url !== undefined) ? url + ((url.match(/\?|\&|\=/) !== null) ? "&" : "?") : "";
		separator = "";
	
		for (var i = 0; i < e.length; i++)
		{
			name = (e[i].name !== "" && e[i].name !== undefined) ? e[i].name : ((e[i].id !== "" && e[i].id !== undefined) ? e[i].id : undefined);
			type = e[i].type;
	
			if (name !== undefined && e[i].attributes["dontsend"] === undefined)
			{
				switch (type)
				{
					case "text":
					case "password":
					case "hidden":
					case "file":
					case "textarea":
					case "select-one":
						urlOut += separator + name + "=" + escape(e[i].value);
						separator = "&";
					break;
	
					case "select-multiple":
						for (var j = 0; j < e[i].options.length; j++)
						{
							if (e[i].attributes["all"] !== undefined)
							{
								urlOut += separator + name + "[]=" + escape(e[i].options[j].value);
								separator = "&";
							}
							else if (e[i].options[j].selected)
							{
								urlOut += separator + name + "[]=" + escape(e[i].options[j].value);
								separator = "&";
							}
						}
					break;
	
					case "radio":
						radio = document.getElementsByName(e[i].name);
		
						for (var j = 0; j < radio.length; j++)
						{
							if (radio[j].checked)
							{
								urlOut += separator + name + "=" + escape(radio[j].value);
								separator = "&";
							}
						}
		
						i += radio.length - 1;
					break;
		
					case "checkbox":
						if (e[i].checked)
						{
							urlOut += separator + name + "=" + escape(e[i].value);
							separator = "&";
						}
					break;
				}
			}
		}
	
		return specialChars(urlOut); // O sinal de "+" é o símbolo de "espaço", para ser literal, ele deve ser substituído.
	};
	
	/**
	 * Verifica se os campos de um formulário estão devidamente preenchidos ou assinalados.
	 * Obs: Todos os elementos do formulário que se deseja efetuar a validação, deverão conter a propriedade "label".
	 *      Que se refere ao texto que irá surgir no caso de um elemento não estar adequadamente preenchido ou assinalado.
	 *      Os que não contiverem "label", serão ignorados. Para o elemento "radio", é necessário "label" somente para o primeiro elemento.
	 *		Quando um elemento posuir o atributo "all", no caso de "select" e "checkbox" (não implementado),
	 *		serão enviados na URL todas as suas opções e seus valores; portanto a validação será efetuada embasada nisso.
	 *		Para alterar a condição da validação, no caso de "text", "password", "textarea", "select" e "file", basta especificar
	 *		o atributo "condition=_condição_".
	 *		Para efetuar uma validação específica em um campo já preenchido, tais como de e-mail, senha, CPF/CNPJ (não implementado), etc.,
	 *		especifique o atributo "validationtype=_palavraChave_"; onde "_palavrachave" é: "email", "password", "cpf" (não implementado) e
	 *		"cnpj" (não implementado).
	 * @autor: Leandro Zanol
	 * 
	 * @param HTMLFormElement form - Referência do formulário a ser validado.
	 * @param Boolean oneByOne (opcional) - Determina o modo de validação: "true" valida campo por campo, "false" valida todos ao mesmo tempo.
	 * @return Boolean. "true" se o formulário estiver devidamente preenchido.
	 */
	this.validate = function(oneByOne)
	{
		var e, type, condition, msg, label, emptyFields, firstField, validationType, blankMessage;
	
		e = _form.elements;
		emptyFields = "";
	
		if (oneByOne === undefined)
		{
			oneByOne = false;
		}
	
		for (var i = 0; i < e.length; i++)
		{
			type = e[i].type;
	
			if (type !== undefined)
			{
				if (type.match(/^text$|^password$|^textarea$|^select\-|^radio$|^checkbox$|^file$/) !== null)
				{
					label = (e[i].attributes["label"] !== undefined) ? e[i].attributes["label"].value : undefined;
					validationType = (e[i].attributes["validationtype"] !== undefined) ? e[i].attributes["validationtype"].value : undefined;
					blankMessage = (e[i].attributes["blankmessage"] !== undefined) ? e[i].attributes["blankmessage"].value : undefined;
				}
	
				if (label !== undefined)
				{
					if (blankMessage === undefined)
					{
						// Define a mensagem de acordo com o tipo do elemento do formulário
						if (type.match(/^text$|^password$|^textarea$/) !== null)
						{
							msg = "Preencha o campo \"" + label + "\"!";
						}
						else if (type.match(/^select\-|^radio$|^checkbox$/) !== null)
						{
							msg = "Selecione uma opção para \"" + label + "\"!";
						}
						else if (type.match(/^file$/) !== null)
						{
							msg = "Selecione o arquivo para \"" + label + "\"!";
						}
					}
					else
					{
						// Define uma mensagem personalizada
						msg = blankMessage;
					}
	
					// Valida cada elemento do formulário
					if (type.match(/^text$|^password$|^textarea$|^select\-|^file$/) !== null)
					{
						if (type.match(/^select\-multiple$/) !== null && e[i].attributes["all"] !== undefined)
						{
							condition = (e[i].options.length === 0);
						}
						else if (e[i].attributes["condition"] !== undefined)
						{
							condition = (e[i].value == e[i].attributes["condition"].value);
						}
						else
						{
							condition = (e[i].value === "");
						}
	
						if (condition)
						{
							if (oneByOne)
							{
								alert(msg);
								e[i].focus();
	
								return false;
							}
							else
							{
								emptyFields += "- " + label + "\n";
	
								if (firstField === undefined)
								{
									firstField = e[i];
								}
							}
						}
					}
					else if (type.match(/^radio$/) !== null)
					{
						var j, chk, radio;
	
						radio = document.getElementsByName(e[i].name);
						chk = false;
						j = 0;
	
						while (j < radio.length)
						{
							if (radio[j].checked)
							{
								chk = true;
			
								break;
							}
		
							j++;
						}
		
						if (!chk)
						{
							if (oneByOne)
							{
								alert(msg);
		
								return false;
							}
							else
							{
								emptyFields += "- " + label + "\n";
	
								if (firstField === undefined)
								{
									firstField = e[i];
								}
							}
						}
		
						i += radio.length - 1;
					}
					else if (type.match(/^checkbox$/) !== null)
					{
						if (!e[i].checked)
						{
							if (oneByOne)
							{
								alert(msg);
	
								return false;
							}
							else
							{
								emptyFields += "- " + label + "\n";
	
								if (firstField === undefined)
								{
									firstField = e[i];
								}
							}
						}
					}
	
					if (validationType !== undefined)
					{
						if (type.match(/^text$|^password$|^textarea$/) !== null && e[i].value !== "")
						{
							switch (validationType)
							{
								case "password":
									var ref, j, vt;
	
									j = i + 1;
	
									while (j < e.length)
									{
										vt = e[j].attributes["validationtype"];
	
										if (vt !== undefined)
										{
											if (vt.value === "password")
											{
												ref = e[j];
												j = e.length;
											}
										}
	
										j++;
									}
	
									if (ref !== null)
									{
										if (ref.value !== e[i].value)
										{
											if (oneByOne)
											{
												alert("Confirmação de senha inválida!");
												ref.select();
		
												return false;
											}
											else
											{
												emptyFields += "- " + label + " (Confirmação de senha inválida)\n";
		
												if (firstField === undefined)
												{
													firstField = ref;
												}
											}
										}
									}
								break;
	
								case "e-mail":
									if (e[i].value.match(/^\w+([\.\-]\w+)*@\w+\.\w+(\.\w+)*$/) === null)
									{
										if (oneByOne)
										{
											alert("O e-mail informado não é válido!");
											e[i].select();
	
											return false;
										}
										else
										{
											emptyFields += "- " + label + " (e-mail inválido)\n";
	
											if (firstField === undefined)
											{
												firstField = e[i];
											}
										}
									}
								break;
								
								case "cpf":
									if (e[i].value.match(/^\d{3}\.\d{3}\.\d{3}\-\d{2}$/) === null)
									{
										if (oneByOne)
										{
											alert("O formato do CPF não é válido!");
											e[i].select();
											
											return false;
										}
										else
										{
											emptyFields += "- " + label + " (CPF inválido)\n";
											
											if (firstField === undefined)
											{
												firstField = e[i];
											}
										}
									}
								break;
								
								case "cnpj":
									if (e[i].value.match(/^\d{2}\.\d{3}\.\d{3}\/\d{4}\-\d{2}$/) === null)
									{
										if (oneByOne)
										{
											alert("O formato do CNPJ não é válido!");
											e[i].select();
											
											return false;
										}
										else
										{
											emptyFields += "- " + label + " (CNPJ inválido)\n";
											
											if (firstField === undefined)
											{
												firstField = e[i];
											}
										}
									}
								break;
							}
						}
					}
				}
			}
	
			if (i === (e.length - 1))
			{
				if (oneByOne)
				{
					return true;
				}
				else
				{
					if (emptyFields !== "")
					{
						alert("Preencha os seguintes campos:\r\n" + emptyFields);
	
						if (firstField.value !== "" && firstField.type.match(/^text$|^textarea$|^password$/) !== null)
						{
							firstField.select();
						}
						else
						{
							firstField.focus();
						}
	
						return false;
					}
					else
					{
						return true;
					}
				}
			}
		}
	};
};