/* Cookies http://www.quirksmode.org/js/cookies.html */
RegExp.escape = function(text) {
  if (!arguments.callee.sRE) {
    var specials = [
      '/', '.', '*', '+', '?', '|',
      '(', ')', '[', ']', '{', '}', '\\'
    ];
    arguments.callee.sRE = new RegExp(
      '(\\' + specials.join('|\\') + ')', 'g'
    );
  }
  return text.replace(arguments.callee.sRE, '\\$1');
}

function createCookie(name,value,days) {
	if (days) {
		var date = new Date();
		date.setTime(date.getTime()+(days*24*60*60*1000));
		var expires = "; expires="+date.toGMTString();
	}
	else var expires = "";
	document.cookie = name+"="+value+expires+"; path=/";
}

function readCookie(name) {
	var nameEQ = name + "=";
	var ca = document.cookie.split(';');
	for(var i=0;i < ca.length;i++) {
		var c = ca[i];
		while (c.charAt(0)==' ') c = c.substring(1,c.length);
		if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
	}
	return null;
}

function eraseCookie(name) {
	createCookie(name,"",-1);
}




_abort_form_submit = false;

function toCurrency(nStr)
{
	nStr += '';
	x = nStr.split('.');
	x1 = x[0];
	x2 = x.length > 1 ? '.' + x[1] : '';
	var rgx = /(\d+)(\d{3})/;
	while (rgx.test(x1)) {
		x1 = x1.replace(rgx, '$1' + ',' + '$2');
	}
	return '$ ' + x1 + x2;
}

function insertAfter(newElement, refElement)
{
	if ( refElement.nextSibling ) {
		refElement.parentNode.insertBefore(newElement, refElement.nextSibling);
	} else {
		refElement.parentNode.appendChild(newElement);
	}
}

function findPos(obj) {
	var curleft = curtop = 0;
	if (obj.offsetParent) {
		curleft = obj.offsetLeft
		curtop = obj.offsetTop
		while (obj = obj.offsetParent) {
			curleft += obj.offsetLeft
			curtop += obj.offsetTop
		}
	}
	return [curleft,curtop];
}

function highlightWords(haystack,needle,prefix,postfix)
{
	var replacements	= new Array();
	var bigregex		= '';
	var words 			= needle.split(' ');
	words.each( function(word) {
		word_regex	= '('+word.replace(/[aá]/gi,'(a|á)').replace(/[eé]/gi,'(e|é)').replace(/[ií]/gi,'(i|í)').replace(/[oó]/gi,'(o|ó)').replace(/[uú]/gi,'(u|ú)').replace(/[nñ]/gi,'(ñ|n)')+')';
		bigregex 	= bigregex ? bigregex+'|'+word_regex : word_regex;
	});

	bigregex = eval('/('+bigregex+')/gi');
	return haystack.replace(bigregex,prefix+'$1'+postfix);
}

Tabletree = {}
Tabletree.hide = function(element)
{
	Element.hide(element);
	
	if ( typeof element.contents != 'undefined' ) {
		
		element.expanded = false;
		Element.removeClassName(element,'expanded');
		
		element.contents.each( function(child) {
			Tabletree.hide(child);
		} );
	}
}

var Rules = {


	/* Collapsable table columns */
	
	/* Initialize togglers */
	'table.vtree td.vtree_toggler': function(element)
	{
		element.originalHTML	= element.innerHTML;
		element.expanded		= true;
		element.targets			= new Array();
		element.style.cursor	= 'w-resize';
		
		element.collapse		= function(use_effect)
		{
			this.expanded		= !this.expanded;
			this.style.cursor	= this.expanded ? 'e-resize' : 'w-resize';
			
			alt = this.getAttribute('alt');
			if ( !alt ) {
				alt = '';
			}
	
			this.innerHTML	= this.expanded ? this.originalHTML : alt;
			var expanded	= this.expanded;
		
			this.targets.each( function(target)
			{
				alt = target.getAttribute('alt');
				if ( !alt ) {
					alt = '';
				}
				target.innerHTML			= expanded ? target.originalHTML : alt;
				element.style.paddingLeft	= expanded ? '10px' : '0';
				
				if ( use_effect ) { 
					new Effect.Highlight(target, {duration: 2});
				}
			});
		}
	},
	
	/* Populate toggler targets */
	'table.vtree td': function(element)
	{
		element.parent	= $(element.getAttribute('parent'));
		if ( element.parent ) {
			element.originalHTML = element.innerHTML;
			element.parent.targets.push(element);
		}
	},
	
	/* Add behavior to togglers */
	'table.vtree td.vtree_toggler:click': function(element)
	{
		element.collapse(true);
	},
	
	/* Collapse pre-collapsed columns */
	'table.vtree td.vtree_toggler.collapsed': function(element)
	{
		element.collapse();
	},


	/* Collapsable table trees */
	'table.tree.expanded tr': function(element)
	{
		element.dont_hide = true;
	},
	
	'table.tree tr': function(element)
	{
		element.parent = $(element.getAttribute('parent'));
		
		if ( element.parent ) {
			
			if ( !Element.hasClassName(element.parent,'expanded') && !element.dont_hide ) {
				element.parent.expanded = false;
				Element.hide(element);
			} else {
				element.parent.expanded = true;
				Element.addClassName(element.parent,'expanded');
			}

			if ( typeof element.parent.contents == 'undefined' ) {
				element.parent.contents = new Array();
			}

			element.parent.contents.push(element);
		}
		
		if ( Element.hasClassName(element, 'tree_toggler') ) {
			element.onclick = function() {

				this.expanded 		= !this.expanded;

				if ( this.expanded ) {
					Element.addClassName(this,'expanded');
				} else {
					Element.removeClassName(this,'expanded');
				}

				if ( !this.contents ) {
					return;
				}

				var ctr_expanded	= this.expanded;
				this.contents.each( function(child) {

					if ( ctr_expanded ) {		/* Expand: show inmediate children */
						Element.show(child);
					} else {					/* Collapse: recursively hide all children */
						Tabletree.hide(child);
					}
				
				} );

			}
		}
	},


	/* Disabled textareas */
	'textarea.disabled:keypress': function(element,event)
	{
		event.preventDefault();
	},

	/* AJAX finder */
	'input.finder': function (element)
	{	
		element.action				= element.getAttribute('action');
		element.curPage				= 1;
	
		if ( !element.action ) {
			return;
		}

		/* Function to convert result records to panel elements */
		element.createResult		= function(record, query)
		{
			var obj					= document.createElement('DIV');
			obj.className			= 'result';
			
			obj.basevalue			= '';
			for ( property in record ) {
				obj.basevalue		+= property+': '+record[property]+', ';
			}
			
			
			regexp					= eval('/'+RegExp.escape(query.replace(/[aá]/gi,'(a|á)').replace(/[eé]/gi,'(e|é)').replace(/[ií]/gi,'(i|í)').replace(/[oó]/gi,'(o|ó)').replace(/[uú]/gi,'(u|ú)').replace(/[nñ]/gi,'(ñ|n)'))+'/gi');
			var matches				= obj.basevalue.match(regexp);			
			if ( matches ) {			
				for ( var c=0; c < matches.length; c++) {
					var string		= matches[c];
					obj.basevalue	= obj.basevalue.replace(string,'<span class="match">'+string+'</span>');
				}			
			}
			obj.innerHTML			= obj.basevalue;
			
			obj.onmouseover			= function()
			{
				if ( element.resultsPane.currentResult ) {
					Element.removeClassName(element.resultsPane.currentResult,'active');
				}
			
				element.resultsPane.currentResult = this;
				Element.addClassName(this,'active');
			}
			
			obj.onmouseout			= function()
			{
				element.resultsPane.currentResult = null;
				Element.removeClassName(this,'active');
			}
			
			obj.onclick				= function()
			{
				element.value = this.basevalue;
			}
			
			return obj;
		}


		/* Create the results container directly under the textfield */
		var results					= document.createElement('DIV');
		results.className			= 'finder_results';
		results.style.display		= 'none';
		results.style.position		= 'absolute';
		results.style.zIndex		= 1500;
		results.style.width			= (element.offsetWidth-2)+'px';
		pos							= findPos(element);
		results.style.top			= (pos[1]+element.offsetHeight)+'px';
		results.style.left			= pos[0]+'px';
		
		results.currentResult		= null;

		/* Clear the results pane contents */
		results.clear	= function() {
			this.currentResult = null;
			Element.hide(this);
			this.innerHTML = '';
			_abort_form_submit = false;
		}

		/* Populate all given results into results pane */
		results.populate	= function(results, query) {

			this.innerHTML		= '';
			this.currentResult	= null;
			
			var count		= 0;
			
			results.each(function(result) {
			
				if ( typeof result == 'undefined' ) {
					return;
				}
				
				element.resultsPane.appendChild( element.createResult(result, query) );
				count++;
			});
			
			if ( count == 1 ) {
				element.resultsPane.currentResult	= element.resultsPane.firstChild;
				Element.addClassName(element.resultsPane.currentResult,'active');
			}

			/* Relocate and display */
			if ( count > 0 ) {
				pos						= findPos(element);
				this.style.top			= (pos[1]+element.offsetHeight)+'px';
				this.style.left			= pos[0]+'px';			
				Element.removeClassName(element,'empty');
				Element.show(this);
			} else {
				this.clear();
				Element.addClassName(element,'empty');
			}
		}

		insertAfter(results,element);

		element.resultsPane			= results;

		element.run					= function(element,event)
		{
			res = element.resultsPane;

			if ( event.keyCode == 13 && res.currentResult ) { /* Hit enter */

				res.currentResult.onclick();
				res.clear();

			} else if ( event.keyCode == 46 && res.currentResult ) { /* Hit SUPR */
			
				if ( res.currentResult.ondelete ) {
					res.currentResult.ondelete();
				}
				res.clear();
			
			} else if (element.value.length >= 2 && event.keyCode != 40 && event.keyCode != 38) {	/* Perform search */

				new Ajax.Request(element.action,{
					parameters: 'q='+element.value,
					onComplete: function(req) {
						results = eval(req.responseText);
						res.populate(results, element.value);
					}
				});

			} else if ( event.keyCode == 40 ) {	/* Hit down key*/

				if (!res.currentResult) {
					res.currentResult = res.firstChild;
					Element.addClassName(res.currentResult, 'active');
					return false;
				}
				
				/* Down key on last element. Perform search again, using next page */
				if (res.currentResult == res.lastChild) {

					element.curPage++;
					new Ajax.Request(element.action,{
						parameters: 'q='+element.value+'&page='+element.curPage,
						onComplete: function(req) {
							results = eval(req.responseText);
							res.populate(results, element.value);
							res.currentResult = res.firstChild;
							Element.addClassName(res.currentResult, 'active');							
						}
					});

					return false;
				}

				Element.removeClassName(res.currentResult, 'active')
				res.currentResult = res.currentResult.nextSibling;
				Element.addClassName(res.currentResult, 'active');
				return false;

			} else if ( event.keyCode == 38 ) {	/* Hit up key */

				if (!res.currentResult) {
					res.currentResult = res.lastChild;
					Element.addClassName(res.currentResult, 'active');
					return false;
				}

				/* Up key on first child */
				if ( res.currentResult == res.firstChild ) {
					
					element.curPage--;
					element.curPage = Math.max(element.curPage,1);
					
					new Ajax.Request(element.action,{
						parameters: 'q='+element.value+'&page='+element.curPage,
						onComplete: function(req) {
							results = eval(req.responseText);
							res.populate(results, element.value);
							res.currentResult = res.lastChild;
							Element.addClassName(res.currentResult, 'active');							
						}
					});				
					return false;
				
				}

				Element.removeClassName(res.currentResult, 'active')
				res.currentResult = res.currentResult.previousSibling;
				Element.addClassName(res.currentResult, 'active');
				return false;

			} else {
				res.clear();
			}

		}		
	},

	'input.finder:keyup': function (element,event)
	{
		if ( !element.getAttribute('action') ) {
			return;
		}

		element.run(element,event);
	},

	'input.finder:keypress': function (element,event)
	{
		_abort_form_submit = event.keyCode == 13;
	},



	/* Observation finder */
	'select.observations:keypress': function(element,event)
	{
		if ( event.keyCode == 46 ) {
			element.remove(element.selectedIndex);
		}
	},

	'input.observation.finder': function(element)
	{
		var objfor					= $(element.getAttribute('for'));
		if ( !objfor ) {
			return;
		}

		/* Function to convert result records to panel elements */
		element.createResult		= function(record, query)
		{
			var obj					= document.createElement('DIV');
			obj.basevalue			= record.text;
			obj.className			= 'result';
			
			regexp					= eval('/'+RegExp.escape(query)+'/gi');
			obj.innerHTML			= record.text.replace(regexp, '<span class="match">'+query+'</span>');
			
			obj.onmouseover			= function()
			{
				if ( element.resultsPane.currentResult ) {
					Element.removeClassName(element.resultsPane.currentResult,'active');
				}
			
				element.resultsPane.currentResult = this;
				Element.addClassName(this,'active');
			}
			
			obj.onmouseout			= function()
			{
				element.resultsPane.currentResult = null;
				Element.removeClassName(this,'active');
			}
			
			obj.onclick				= function()
			{
				if (objfor.tagName == 'SELECT') {
					
					for(c=0; c < objfor.length; c++) {
						if (objfor.options[c].value == this.basevalue) {
							element.resultsPane.clear();
							element.value = '';
							return;
						}
					}
					
					var noption			= document.createElement('OPTION');
					noption.value		= this.basevalue;
					noption.innerHTML	= this.basevalue;
					objfor.appendChild(noption);
				} else {
					regexp = eval('/'+RegExp.escape(this.basevalue)+'/gi');
					if ( !objfor.value.match(regexp) ) {
						objfor.value += objfor.value ? '\n'+this.basevalue : this.basevalue;
					}
				}

				element.resultsPane.clear();
				element.value = '';
			}
			
			obj.ondelete			= function()
			{
				regexp = eval('/'+RegExp.escape(this.basevalue)+'\\n?/gi');
				objfor.value = objfor.value.replace(regexp,'');
				element.resultsPane.clear();
				element.value = '';
			}

			return obj;
		}
	},

	/* Student finder */
	'input.person.finder': function(element)
	{
		var doredirect					= element.getAttribute('redirect') == 1;
	
		if ( !doredirect ) {
			/* Create the hidden form field to store the selected id */
			var field					= document.createElement('INPUT');
			field.name					= element.name+'_id';
			field.type					= 'hidden';
			field.value					= element.getAttribute('default');
			element.parentNode.appendChild(field);
			element.dataField			= field;
		}

		/* Function to convert result records to panel elements */
		element.createResult		= function(record, query)
		{
			var obj					= document.createElement('DIV');
			obj.basevalue			= record.fullname;
			obj.className			= 'person result';
			
			obj.data				= record;

			var fullname			= highlightWords(record.fullname,query,'<span class="match">','</span>');
			var code				= record.code.replace(eval('/('+RegExp.escape(query)+')/gi'), '<span class="match">$1</span>');

			obj.innerHTML			= '<img src="'+record.thumbnail+'" />';
			obj.innerHTML			+= '<h2>'+fullname+'</h2>';
			obj.innerHTML			+= '<div class="code"><span class="label">'+obj.data.typename+':</span> <span class="value">'+code+'</span></div>';

			obj.onmouseover			= function()
			{
				if ( element.resultsPane.currentResult ) {
					Element.removeClassName(element.resultsPane.currentResult,'active');
				}
			
				element.resultsPane.currentResult = this;
				Element.addClassName(this,'active');
			}
			
			obj.onmouseout			= function()
			{
				element.resultsPane.currentResult = null;
				Element.removeClassName(this,'active');
			}
			
			obj.onclick				= function()
			{
				/* Check if element has an onchoose declaration */
				var callback = element.getAttribute('callback');
				if ( callback ) {
					eval(callback+'(this.data)');
					return;
				}

				if ( doredirect ) {
					window.location = this.data.href;
				} else {
					element.dataField.value = this.data.id;
					element.resultsPane.clear();
					element.value = this.basevalue;
				}
			}

			return obj;
		}
	},

	'input.ads.finder': function(element)
	{
		var doredirect					= element.getAttribute('redirect') == 1;


		/* Function to convert result records to panel elements */
		element.createResult		= function(record, query)
		{
			var obj					= document.createElement('DIV');
			obj.basevalue			= record.title;
			obj.className			= 'ad result';

			obj.data				= record;

			var title			= highlightWords(record.title,query,'<span class="match">','</span>');
			var fullname				= record.fullname.replace(eval('/('+RegExp.escape(query)+')/gi'), '<span class="match">$1</span>');

			obj.innerHTML			= '<img src="'+record.thumbnail+'" />';
			obj.innerHTML			+= '<h2>'+title+'</h2>';
			obj.innerHTML			+= '<div class="code"><span class="label">'+obj.data.label+':</span> <span class="value">'+fullname+'</span></div>';

			obj.onmouseover			= function()
			{
				if ( element.resultsPane.currentResult ) {
					Element.removeClassName(element.resultsPane.currentResult,'active');
				}

				element.resultsPane.currentResult = this;
				Element.addClassName(this,'active');
			}

			obj.onmouseout			= function()
			{
				element.resultsPane.currentResult = null;
				Element.removeClassName(this,'active');
			}

			obj.onclick				= function()
			{
				/* Check if element has an onchoose declaration */
				var callback = element.getAttribute('callback');
				if ( callback ) {
					eval(callback+'(this.data)');
					return;
				}

				if ( doredirect ) {
					window.location = this.data.href;
				} else {
					element.dataField.value = this.data.id;
					element.resultsPane.clear();
					element.value = this.basevalue;
				}
			}

			return obj;
		}
	},

	/* Caller finder */
	'input.caller.finder': function(element)
	{
		var doredirect					= element.getAttribute('redirect') == 1;
	
		if ( !doredirect ) {
			/* Create the hidden form field to store the selected id */
			var field					= document.createElement('INPUT');
			field.name					= element.name+'_id';
			field.type					= 'hidden';
			element.parentNode.appendChild(field);
			element.dataField			= field;
		}

		/* Function to convert result records to panel elements */
		element.createResult		= function(record, query)
		{
			var obj					= document.createElement('DIV');
			obj.basevalue			= record.fullname;
			obj.className			= 'person result';
			
			obj.data				= record;
			
			regexp					= eval('/'+RegExp.escape(query.replace(/[aá]/gi,'(a|á)').replace(/[eé]/gi,'(e|é)').replace(/[ií]/gi,'(i|í)').replace(/[oó]/gi,'(o|ó)').replace(/[uú]/gi,'(u|ú)').replace(/[nñ]/gi,'(ñ|n)'))+'/gi');
			var fullname			= record.fullname;
			var matches				= fullname.match(regexp);			
			if ( matches ) {			
				for ( var c=0; c < matches.length; c++) {
					var string			= matches[c];
					fullname			= fullname.replace(string,'<span class="match">'+string+'</span>');
				}			
			}
			

			obj.innerHTML			= '<img src="'+record.thumbnail+'" />';
			obj.innerHTML			+= '<h2>'+fullname+'</h2>';
			obj.innerHTML			+= '<div class="code"><span class="label">Tel:</span> <span class="value">'+obj.data.phone+'</span></div>';
			obj.innerHTML			+= '<div class="code"><span class="label">Cel:</span> <span class="value">'+obj.data.mobile+'</span></div>';

			obj.onmouseover			= function()
			{
				if ( element.resultsPane.currentResult ) {
					Element.removeClassName(element.resultsPane.currentResult,'active');
				}
			
				element.resultsPane.currentResult = this;
				Element.addClassName(this,'active');
			}
			
			obj.onmouseout			= function()
			{
				element.resultsPane.currentResult = null;
				Element.removeClassName(this,'active');
			}
			
			obj.onclick				= function()
			{
				/* Check if element has an onchoose declaration */
				var callback = element.getAttribute('callback');
				if ( callback ) {
					eval(callback+'(this.data)');
					return;
				}

				if ( doredirect ) {
					window.location = this.data.href;
				} else {
					element.dataField.value = this.data.id;
					element.resultsPane.clear();
					element.value = this.basevalue;
				}
			}

			return obj;
		}
	},


	/* Academic finder */
	'input.academic.finder': function(element)
	{
		var doredirect					= element.getAttribute('redirect') == 1;
	
		if ( !doredirect ) {
			/* Create the hidden form field to store the selected id */
			var field					= document.createElement('INPUT');
			field.name					= element.name+'_id';
			field.type					= 'hidden';
			field.value					= element.getAttribute('default');
			element.parentNode.appendChild(field);
			element.dataField			= field;
		}

		/* Function to convert result records to panel elements */
		element.createResult		= function(record, query)
		{
			var obj					= document.createElement('DIV');
			obj.className			= 'academic result';
			
			obj.data				= record;


			var fullname			= highlightWords(record.subject+' '+record.course,query,'<span class="match">','</span>');
			var groupname			= highlightWords(record.group,query,'<span class="match">','</span>');

			obj.innerHTML			+= '<h2>'+fullname+'</h2>';
			obj.innerHTML			+= '<div class="group"><strong>Grupo:</strong> <span class="value">'+groupname+'</span></div>';

			obj.onmouseover			= function()
			{
				if ( element.resultsPane.currentResult ) {
					Element.removeClassName(element.resultsPane.currentResult,'active');
				}
			
				element.resultsPane.currentResult = this;
				Element.addClassName(this,'active');
			}
			
			obj.onmouseout			= function()
			{
				element.resultsPane.currentResult = null;
				Element.removeClassName(this,'active');
			}
			
			obj.onclick				= function()
			{
				/* Check if element has an onchoose declaration */
				var callback = element.getAttribute('callback');
				if ( callback ) {
					eval(callback+'(this.data)');
					return;
				}

				if ( doredirect ) {
					window.location = this.data.href;
				} else {
					element.dataField.value = this.data.id;
					element.resultsPane.clear();
					element.value = this.basevalue;
				}
			}

			return obj;
		}
	},



	'.finder_setting:click': function(element,event)
	{
		var finder = $(element.getAttribute('for'));		
		if ( finder ) {
			finder.action = element.getAttribute('action');
			finder.run(finder,event);
			
			$$('.finder_setting.active').each( function(thingy) {
				Element.removeClassName(thingy,'active');
			} );
			
			Element.addClassName(element,'active');
		}
	},


	'input.finder_setting:click': function(element,event)
	{
		var finder = $(element.getAttribute('for'));		
		if ( finder ) {
			finder.action = element.value;
			finder.run(finder,event);
		}
	},


	/* Student finder */
	'input.student.finder': function(element)
	{
		/* Create the hidden form field to store the selected id */
		var field					= document.createElement('INPUT');
		field.name					= element.name+'_id';
		field.type					= 'hidden';
		element.parentNode.appendChild(field);
		element.dataField			= field;
	
		/* Function to convert result records to panel elements */
		element.createResult		= function(record, query)
		{
			var obj					= document.createElement('DIV');
			obj.basevalue			= record.fullname;
			obj.className			= 'person result';
			
			obj.person_id			= record.id;
			
			regexp					= eval('/'+RegExp.escape(query.replace(/[aá]/gi,'(a|á)').replace(/[eé]/gi,'(e|é)').replace(/[ií]/gi,'(i|í)').replace(/[oó]/gi,'(o|ó)').replace(/[uú]/gi,'(u|ú)').replace(/[nñ]/gi,'(ñ|n)'))+'/gi');
			var fullname			= record.fullname;
			var matches				= fullname.match(regexp);			
			if ( matches ) {			
				for ( var c=0; c < matches.length; c++) {
					var string			= matches[c];
					fullname			= fullname.replace(string,'<span class="match">'+string+'</span>');
				}			
			}

			obj.innerHTML			= '<img src="'+record.thumbnail+'" />';
			obj.innerHTML			+= '<h2>'+fullname+'</h2>';
			obj.innerHTML			+= '<span class="course">'+record.course+'</span>';

			obj.onmouseover			= function()
			{
				if ( element.resultsPane.currentResult ) {
					Element.removeClassName(element.resultsPane.currentResult,'active');
				}
			
				element.resultsPane.currentResult = this;
				Element.addClassName(this,'active');
			}
			
			obj.onmouseout			= function()
			{
				element.resultsPane.currentResult = null;
				Element.removeClassName(this,'active');
			}
			
			obj.onclick				= function()
			{	
				element.dataField.value = this.person_id;
				element.resultsPane.clear();
				element.value = this.basevalue;
			}

			return obj;
		}
	},




	/* Secure passwords */
	'input.secure': function(element)
	{
		var notice			= document.createElement('SPAN');
		notice.className	= 'notice';
		element.notice		= notice;
		insertAfter(notice,element);
	},
	
	'input.secure:keyup': function(element)
	{
	
		var prefix = '<span class="red">Contraseña Insegura: </span>';
	
		if ( !element.value ) {
			element.notice.innerHTML = '';
			return;
		}
	
		if ( element.value.length < 6 ) {
			element.notice.innerHTML = prefix+'La contraseña es demasiado corta';
			return;
		}
	
		if ( !element.value.match(/[a-z]/) ) {
			element.notice.innerHTML = prefix+'Incluya al menos una letra minúscula';
			return;
		}
	
		if ( !element.value.match(/[A-Z]/) ) {
			element.notice.innerHTML = prefix+'Incluya al menos una letra mayúscula';
			return;
		}
	
		if ( !element.value.match(/[0-9]/) ) {
			element.notice.innerHTML = prefix+'Incluya al menos un número';
			return;
		}
	
		element.notice.innerHTML = '<span class="green">Contraseña segura </span>';	
	},

	/* Sortables */
	'.sortable': function(element)
	{
		var tag		= element.getAttribute('tag');
		if ( !tag ) {
			tag = 'li';
		}
		
		var handle	= element.getAttribute('handle');
		if ( !handle ) {
			handle = false;
		}		
		
		var action	= element.getAttribute('action');

		if ( action ) {
			Sortable.create(element, {tag:tag,handle:handle,onUpdate: function(srt)
			{
				new Ajax.Request(action, {
					parameters:Sortable.serialize(srt, {name:'sorted'})
				});
			}});
		} else {
			Sortable.create(element, {tag:tag,handle:handle});
		}
	},

	/* Jump to date */
	'.datejump': function(element)
	{
		var action;
		var varname;
		var format;
	
		if ( !(action = element.getAttribute('action')) ) {
			return;
		}
		
		if ( !(varname = element.getAttribute('varname')) ) {
			varname = 'date';
		}

		if ( !action.match(/\/$/) ) {
			varname = '&'+varname;
		}

		if ( !(format = element.getAttribute('format')) ) {
			format = '%s';
		}

		if ( !element.id ) {
			element.id = 'jumper_'+varname;
		}

		var button			= document.createElement('BUTTON');
		button.className	= 'datepicker';
		button.id			= element.id+'_button';
		insertAfter(button,element);
		
		Calendar.setup({
			//date		   : element.innerHTML,
			button         : button.id,
			singleClick    : true,
			onSelect	   : function(cal) {
				if (cal.dateClicked) {
					window.location = action+varname+'='+cal.date.print(format);
				}
			}			
		});		
	},


	/* Sumatory fields */
	'input.expense': function(element)
	{
		var a = document.createElement('A');
		a.href = '#';
		a.innerHTML = '$ ';
		a.expense = element;
		a.onclick = function()
		{
			this.expense.value = parseInt(this.expense.getAttribute('max'));
			this.expense.funds.rebuild(this.expense.funds);
			return false;
		}
		element.parentNode.insertBefore(a, element);
	},

	'a.expense_ignorer': function(element)
	{
		var expense_id = element.getAttribute('expense');
		if ( !expense_id ) {
			return;
		}
		
		element.expense	= $(expense_id);
		element.checked	= false;
	},

	'a.expense_ignorer:click': function(element, event)
	{
		element.checked = !element.checked;
	
		if ( element.checked ) {
			element.style.textDecoration = 'line-through';
			element.expense.value = 0;
			element.expense.onkeyup();
			element.expense.disable();
		} else {
			element.style.textDecoration = 'none';
			element.expense.enable();
		}
		
		Event.stop(event);		
	},

	'input.funds': function(element)
	{
		/* Identify and setup all expense items */
		element.expenses	= new Array();
		$A(document.getElementsByClassName('expense')).each( function(candidate)
		{
			if (candidate.getAttribute('funds') == element.id) {
				
				
				/* Preload expene remainder labels */
				candidate.remainders	= new Array();
				$A(document.getElementsByClassName('expense_remainder')).each( function(elem)
				{
					if (elem.getAttribute('expense') == candidate.id) {
						candidate.remainders.push(elem);
					}
				});

				candidate.funds		= element;

				candidate.onkeyup = function()
				{
					if ( !parseInt(this.value) ) {
						this.value = 0;
					}

					var maxvalue	= parseInt(this.getAttribute('max'));
					if (this.value > maxvalue) {
						this.value = maxvalue;
					}

					this.funds.rebuild(this.funds);
				}

				element.expenses.push(candidate);

			}
		});

		/* Identify and setup all remainder (info) items */
		element.labels	= new Array();
		$A(document.getElementsByClassName('funds_remainder')).each( function(candidate)
		{
			if (candidate.getAttribute('for') == element.id) {
				element.labels.push(candidate);
			}
		});

		/* Identify and setup all remainder (info) items */
		element.spent	= new Array();
		$A(document.getElementsByClassName('funds_spent')).each( function(candidate)
		{
			if (candidate.getAttribute('for') == element.id) {
				element.spent.push(candidate);
			}
		});

		element.rebuild	= function(funds)
		{
			/* Clear subtotal labels */
			$A(document.getElementsByClassName('funds_subtotal')).each(function(subtotal)
			{
				subtotal.value = 0;
			});
			
			/* Reconfigure expense's values */
			var available		= parseInt(funds.getAttribute('total'));
			var total_spent		= 0;

			funds.expenses.each( function(expense) {
				var exp_value	= Math.min(parseInt(expense.value),parseInt(expense.getAttribute('max')),available);
				expense.value	= exp_value;
				total_spent		+= exp_value;
				available		-= exp_value;

				/* Update remainders */
				expense.remainders.each( function(elem)
				{
					elem.innerHTML = toCurrency( expense.getAttribute('max') - exp_value );
				});

				/* Update totalizers */
				if (total = $(expense.getAttribute('totalizer'))) {
					total.value	+= exp_value;
				}
			} );
			
			/* Update remainder labels */
			funds.value	= available;
			funds.labels.each( function(label)
			{
				label.innerHTML = toCurrency(funds.value);
			});

			/* Update spent labels */
			funds.spent.each( function(label)
			{
				label.innerHTML = toCurrency(total_spent);
				if (subtract = $(label.id+'_minus')) {
					subtract.innerHTML = toCurrency(subtract.getAttribute('value')-total_spent);
				}
			});

			/* Update subtotal labels */
			$A(document.getElementsByClassName('funds_subtotal')).each(function(subtotal)
			{
				subtotal.innerHTML = toCurrency(subtotal.value);
				if ( subtract = $(subtotal.id+'_minus') ) {
					subtract.innerHTML = toCurrency(subtract.getAttribute('value') - subtotal.value);
				}
			});
		},

		element.distribute = function(funds)
		{
			var available		= parseInt(funds.getAttribute('total'));
			funds.expenses.each( function(expense) {
				expense.value	= Math.min(parseInt(expense.getAttribute('max')),available);
			} );
			funds.rebuild(funds);
		}
	},

	/* Master checkboxes */
	'input[type=checkbox].master:click': function(element)
	{
		var classname = element.getAttribute('for');
		if (!classname) {
			return;
		}

		$A(document.getElementsByClassName(classname)).each(function(target)
		{
			if (target.tagName != 'INPUT' && target.type != 'CHECKBOX') {
				return;
			}

			target.checked = element.checked;
		});
	},

	/* Tooltips */
	'.tooltip': function(element)
	{
		var target = element.getAttribute('for');
		if (!target || !(target = $(target))) {
			return;
		}

		Element.hide(element);
		element.style.position	= 'absolute';
		
		target.tooltip			= element;
		Element.addClassName(target,'tooltipped');

		target.onmouseover		= function()
		{
			Element.show(this.tooltip);
		}

		target.onmouseout		= function()
		{
			Element.hide(this.tooltip);
		}

		target.onmousemove		= function(event)
		{
			this.tooltip.style.top	= 5+Event.pointerY(event)+'px';
			this.tooltip.style.left	= -120+Event.pointerX(event)+'px';
		}
	},


	/* Input buttons */
	'input[type=submit]:click': function(element) {
		
		if ( element.getAttribute('type') != 'submit' || _abort_form_submit ) {
			return;
		}
		
		element.originalValue	= element.value;
		element.value			= 'Enviando...';
		Element.addClassName(element,'sending');
	},

	/* Prevent multiple submissions */	
	'form': function(form)
	{
		if ( typeof form.onsubmit != 'undefined' ) {
			form.originalonsubmit	= form.onsubmit;
		} else {
			form.originalonsubmit 	= false;
		}
	
		if ( typeof form.onbeforesubmit == 'undefined' ) {
			form.onbeforesubmit = form.getAttribute('onbeforesubmit');
		}	
	
		form.onsubmit = function(event)
		{
			if ( form.onbeforesubmit && !eval(form.onbeforesubmit) ) {
				return false;
			}		
		
			if (_abort_form_submit) {
				return false;
			}
			
			if ( form.originalonsubmit && !form.originalonsubmit() ) {
				return false;
			}
			
			if (this.submitting) {
				return false;
			}
			this.submitting = true;
		}
	},


	/* Validate forms */
	'form.validable': function(element)
	{
		element.onsubmit = function() {

			/* ONLY SUBMIT ONCE */
			if (this.submitting) {
				return false;
			}
			this.submitting = true;

			/* Clear all errors */
			$A(document.getElementsByClassName('error')).each(function(err){
				err.parentNode.removeChild(err);
			});

			new Ajax.Request(this.action,{
				parameters: Form.serialize(this),
				onComplete: function(req) {
					response	= eval(req.responseText);

					if (response.location) {
						window.location = response.location;
						return false;
					}

					for ( var i in response) {
						input = document.getElementsByName(i)[0];
						if (input) {
							var addme			= document.createElement('SPAN');
							addme.className		= 'error';
							addme.innerHTML		= response[i];
							input.error			= addme;	
							input.parentNode.appendChild(addme);

							input.onfocus		= function()
							{
								if (this.error) {
									this.error.parentNode.removeChild(this.error);
									this.error	= false;
								}
							}
						}
					}

					/* Reactivate form and input buttons */
					element.submitting = false;
					$A(element.getElementsByTagName('INPUT')).each(function(input){
						if (input.type == 'submit') {
							Element.removeClassName(input,'sending');
							if (input.originalValue){
								input.value = input.originalValue;
							}
						}
					});
				
				}
			});

			return false;
		}
	},

	/* Spell out currency values */
	'input.currency': function(element)
	{
		var span			= document.createElement('SPAN');
		span.className		= 'notice';
		element.parentNode.appendChild(span);
		element.textspan	= span;
	},

	'input.currency:keyup': function(element,event)
	{
		new Ajax.Request(element.getAttribute('action'), {
			parameters: 'v='+element.value,
			onComplete: function(req) {
				element.textspan.innerHTML = req.responseText;
			}
		});
	},


	/* Calendars */
	'input.date': function(element)
	{
		if ( element.alreadyLoaded ) {
			return;
		}
		element.alreadyLoaded = true;
		
		element.setAttribute('readonly',1);

		if (!element.id) {
			element.id		= element.getAttribute('name');
		}

		element.format		= element.getAttribute('format');
		if (!element.format)	{
			element.format	= '%d/%m/%Y';
		}

		element.time		= element.getAttribute('time') ? true : false;

		var button			= document.createElement('BUTTON');
		button.className	= 'datepicker';
		button.id			= element.id+'_button';
		//element.parentNode.appendChild(button);
		insertAfter(button,element);

		Calendar.setup({
			inputField     : element.id,
			ifFormat       : element.format,
			button         : button.id,
			singleClick    : true,
			showsTime	   : element.time
		});
	},
	
	/* Grade calculator */
	'.gradecalc': function(element)
	{
		var avg = $(element.getAttribute('avg'));
		if ( !avg ) {
			return;
		}

		if ( typeof avg.grades == 'undefined' ) {
			avg.grades = new Array();
		}

		avg.grades.push(element);
		avg.value = 0;

		avg.calculate = function(avg) {
			
			var sum			= 0;
			var sum_weight	= 0;
			
			for ( var cnt = 0; cnt < avg.grades.length; cnt++) {				
				
				var weight	= parseInt(avg.grades[cnt].getAttribute('weight')||1);
				var value	= avg.grades[cnt].tagName == 'TD' ? avg.grades[cnt].getAttribute('value') : avg.grades[cnt].value;
				
				if ( value == '' ) {
					continue;
				}

				value		= parseFloat(value.replace(/,/g,'.').replace(/[^0-9.]/g,''));
				sum			+= value*weight;
				sum_weight	+= weight;
			}

			var result		= sum_weight > 0 ? sum/sum_weight : '';

			avg.value		= Grade.adjust(result);
			avg.innerHTML	= Grade.display(result);
			avg.setAttribute('value', result);
			
			/* Cascade */
			if ( typeof avg.avg != 'undefined' ) {
				avg.avg.calculate(avg.avg);
			}
		}
		
		element.avg = avg;
	},

	'input.gradecalc:keyup': function(element)
	{
		if ( typeof element.avg == 'undefined' ) {
			return;
		}
		element.avg.calculate(element.avg);
	},

	'select.gradecalc:change': function(element)
	{
		if ( typeof element.avg == 'undefined' ) {
			return;
		}
		element.avg.calculate(element.avg);
	},
	
	/* TABSETS */
	'.tabpane': function(element)
	{
		var cookiename 	= 'tabpane_current'+element.id;
		var tallest_tab	= 0;
		
		/* Go throug each tab removing titles and create the tab list */
		var tablist	= document.createElement('UL');
		tablist.className	= 'tablist';
		
		var tabwrapper = document.createElement('DIV');
		tabwrapper.className = 'tabwrapper';
		tabwrapper.appendChild(tablist);
		
		var isfirst = true;
		
		/* Pre-select the currently open tab */
		var current_tab = window.location.hash.replace('#','') || readCookie(cookiename);
		
		element.select('.tab').each( function(tab) {
			
			tallest_tab = Math.max(tallest_tab,tab.offsetHeight);
			
			tab.tabpane			= element;
			var tabh1			= tab.select('.tabname')[0];
			
			var tabitem			= document.createElement('LI');
			
			var anchorname		= tabh1.innerHTML.replace(/[^a-zA-Z0-9]/g,'').toLowerCase();
			
			tabitem.innerHTML	= '<a class="'+tabh1.className+'" href="#'+anchorname+'" onclick="blur()">'+tabh1.innerHTML+'</a>';

			/* Append the tabnotice item, if any */
			var tabnotices = tab.select('.tabnotice')
			if ( tabnotices.length == 1 ) {
				var tabnotice = tabnotices[0]
				tabitem.innerHTML = '<span class="tabnotice">'+tabnotice.innerHTML+'</span>'+tabitem.innerHTML
				tabnotice.remove()
			}
			
			tabitem.tab			= tab;
			tabitem.anchorname	= anchorname;
			
			Element.removeClassName(tabitem,'tabname');
			
			tabitem.onclick		= function() {
				this.tab.tabpane.select('.tab').each( function(tab) {
					tab.hide();
				});
				this.tab.show();
				
				Element.childElements(this.tab.tabpane.tablist).each( function(tab) {
					Element.removeClassName(tab,'active');
				} );
				Element.addClassName(this, 'active');

				createCookie(cookiename, this.anchorname, 1);
			}
			
			tablist.appendChild(tabitem);
			
			tabh1.remove();

			if ( (!current_tab && isfirst) || current_tab == anchorname ) {
				Element.addClassName(tabitem,'active');
			} else {
				tab.hide();
			}
			
			isfirst = false;
			
			element.tablist = tablist;
		} );

		if ( tallest_tab ) { 
			element.style.height = tallest_tab+'px';
		}

		element.insert({top: tabwrapper});
	}

}


Event.observe(window, 'load', function() {
  /* Manually add virtual table ruler, as to avoid the mess specified in the rules */
  $A(document.getElementsByTagName('TR')).each(function(row)
  {
  	if ( Element.hasClassName(row,'notice') ) {
  		return;
  	}

  	row.onmouseover = function() {
  		Element.addClassName(this,'hover');
  	}

  	row.onmouseout = function() {
  		Element.removeClassName(this,'hover');
  	}

  	row.onclick = function() {
  		Element.toggleClassName(this,'clicked');
  	}
  });

	EventSelectors.start(Rules);  
});