var ScrollLinks = {
	currentHash: false,
	start: function(){
		this.scroll = new fx.Scroll({duration: 1100, transition: fx.sineOut, onComplete: function(){this.end();}.bind(this)});
		this.allinks = $c(document.getElementsByTagName('a'));
		this.allinks.each(function(lnk){
			if ((lnk.href && lnk.href.indexOf('#') != -1) && ( (lnk.pathname == location.pathname) 
				|| ('/'+lnk.pathname == location.pathname) ) && (lnk.search == location.search)) {
				lnk.onclick = function(){
					ScrollLinks.scroll.clearTimer();
					this.initialHref = this.href;
					this.initialHash = this.hash;
					this.href = "javascript:void(0)";
					setTimeout(function(){this.href = this.initialHref;}.bind(this), 1000);
					ScrollLinks.go(this);
				}
			}
		});
	},

	go: function(link){
		this.currentHash = link.initialHash.slice(1);
		if (this.currentHash) {
			this.allinks.each(function(lnk){
				if (lnk.id == ScrollLinks.currentHash){
					if (window.opera) lnk =  [lnk].find('parentNode');
					ScrollLinks.scroll.scrollTo(lnk);
					return;
				}
			});
		}
	},

	end: function(){
		if (!/Konqueror|Safari|KHTML/.test(navigator.userAgent)) window.location.hash = "#"+this.currentHash;
		this.currentHash = false;
	}
}

Metodus = function() {};

Metodus.parser = Class.create();
Metodus.parser.prototype = {
	initialize: function() {
		str = document.URL;	
		x = str.indexOf("?");
		
		if (x != -1) {
			x++;
			y = str.length;
			p = str.substring(x, y);
			
			x = p.indexOf("=");
			a = p.substring(0, x);
			
			x++;
			y = p.length;
			b = p.substring(x, y);
			
			el = $(a);
			if (el != null) { el.value = unescape(b); }
		}
	}
}

Metodus.validate = Class.create();
Metodus.validate.prototype = {
	initialize: function(f, props) {
		this.props = {
			lang: 'en',
			inline: 'last',
			block: false
		}
		Object.extend(this.props, props || {});	

		this.f = $(f);		
		this.f.onsubmit = function() { return this.validate(); }.bind(this);
	},

	validate: function() {
		errors = document.getElementsByClassName('error'); // clean up
		errors.each(function(el, i) {
			Element.removeClassName(el, 'error');

			labels = el.parentNode.getElementsByTagName('label');
			if (labels.length) labels[0].style.display = 'block';
			
			if (el.tagName == 'SPAN') {
				spans = el.parentNode.getElementsByTagName('span');
				for (s = 0; s < spans.length; s++) {
					if (spans[s].parentNode == el.parentNode && spans[s] != el) {
						spans[s].style.display = 'inline';
						break;
					}
				}
			}

			if (el.tagName == 'SPAN' || el.tagName == 'DIV') el.parentNode.removeChild(el);
		});
		this.ul = document.createElement('ul'); // reset
		this.fx = new Array();
		this.passed = true;

		for (i = 0; i < this.f.elements.length; i++) {
			el = this.f.elements[i];
			if (el.optional) continue;
			t = el.type; 
			v = el.value;

			labels = el.parentNode.getElementsByTagName('label');
			if (labels.length) n = labels[0].innerHTML.replace(/<.*>/g, ""); // /<[^>]+>/g innerText
			else n = el.name; 

			if (t == 'text' || t == 'password' || t == 'textarea') {
				if (this.isEmpty(v)) { (this.props.lang == 'es') ? this.doError(el, n+' no puede estar vacio') : this.doError(el, n+' cannot be empty'); continue; }
				
				// if (v == el.defaultValue) { (this.props.lang == 'es') ? this.doError(el, n+' no puede usar el valor prefijado') : this.doError(el, n+' cannot use the default value'); continue; }
				
				if (el.isAlpha) {
					if(!this.isAlpha(v)) { (this.props.lang == 'es') ? this.doError(el, n+' solo puede tener caracteres A-Z a-z') : this.doError(el, n+' can only contain characters A-Z a-z'); continue; }
				}
				
				if (el.isNumeric) {
					if(!this.isNumeric(v)) { (this.props.lang == 'es') ? this.doError(el, n+' solo puede tener caracteres 0-9') : this.doError(el, n+' can only contain characters 0-9'); continue; }
				}
				
				if (el.isAlphaNumeric) {
					if(!this.isAlphaNumeric(v)) { (this.props.lang == 'es') ? this.doError(el, n+' solo puede tener caracteres A-Z a-z 0-9') : this.doError(el, n+' can only contain characters A-Z a-z 0-9'); continue; }
				}
				
				if (el.isEmail) {
					if(!this.isEmail(v)) { (this.props.lang == 'es') ? this.doError(el, v+' no es un email v' + unescape('%E1') + 'lido') : this.doError(el, v+' is not a valid email'); continue; }
				}
				
				if (el.isLength != null) {
					var len = el.isLength;
					if (!this.isLength(v, len)) { (this.props.lang == 'es') ? this.doError(el, n+' debe ser solamente '+len+' caracteres') : this.doError(el, n+' must contain only '+len+' characters'); continue; }
				}
				
				if (el.isLengthBetween != null) {
					var min = el.isLengthBetween[0];
					var max = el.isLengthBetween[1];
					if (!this.isLengthBetween(v, min, max)) { (this.props.lang == 'es') ? this.doError(el, n+' no puede tener menos de '+min+' o mas de '+max+' caracteres') : this.doError(el, n+' cannot contain less than '+min+' or more than '+max+' characters'); continue; }
				}
				
				if (el.isPhoneNumber) {
					if (!this.isPhoneNumber(v)) { (this.props.lang == 'es') ? this.doError(el, v+' no es un numero telefonico v' + unescape('%E1') + 'lido') : this.doError(el, v+' is not a valid phone number'); continue; }
				}
				
				if (el.isDate) {
					if (!this.isDate(v)) { (this.props.lang == 'es') ? this.doError(el, v+' no es una fecha v' + unescape('%E1') + 'lida') : this.doError(el, v+' is not a valid date'); continue; }
				}
				
				if (el.isMatch != null) {					
					if (!this.isMatch(v, el.isMatch.value)) { (this.props.lang == 'es') ? this.doError(el, n+' no son iguales') : this.doError(el, n+' does not match'); continue; }
				}
			}
			if (t.indexOf('select') != -1) {
				if (this.isEmpty(el.options[el.selectedIndex].value)) { (this.props.lang == 'es') ? this.doError(el, n+' se necesita una opci' + unescape('%F3') + 'n seleccionada') : this.doError(el, n+' needs an option selected'); continue; }
			}
			
			if (t == 'file') {
				if (this.isEmpty(v)){ (this.props.lang == 'es') ? this.doError(el, n+' se necesita un archivo para ser cargado') : this.doError(el, n+' needs a file to upload'); continue; }
			}			
		}

		if (!this.passed) {
			err = (this.props.lang == 'es') ? 'Por favor corregir los errores indicados' : 'Please correct the errors indicated';
				
			if (this.props.block != false && this.props.inline != 'block') {
				p = document.createElement('p');
				p.appendChild(document.createTextNode(err));	
				
				div = document.createElement('div');
				div.className ='error';		
				div.appendChild(p);
				div.appendChild(this.ul.cloneNode(true));
				
				if (window.fx) {
					o = new fx.Opacity(div, { duration: 1000 });
					o.hide();
					this.fx.push(o);					
				}

				if (this.props.block == 'outside') this.f.parentNode.insertBefore(div, this.f);
				else if (this.props.block == 'top') document.body.insertBefore(div, document.body.firstChild);
				else this.f.insertBefore(div, this.f.firstChild); // inside by default
			}

			if (this.props.inline != false) {
				el = $('submit');
				if (el != null) this.doError(el, err);
			}

			this.fx.each(function(el, i) { el.custom(0, .99); });
		}
		
		return this.passed;
	},

	doError: function(el, err) {
		this.passed = false;

		Element.addClassName(el, 'error');
		
		if (this.props.block != false && this.props.inline != 'block') {
			li = document.createElement('li');
			li.appendChild(document.createTextNode(err));
			this.ul.appendChild(li);
		}
		
		if (this.props.inline != false) {
			if (this.props.inline == 'block') {
				p = document.createElement('p');
				p.appendChild(document.createTextNode(err));	

				div = document.createElement('div');
				div.className = 'error';		
				div.appendChild(p);	
				if (window.fx) {
					o = new fx.Opacity(div, { duration: 1000 });
					o.hide();
					this.fx.push(o);					
				}
				
				el.parentNode.parentNode.insertBefore(div, el.parentNode.nextSibling);
			}
			else {
				span = document.createElement('span');
				span.className = 'error';		
				span.appendChild(document.createTextNode(err));	
					
				if (this.props.inline == 'label') {
					labels = el.parentNode.getElementsByTagName('label');
					if (labels.length) {
						labels[0].style.display = 'none';
						el.parentNode.insertBefore(span, labels[0]);
					}
				}
				else if (this.props.inline == 'span') {
					spans = el.parentNode.getElementsByTagName('span');
					for (s = 0; s < spans.length; s++) {
						if (spans[s].parentNode == el.parentNode) {
							spans[s].style.display = 'none';
							el.parentNode.insertBefore(span, spans[s]);
							break;
						}
					}
				}
				else if (this.props.inline == 'first') el.parentNode.insertBefore(span, el.parentNode.firstChild);
				else if (this.props.inline == 'before') el.parentNode.insertBefore(span, el);
				else if (this.props.inline == 'after') el.parentNode.insertBefore(span, el.nextSibling);
				else el.parentNode.appendChild(span); // last by default

				if (window.fx) {
					o = new fx.Opacity(span, { duration: 1000 });
					o.hide();
					this.fx.push(o);					
				}
			}
		}
	},

	// Regexp by Travis Beckham (http://www.squidfingers.com | http://www.podlob.com)

	isEmpty: function(str) { // returns true if the string is empty
		return (str == null) || (str.length == 0);
	},
	
	isEmail: function(str) { // returns true if the string is a valid email
		if(this.isEmpty(str)) return false;
		var re = /^[^\s()<>@,;:\/]+@\w[\w\.-]+\.[a-z]{2,}$/i;
		return re.test(str);
	},

	isAlpha: function(str) { // returns true if the string only contains characters A-Z or a-z
		var re = /[^a-zA-Z]/g;
		if (re.test(str)) return false;
		return true;
	},
	
	isNumeric: function(str) { // returns true if the string only contains characters 0-9
		var re = /[\D]/g;
		if (re.test(str)) return false;
		return true;
	},

	isAlphaNumeric: function(str) { // returns true if the string only contains characters A-Z, a-z or 0-9
		var re = /[^a-zA-Z0-9]/g;
		if (re.test(str)) return false;
		return true;
	},

	isLength: function(str, len) { // returns true if the string's length equals "len"
		return str.length == len;
	},
	
	isLengthBetween: function(str, min, max) { // returns true if the string's length is between "min" and "max"
		return (str.length >= min)&&(str.length <= max);
	},

	isPhoneNumber: function(str) { // returns true if the string is formatted as (000)000-0000, (000) 000-0000, 000-000-0000, 000.000.0000, 000 000 0000, 0000000000
		var re = /^\(?[2-9]\d{2}[\)\.-]?\s?\d{3}[\s\.-]?\d{4}$/;
		return re.test(str);
	},

	isDate: function(str) { // returns true if the string is formatted as mm dd yyyy, mm/dd/yyyy, mm.dd.yyyy, mm-dd-yyyy
		var re = /^(\d{1,2})[\s\.\/-](\d{1,2})[\s\.\/-](\d{4})$/;
		if (!re.test(str)) return false;
		var result = str.match(re);
		var m = parseInt(result[1]);
		var d = parseInt(result[2]);
		var y = parseInt(result[3]);
		if(m < 1 || m > 12 || y < 1900 || y > 2100) return false;
		if(m == 2) {
			var days = ((y % 4) == 0) ? 29 : 28;
		}
		else if(m == 4 || m == 6 || m == 9 || m == 11) {
			var days = 30;
		}
		else {
			var days = 31;
		}
		return (d >= 1 && d <= days);
	}, 

	isMatch: function(str1, str2) { // returns true if "str1" is the same as the "str2"
		return str1 == str2;
	}
}
