function getPosicaoElemento(elemID) {
	var offsetTrail = document.getElementById(elemID);
	var offsetLeft = 0;
	var offsetTop = 0;
	while (offsetTrail) {
		offsetLeft += offsetTrail.offsetLeft;
		offsetTop += offsetTrail.offsetTop;
		offsetTrail = offsetTrail.offsetParent;
	}
	if (navigator.userAgent.indexOf("Mac") != -1 && 
		typeof document.body.leftMargin != "undefined") {
		offsetLeft += document.body.leftMargin;
		offsetTop += document.body.topMargin;
	}
	return {left:offsetLeft, top:offsetTop};
}

function txtBoxFormat(strField, sMask, evtKeyPress) {
	var i, nCount, sValue, fldLen, mskLen,bolMask, sCod, nTecla;
	
	if (document.all) { // Internet Explorer
		 nTecla = evtKeyPress.keyCode;
	} else if (document.layers) { // Nestcape
		 nTecla = evtKeyPress.which;
	} else {
		 nTecla = evtKeyPress.which;
		 if (nTecla == 8) {
			  return true;
		 }
	}

	sValue = strField.value;
	// Limpa todos os caracteres de formataçăo que
	// já estiverem no campo.
	while (sValue.indexOf("-")>=0){
		sValue = sValue.toString().replace( "-", "" );
	}
	while (sValue.indexOf(".")>=0){
		sValue = sValue.toString().replace( ".", "" );
	}
	while (sValue.indexOf(",")>=0){
		sValue = sValue.toString().replace( ",", "" );
	}
	while (sValue.indexOf("/")>=0){
		sValue = sValue.toString().replace( "/", "" );
	}
	while (sValue.indexOf("(")>=0){
		sValue = sValue.toString().replace( "(", "" );
	}
	while (sValue.indexOf(")")>=0){
		sValue = sValue.toString().replace( ")", "" );
	}
	while (sValue.indexOf(":")>=0){
		sValue = sValue.toString().replace( ":", "" );
	}
	//sValue = sValue.toString().replace( " ", "" );
	//sValue = sValue.toString().replace( " ", "" );
	fldLen = sValue.length;
	mskLen = sMask.length;
	
	i = 0;
	nCount = 0;
	sCod = "";
	mskLen = fldLen;
	
	while (i <= mskLen) {
		bolMask = ((sMask.charAt(i) == "-") || (sMask.charAt(i) == ":") || (sMask.charAt(i) == ".") || (sMask.charAt(i) == "/"));
		bolMask = bolMask || ((sMask.charAt(i) == "(") || (sMask.charAt(i) == ")") || (sMask.charAt(i) == " "));
		
		if (bolMask) {
			 sCod += sMask.charAt(i);
			 mskLen++;
		} else {
			 sCod += sValue.charAt(nCount);
			 nCount++;
		}
		i++;
	}
	
	strField.value = sCod;
	if(sMask.charAt(0) == "C"){
		return ((nTecla == 8) || (nTecla == 32) || (nTecla > 64) && (nTecla < 91) || (nTecla > 96) && (nTecla < 123) || (nTecla > 191) && (nTecla < 256));// apenas backspace, espaço, letras de a-z e A-Z com e sem acento
	} else {
		mask = sMask.charAt(i-1);
		switch(mask){
			case "9":
				return ((nTecla > 47) && (nTecla < 58));// números de 0 a 9
			break;
	
			default:
				return true;
			break;
		}
	}
}

/**
 * Gerenciador de formulários
 * 
 * @author {Eduardo Schmidt}
 * @param {Object/String} form Formulário que será gerenciado
 * @version {1.2}
 */
function FormValidator(form, comimagem)
{
	this.AddImagem = (typeof comimagem == 'undefined') ? true : comimagem; /* Adicionado para colocar ou năo a imagem ao lado do campo quando houver erro */
	var form = (typeof form == 'object') ? (form) : (document.forms[form]);
	form.formManager = this;

	this.isValidated = false;
	this.invalidFields = new Array(0);

	this.IMAGE = 'images/img_campo.gif';
	this.IMAGE_POSITION = 'right';	
	this.validators = {
		vtypes: [{
			validator: 'date',
			message: 'Preencha uma data válida no formato dd/mm/AAAA!',
			callback: function(value) {
				var regex = /^(((0[1-9]|[12][0-9]|3[01])([-./])(0[13578]|10|12)([-./])(\d{4}))|(([0][1-9]|[12][0-9]|30)([-./])(0[469]|11)([-./])(\d{4}))|((0[1-9]|1[0-9]|2[0-8])([-./])(02)([-./])(\d{4}))|((29)(\.|-|\/)(02)([-./])([02468][048]00))|((29)([-./])(02)([-./])([13579][26]00))|((29)([-./])(02)([-./])([0-9][0-9][0][48]))|((29)([-./])(02)([-./])([0-9][0-9][2468][048]))|((29)([-./])(02)([-./])([0-9][0-9][13579][26])))$/;
				return regex.test(value); 
			}
		}, {
			validator: 'email',
			message: 'Preencha um e-mail válido no formato usuario@dominio.com!',
			callback: function(value) {
				var regex = /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/;
				return regex.test(value);
			}
		}, {
			validator: 'fone',
			message: 'Preencha corretamento o telefone no formato (DD)FFFF-FFFF!',
			callback: function(value) {
				var regex = /^\((\d{2})\)+(\d{4})+-(\d{4})$/;
				return regex.test(value);
			}
		}, {
			validator: 'cep',
			message: 'Preencha um CEP válido no formato XXXXX-XXX!',
			callback: function(value) {
				var regex = /^(\d{5})+-(\d{3})$/;
				return regex.test(value);
			}
		}],

		add: function(validator) {
			if (validator.validator && validator.message && validator.callback) {
				this.vtypes.push(validator);
			} else {
				alert('Invalid validator object! I need properties: validator, message and callback. See the doc for more.');
			}
		},
	
		get: function(validator) {
			for (var i=0; i<this.vtypes.length; i++) {
				if (this.vtypes[i].validator == validator) {
					return this.vtypes[i];
					break;
				}
			}
			return false;
		}
	};

	getValue = function(field) {
		switch (field.type.toLowerCase()) {
			case 'text':
			case 'textarea':
			case 'password':
			case 'hidden':
			case 'file':
			case 'select-one':
			case 'select-multiple':
				return field.value;
				break;
			case 'radio':
			var name = field.name;
				for (var i=0; i<form.elements[name].length; i++) {
					if (form.elements[name][i].checked) {
						return form.elements[name][i].value;
					}
				}
				return '';
				break;
			case 'checkbox':
				return field.checked ? field.value : '';
				break;
			default: return ''; //alert(field.type);
		}
	};

	this.markField = function(field, image, message, pos) {
		var alertEl = document.getElementById('alert_'+field.name); 
		if (alertEl === null) {
			var img = document.createElement('img');
			img.setAttribute('id', 'alert_'+field.name);
			img.setAttribute('src', image);
			img.setAttribute('title', message);
			img.style.cursor = 'pointer'; 
			img.style.marginLeft = img.style.marginRight = '5px';
			if(this.AddImagem) img.style.paddingTop = '8px'; 

			img.onclick = function(event) { field.focus(); };
			img.onmouseover = function(event) {
				var hintEl = document.getElementById('hint_'+field.name);
				if (hintEl === null) {
					var hint = document.createElement('div');
					hint.setAttribute('id', 'hint_'+field.name);
					hint.innerHTML = '\
					<table border="0" cellpadding="0" cellspacing="0" style="margin: 0; padding: 0;">\
					<tbody>\
					<tr>\
						<td class="hint_ne"></td>\
						<td class="hint_n"></td>\
						<td class="hint_nw"></td>\
					</tr><tr>\
						<td class="hint_e"></td>\
						<td class="hint"><span>'+ img.getAttribute('title') +'</span></td>\
						<td class="hint_w"></td>\
					</tr><tr>\
						<td class="hint_se"></td>\
						<td class="hint_s"></td>\
						<td class="hint_sw"></td>\
					</tr><tr>\
						<td class="'+ (pos == 'left' ? 'hint_bl' : 'hint_br') +'" colspan="3"></td>\
					</tr>\
					</tbody>\
					</table>';
					hint.style.position = 'absolute';
					document.body.appendChild(hint);
					var imgPos = getPosicaoElemento(img.getAttribute('id'));
					hint.style.top = (imgPos.top - hint.offsetHeight - 5) +'px';
					if (pos == 'left') {
						hint.style.left = imgPos.left +'px';
					} else {
						hint.style.left = (imgPos.left - hint.offsetWidth + 20) +'px';
					}
					img.setAttribute('title', '');
				} else {
					hintEl.parentNode.removeChild(hintEl);
				}
			};
			img.onmouseout = function(event) {
				var hint = document.getElementById('hint_'+field.name);
				img.setAttribute('title', hint.getElementsByTagName('span')[0].innerHTML);
				if (hint) document.body.removeChild(hint);
			};

			if (pos == 'left') {
				if(this.AddImagem) field.style.border = 'solid #FF0000 1px'; /* Trecho modificado para deixar o campo com outra cor */
				field.parentNode.insertBefore(img, field);
			} else {
				if(this.AddImagem) field.style.border = 'solid #FF0000 1px'; /* Trecho modificado para deixar o campo com outra cor */
				field.parentNode.appendChild(img);
			}
		} else {
			if (alertEl.title != message) alertEl.title = message;
		}
	};

	this.unmarkField = function(field, message) {
		if (document.getElementById('alert_'+field.name) !== null) {
			field.style.border = 'solid #A7A6AA 1px'; /* Trecho modificado para deixar o campo com a cor original */
			field.parentNode.removeChild(document.getElementById('alert_'+field.name));
			var hint = document.getElementById('hint_'+field.name);
			if (hint) document.body.removeChild(hint);
		}else if(!this.AddImagem){
			field.style.border = 'solid #A7A6AA 1px';
		}
	};


	/**
	 * Valida um campo específico do formulário
	 * 
	 * @param {Object/String} field Campo que se deseja validar
	 * @return {bool}
	 */
	this.validateField = function(field) {
		if (typeof field != 'object') field = document.getElementById(field);
		try {
			// preenchimento obrigatório
			if ((field.getAttribute('required') == 'true') && !getValue(field).replace(/^\s*/, "").replace(/\s*$/, "").length) {
				throw 'Campo de preenchimento obrigatório';
			}
			// validador de conteúdo
			var valName = field.getAttribute('validator');
			if ((valName !== null) && getValue(field)) {
				var validator = this.validators.get(valName);
				if (!validator.callback(getValue(field))) throw validator.message;
			}
			this.unmarkField(field);
			return true;
		} catch (e) {
			this.markField(field, this.IMAGE, e, this.IMAGE_POSITION);
			return false;
		}
	};

	/**
	 * Valida o formulário em questăo
	 * 
	 * @return {bool}
	 */
	this.validate = function() {
		this.isValidated = true;
		this.invalidFields = new Array(0);
		for (var i=0; i<form.length; i++) {
			var el  = form.elements[i];
			if (!this.validateField(el)) {
				//this.invalidFields.push(el.name);
				this.isValidated = false;
			}
		}
		return this.isValidated;
	};

	/**
	 * Construtor
	 */
	for (var i=0; i<form.length; i++) {
		var el = form.elements[i];
		// validador
		el.onchange = el.onkeyup = el.onblur = function(event) {
			this.form.formManager.validateField(this);
		}
		// máscara
		if (el.getAttribute('mask') !== null) {
			el.onkeypress = function(event) {
				if (document.all) event = window.event; // merda do IE dinovo, năo repassa o evento
				return txtBoxFormat(this, this.getAttribute('mask'), event);
			}
		}
	}
	form.onsubmit = function(event) {
		var validated = this.formManager.validate();
		if (this.formManager.onsubmit) {
			var uResult = this.formManager.onsubmit(validated, this.formManager.invalidFields);
			return validated ? uResult : validated;
		} else {
			return validated;
		}
	};
};
