var http;
var InstanciaForm = null;
function Form() {
	/// <summary>
	/// Define uma URL para postar o formulário.
	/// <access mode="public"/>
	/// </summary>
	this.PostUrl = null;

	/// <summary>
	/// Define a URL que deve ser postada para carregar o formulário.
	/// <access mode="public"/>
	/// </summary>
	this.LoadUrl = null;
	
	/// <summary>
	/// Define o formulário para ser postado.
	/// <access mode="public"/>
	/// </summary>
	this.Form = null;

	/// <summary>
	/// Define a string que deve ser enviada junto à requisição.
	/// <access mode="public"/>
	/// </summary>
	this.StrPost = null;

	/// <summary>
	/// Define o nome do nó XML que contém as informações do registro.
	/// <access mode="public"/>
	/// </summary>
	this.NoRegistro = null;

	/// <summary>
	/// Define os nomes dos nós XML que contém possíveis erro na solicitação dos dados. Se estiver definido e o XML retornar qualquer nó que coincidam com os nós definidos, será considerado que existe um erro.
	/// <access mode="public"/>
	/// </summary>
	this.NoErro = Array();

	/// <summary>
	/// Define o formulário que deve ser submetido para carregar o formulário.
	/// <access mode="public"/>
	/// </summary>
	this.LoadForm = null;

	/// <summary>
	/// Armazena o estado de retorno para o carregamento do formulário. Caso o XML retornado por "LoadUrl" não contiver nós, seu valor será "false", caso contrário, seu valor será "true". Essa variável só será populada depois da chamada do método "Load".
	/// <access mode="public"/>
	/// </summary>
	this.LoadFeedback = null;

	/// <summary>
	/// Define a função que deve ser chamada quando a postagem do formulário for concluída.
	/// <access mode="public"/>
	/// </summary>
	this.callback = function() {};

	/// <summary>
	/// Define a função que deve ser chamada quando a o carregamento do formulário for concluído.
	/// <access mode="public"/>
	/// </summary>
	this.LoadCallback = function() {};

	/// <summary>
	/// Define as validações que devem ser efetuadas antes de o formulário ser postado.
	/// <access mode="private"/>
	/// </summary>
	this.Validators = Array();

	// <summary>
	/// Posta o formulário na URL especificada.
	/// <access mode="public"/>
	/// <returns>Retorna "true" se o formulário for postado com sucesso, e "false" caso haja algum erro de validação.</returns>
	/// </summary>
	this.DoPost = function() {
		if (this.Form == null && this.StrPost == null)
			throw new Error("Formulário não especificado.");
		else if (this.PostUrl == null)
			throw new Error("URL não especificada.");


		try
		{
			this.ValidarForm();

			var strPost = "";
			if (this.Form != null)
				strPost = this.GerarStrPost(this.Form);
			else if (this.StrPost != null)
				strPost = this.StrPost;
			http = this.ObterHttp();
			http.onreadystatechange = this.callback;
			http.open("POST",this.PostUrl,true);
			http.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset: utf-8");
			http.send(strPost);
			return http;
		}
		catch (e)
		{
			alert(e.message);
			return false;
		}

	}

	/// <summary>
	/// Carrega o formulário de acordo com o XML carregado a partir de "LoadUrl";
	/// <access mode="public"/>
	/// </summary>
	this.Load = function() {
		InstanciaForm = this;
		var strPost = null;
		var method = "GET";

		http = this.ObterHttp();
		http.onreadystatechange = this.PopularForm;
		if (this.LoadForm != null) {
			strPost = this.GerarStrPost(this.LoadForm);
			method = "POST";
		}
		http.open(method,this.LoadUrl,true);
		if (this.LoadForm != null)
			http.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset: utf-8");
		http.send(strPost);
		
	}

	/// <summary>
	/// Função de callback para popular o formulário após a execução de "Load".
	/// <access mode="private"/>
	/// </summary>
	this.PopularForm = function() {
		if (http.readyState == 4)
		{
			var xml = http.responseXML;

			// Verifica se o XML retornou algum erro
			var erro = false;
			if (InstanciaForm.NoErro.length == 0) {
				erro = xml.getElementsByTagName(InstanciaForm.NoRegistro)[0].childNodes.length > 0;
			} else {
				for (var i=0;i<InstanciaForm.NoErro.length;i++) {
					if (xml.getElementsByTagName(InstanciaForm.NoErro[i]).length > 0) {
						erro = true;
					}
				}
			}

			// Popula o formulário, caso o XML não tenha retornado nenhum erro.			
			if(!erro) {
				InstanciaForm.LoadFeedback = true;
				for(var i=0;i<InstanciaForm.Form.elements.length;i++) {
					var el = InstanciaForm.Form.elements[i];
					var valor = "";
					try {
						valor = xml.getElementsByTagName(el.name)[0].childNodes[0].nodeValue;
					} catch (e) {}
					if (el.type == "text" || el.type == "hidden" || el.type == "password") {
						el.value = valor;
					} else if (el.type == "select-multiple" || el.type == "select-one") {
						for(var j=0;j<el.options.length;j++) {
							if (el.options[j].value == valor)
								el.options[j].selected = true;
						}
					} else if (el.type == "radio") {
						if(el.value == valor)
							el.checked = true;
					} else if (el.type == "checkbox") {
						valor = xml.getElementsByTagName(el.name);
						for(var j=0;j<valor.length;j++) {
							if (valor[j].childNodes[0].nodeValue == el.value)
								el.checked = true;
						}
					}
				}
			} else {
				InstanciaForm.LoadFeedback = false;
			}
			InstanciaForm.LoadCallback();
		}
	}

	// <summary>
	/// Posta o formulário na URL especificada.
	/// <access mode="public"/>
	/// </summary>
	this.ValidarForm = function() {
	    for (var i = 0; i < this.Validators.length; i++) {
	        var val = this.Validators[i];
	        if (val.TipoValidacao == "vazio") {
	            switch (this.Form.elements[val.NomeCampo].type) {
	                case "textarea":
	                case "text":
	                    if (this.Form.elements[val.NomeCampo].value == "")
	                        throw new Error(val.Mensagem);
	                    break;
	                case "password":
	                    if (this.Form.elements[val.NomeCampo].value == "")
	                        throw new Error(val.Mensagem);
	                    break;
	                case "select-one":
	                    if (this.Form.elements[val.NomeCampo].options[this.Form.elements[val.NomeCampo].selectedIndex].value == "")
	                        throw new Error(val.Mensagem);
	                    break;
	                case "select-multiple":
	                    if (this.Form.elements[val.NomeCampo].options[this.Form.elements[val.NomeCampo].selectedIndex].value == "")
	                        throw new Error(val.Mensagem);
	                    break;
	                default:
	                    var valido = false;
	                    for (var j = 0; j < this.Form.elements[val.NomeCampo].length; j++) {
	                        if (this.Form.elements[val.NomeCampo][j].checked == true) {
	                            valido = true;
	                            break;
	                        }
	                    }
	                    if (!valido)
	                        throw new Error(val.Mensagem);
	                    break;
	            }
	        } else if (val.TipoValidacao == "email") {
	            if (!this.isEmail(this.Form.elements[val.NomeCampo].value))
	                throw new Error(val.Mensagem);
	        } else if (val.TipoValidacao == "cpf") {
	            if (!this.isCPF(this.Form.elements[val.NomeCampo].value))
	                throw new Error(val.Mensagem);
	        } else if (val.TipoValidacao == "cnpj") {
	            if (!this.isCNPJ(this.Form.elements[val.NomeCampo].value))
	                throw new Error(val.Mensagem);
	        } else if (val.TipoValidacao == "data") {
	            if (!this.isDate(this.Form.elements[val.NomeCampo].value))
	                throw new Error(val.Mensagem);
	        } else if (val.TipoValidacao == "cep") {
	            if (!new RegExp(/\d{5}-\d{3}/).test(this.Form.elements[val.NomeCampo].value))
	                throw new Error(val.Mensagem);
	        } else if (val.TipoValidacao == "ddd") {
	            if (!new RegExp(/\d{3}/).test(this.Form.elements[val.NomeCampo].value))
	                throw new Error(val.Mensagem);
	        } else if (val.TipoValidacao == "telefone") {
	            if (!new RegExp(/\d{8}/).test(this.Form.elements[val.NomeCampo].value))
	                throw new Error(val.Mensagem);
	        }
	    }
	}

	// <summary>
	/// Adiciona uma validação para ser efetuada antes de o formulário a ser postado.
	/// <access mode="public"/>
	/// <param name="NomeCampo">Nome do campo do formulário para ser validado.</param>
	/// <param name="Mensagem">Mensagem de erro para ser mostrada caso a validação não seja bem sucedida.</param>
	/// <param name="TipoValidacao">Tipo da validação para ser efetuada. O valor para esse parametro pode ser um dos abaixo:
	/// vazio: Não permite que o valor campo seja vazio.
	/// email: Verifica se o valor do campo é um endereço e-mail válido.
	/// cpf: Verifica se o valor do campo é um cpf válido.
	/// cnpj: Verifica se o valor do campo é um cnpj válido.
	/// </summary>
	this.AdicionarValidacao = function (NomeCampo, Mensagem, TipoValidacao) {
		var validacao = {
			"NomeCampo" : NomeCampo,
			"Mensagem" : Mensagem,
			"TipoValidacao" : TipoValidacao
		};
		this.Validators[this.Validators.length] = validacao;
	}

	// <summary>
	/// Obtem uma instância do objeto responsável por efetuar as chamadas Ajax.
	/// <access mode="private"/>
	/// </summary>
	this.ObterHttp = function() {
	    var http = false;

	    try {
	        http = new XMLHttpRequest();
	    }
	    catch (e) {
	        try {
	            http = new ActiveXObject("Microsoft.XMLHTTP");
	        }
	        catch (e) {
	            http = new ActiveXObject("Msxml2.XMLHTTP");
	            //http = false;
	        }
	    }

	    //		if (!http && typeof XMLHttpRequest!='undefined') {
	    //			http = new XMLHttpRequest();
	    //		}

	    return http;
	}

	// <summary>
	/// Verifica se o valor do parâmetro é um e-mail válido.
	/// <access mode="private"/>
	/// <param name="email">Valor para verificar se é um e-mail válido.</param>
	/// </summary>
	this.isEmail = function(email){
		var suportado = 0;
		EmailInv = false;

		if (window.RegExp) {
			var tempReg = /a/;
			if (tempReg.test("a")){
				suportado = 1;
			}
		}

		if (!suportado){
			if(((email.indexOf(".") <= 0) || (email.indexOf("@") <= 0)) || ((email.lastIndexOf(".") == (email.length - 1)) || (email.lastIndexOf("@") == (email.length -1)))){
				EmailInv = true;
			}
		}else{
			var tmp1 = /(@.*@)|(\.\.)|(@\.)|(^\.)/;
			var tmp2 = /^.+@(\[?)[a-zA-Z0-9\-\.]+\.([a-zA-Z]{2,3}|[0-9]{1,3})(\]?)$/;
			if(tmp1.test(email) || !tmp2.test(email)){
				EmailInv = true;
			}
		}

		return !EmailInv;
	}

	// <summary>
	/// Verifica se o valor do parâmetro é um CPF válido.
	/// <access mode="private"/>
	/// <param name="cpf">Valor para verificar se é um CPF válido.</param>
	/// </summary>
	this.isCPF = function(cpf){
		var cpf_limpo = cpf.replace(/\D/g,"");
		if (cpf_limpo.length !=11)
			return false;

		var soma = 0;
		for (var i=0; i<9; i++)
			soma += parseInt(cpf_limpo.charAt(i)) * (10-i);

		if (soma == 0)
			return false;

		primeiro_digito = 11 - soma % 11;
		if (primeiro_digito > 9)
			primeiro_digito = 0;

		if (cpf_limpo.substr(9,1) != primeiro_digito)
			return false;

		var soma = 0;
		for (var i=0; i<10; i++)
			soma += parseInt(cpf_limpo.charAt(i)) * (11-i);

		var segundo_digito = 11 - soma % 11;

		if (segundo_digito > 9)
			segundo_digito = 0;
		if (cpf_limpo.substr(10,1) != segundo_digito)
			return false;

		return true;
	}

	// <summary>
	/// Verifica se o valor do parâmetro é um CNPJ válido.
	/// <access mode="private"/>
	/// <param name="CNPJ">Valor para verificar se é um CNPJ válido.</param>
	/// </summary>
	this.isCNPJ = function(CNPJ) {
		while(/\D/.test(CNPJ))
			CNPJ = CNPJ.replace(/\D/,"");
		if (CNPJ.length < 14)
			return false;
		var a = [];
		var b = new Number;
		var c = [6,5,4,3,2,9,8,7,6,5,4,3,2];
		for (i=0; i<12; i++){
			a[i] = CNPJ.charAt(i);
			b += a[i] * c[i+1];
		}
		if ((x = b % 11) < 2) {
			a[12] = 0
		} else {
			a[12] = 11-x
		}
		b = 0;
		for (y=0; y<13; y++) {
			b += (a[y] * c[y]);
		}
		if ((x = b % 11) < 2) {
			a[13] = 0;
		} else {
			a[13] = 11-x;
		}

		if ((CNPJ.charAt(12) != a[12]) || (CNPJ.charAt(13) != a[13]))
			return false;
		else
			return true;
    }

    this.isDate = function(strDate) {
        if (!strDate && strDate.length == 0) {
            return true;
        } else {
            var arrDate = strDate.split("/")
            var intDay = arrDate[0];
            var intMonth = arrDate[1];
            var intYear = arrDate[2];

            if (intMonth >= 1 && intMonth <= 12 && intYear > 0 && intYear.length >= 2 && !isNaN(intDay) && !isNaN(intMonth) && !isNaN(intYear)) {
                if ((intDay >= 1) && (intDay <= this.dayMonth(intMonth, intYear))) {
                    return true;
                } else {
                    return false;
                }
            }
            else {
                return false;
            }
        }
    }

    this.dayMonth = function(intMonth, intYear) {
        if (intMonth == 2) {
            if (((intYear % 4) != 0) || (((intYear % 100) == 0) && ((intYear % 400) != 0))) {
                return (28);
            } else {
                return (29);
            }
        } else {
            if (intMonth < 8) {
                return (30 + (intMonth % 2));
            } else {
                return (31 - (intMonth % 2));
            } 
        }
    }

	// <summary>
	/// Obtém uma string no formato "nome1=valor1&nome2=valor2", contendo os campos formulário passado como parâmetro.
	/// <access mode="private"/>
	/// <param name="form">Objeto "<form>" para buscar os campos e gerar a string.</param>
	/// </summary>
	this.GerarStrPost = function(form) {
		var strPost = "";
		for(var i=0;i<form.elements.length;i++)
		{
			var el = form.elements[i];
			if (el.name == "__VIEWSTATE")
			    continue;
			if (el.type == "text" || el.type == "hidden" || el.type == "password" || el.type == "textarea")
				strPost += el.id +"="+ el.value +"&";
			else if (el.type == "select-one" || el.type == "select-multiple") 
			{
			    if (el.selectedIndex > -1)
				    strPost += el.id +"="+ el.options[el.selectedIndex].value +"&";
			}
			else if (el.type == "radio" || el.type == "checkbox") {
				if(el.checked)
					strPost += el.id + (this.PostUrl.indexOf(".php") > 0 ? "[]" : "") +"="+ el.value +"&";
			}
		}

		return strPost;
	}
}