/*############################################################################
# LEGAL:
# All technical material (specificaly the PHP, CSS, JS, code documentation, 
# configs and htaccess) in this website was indepentantly created by 
# Owen Beresford, with his own resources.
# The page structure and template system is an original work of Owen Beresford, 
# designed indepentantly with his own resources.
# All this was built without reference to any companies intellectual property.
#  
# All this is released for general use in websites under the terms of the 
# perl artistic licence.
# The complete terms of this licence may be found at
# http://dev.perl.org/perl6/rfc/346.html
# or typing
# `man perlartistic'
# in a any usefull shell.
#############################################################################*/
/* Library to validate forms based on 'validate' attribute of form items
 *
	ALL form items must have an id as well as a name
 
	min-length
	max-length
	regex
	callback * run JS function
			* this function should return false, 
			* or the buffer with any relevent modifications
	
	selected * not empty, for select boxes
	pure-numeric
	no-whitespace
	pure-alpha
	pure-text * letters and white space
	pure-char * \w only with '
	upper
	lower
	trim
	md5

	to suppress client-side validation, inject this into the JS engine
    window.validation_suppression
*/


function validate_form($id) 
{{{
	var $form			=document.forms[$id];
	window.log_buffer	=1;
	if(window.validation_suppression)		{ return true;}
	var $good			=true;
	for(var $i in $form) 
	{
		$skip			=false;
		$wipe			=false;
		
		if(typeof $form[$i] != 'object'){ continue; }
		try								{ var $waste=$form[$i].id; }
		catch(e)						{ $skip=true; }
		if($skip)						{ continue; }
		if(typeof $form[$i].id !='string') {continue; }
		if($form[$i].id.length==0)		{ continue; }
	
		if($form[$i].id)				{ var $tmp=window.get($form[$i].id); }
		else
		{ 			
			if(window.debug>2)
				window.log("Form Error: Have no identifier for this "+$i+" element.");
			continue;
		}
		if(!$tmp)						{ continue; }
	
		var $visp		=false;
		if(typeof document.defaultView != "undefined"
			&& typeof document.defaultView.getComputedStyle != "undefined") { 
			$visp		=document.defaultView.getComputedStyle($tmp, null).getPropertyValue("display");
		} else if ($tmp.currentStyle) {
			$visp		=$tmp.currentStyle["display"];
		}
		if($visp && $visp=='none')		{ continue; }

		
		var $block		=$tmp.getAttribute('validate');
		var $data		=$form[$i].value;
		if($tmp.type=='select-one')
		{
			if($tmp.selectedIndex<0)	{ $data=undefined; }
			else						{ $data=$tmp.options[$tmp.selectedIndex].value; }
		}
	
		if(typeof $block !='undefined' && typeof $block !='boolean' && $block!=null)
		{
			var $items	=parse_block($block);
			if(!$items['screen-name'] && $form[$i].name)
			{ $items['screen-name']=$form[$i].name; }
			if(!$items['screen-name'])	{ $items['screen-name']=$i;	}
			for(var $j in $items )
			{
				$filter	=false;
				switch($j)
				{
					case 'error-msg':
					case 'screen-name':
						$filter=true;
				}		
				if($filter)				{ continue; }

				$data	=validate_data($j, $items[$j], $data);
				if(!$data)
				{
					if(window.debug>2)
					{ 
						window.log($i+" failed "+$j+" (data "+$items[$j]+")"); 
					}
					if($items['error-msg'])
					{
						window.log($items['screen-name']+': '+$items['error-msg']);
					}
					else
					{
						window.log($items['screen-name']+': failed validation.');	
					}
					$form[$i].className+=" input_error";
					if($good) { $form[$i].focus(); }
					$good=false;
					$wipe=false;
					break;
				} 
				else					 
				{
					if(window.debug>2)
					{ 
						window.log($i+" passed "+$j+" (data "+$items[$j]+")"); 
					}
					$wipe=true;
				}
			}
			if($wipe)
			{
				if($tmp.type!='select-one')	{ $form[$i].value=$data; }
				else 
				{
					var $length=$tmp.options.length;
					for(var $i=0; $i<$length; $i++) {
						if($data==$tmp.options[$i].value) 
						{ $tmp.selectedIndex=$i; break; }
					}
				}
				var $re	=new RegExp('[ ]*input_error');
				var $t	=new String($form[$i].className);
				$form[$i].className=$t.replace($re, '');
			}
		}
	}
	window.log_buffer	=0;
	window.log("");
	return $good;
}}}

function parse_block($text)
{{{
	var $tmp=$text.split(':');
	var $out=new Array($tmp.length);
	var $count=0;
	for(var $i in $tmp) 
	{
		if(typeof $tmp[$i] != 'string')	{ continue; }
		$tmp2=$tmp[$i].split('=');
		if($tmp2.length!=2)				{ continue; }
		if($tmp2[0]=='template')
		{
			if(window.validation_templates[ $tmp2[1] ]) 
			{
				for(var $j in window.validation_templates[ $tmp2[1] ]) 
				{
					$out[$j]=window.validation_templates[ $tmp2[1] ][$j];
				}
			} 
			else 
			{
				window.log($tmp2[1]+': Unknown template, please contact sysadmin.');
			}
			
			
		} 
		else
		{
			$out[ $tmp2[0] ]=$tmp2[1];	
		}
	}
	return $out;
}}}

function validate_data($limitname, $limitvalue, $data)
{{{
	switch($limitname)
	{
		case 'min-length':
			if($data.length<parseInt($limitvalue)) 
			{
				return false;
			}
			break;
		
		case 'max-length':
			if($data.length>parseInt($limitvalue))
			{
				return false;
			}
			break;
		
		case 'regex':
			var re = new RegExp($limitvalue);
			if($data.match(re)==undefined){ return false;	}
			break;	

		case 'callback':
			eval("var $ret="+$limitvalue+"('"+$data+"');");
			return $ret;
			break;

		case 'selected':
			if($data==undefined || $data=='')
			{ 
				return false; 
			}
			break;


		case 'pure-numeric':
			if(isNaN(parseFloat($data))){ return false;	}
			break;

		case 'pure-alpha':
			var re = new RegExp('^[a-zA-Z]+$');
			if($data.match(re)==null)	{ return false;	}
			break;

		case 'pure-text':
			var re = new RegExp('^[a-zA-Z \t]+$');
			if($data.match(re)==null)	{ return false;	}
			break;
			
		case 'pure-char':
			var re = new RegExp('^[a-zA-Z0-9_\'-]+$');
			if($data.match(re)==null)	{ return false; }
			break;

		case 'no-white-space':
			var re = new RegExp('[ \t\n\b\v]');
			if($data.match(re)!=null)	{ return false;	}
			break;
	
		

		case 'upper':
			$data=$data.toUpperCase();
			break;

		case 'lower':
			$data=$data.toLowerCase();
			break;

		case 'trim':
			$data=trim($data); // XXX
			
		case 'md5':
			if(window.md5_sum)
			{
				$data=window.md5_sum($data);
			} else {
				window.log('ERROR: no password hashing algorithm found, please contact sysadmin.');
			}
			break;
			
		default:
			window.log($limitname+': Unknown input validation filter.');
			return false;
	}
	return $data;
}}}

function register_all_forms() 
{{{
	if(typeof list2array == 'undefined' || typeof window.get == 'undefined' )
	{
		window.log("ERROR: there are missing required libraries.");
		return false;
	}
	
	window.validation_templates=new Array();
	window.validation_templates['uk-phone']=list2array('min-length', '9', 'max-length', '13', 'pure-numeric', '1', 'regex', '^0[0-9]+', 'trim', 1, 'error-msg', 'is not a valid phone number for the UK.');
	window.validation_templates['postcode']=list2array('min-length', '6', 'max-length', '9', 'upper', '1', 'regex', '^[A-Z]{1,2}[0-9]{1,2} [0-9]{1,2}[A-Z]{1,2}$', 'trim', 1, 'error-msg', 'is not a valid UK postcode.');
	window.validation_templates['password']=list2array('min-length', '5', 'max-length', '15', 'trim', 1, 'md5', 1, 'error-msg', 'is not a valid password.');
	window.validation_templates['ip-address']=list2array('min-length', '7', 'max-length', '15', 'callback', 'validate_ip', 'trim', 1, 'error-msg', 'is not a valid IP address');
	//WARN: what else would you need?
	var $char='[a-zA-Z0-9._-]';
	window.validation_templates['email']=list2array('min-length', '8', 'max-length', '100', 'trim', 1, 'regex', '^'+$char+'+@(?'+$char+'{2,80}\.){2,40}\.'+$char+'{2,5}$',  'error-msg', 'is not a valid email address');
	window.validation_templates['filename']=list2array('min-length', '3', 'max-length', '50', 'trim', 1, 'pure-char', 1, 'error-msg', 'is not a filename.');
	window.validation_templates['generic']=list2array('min-length', '3', 'max-length', '50', 'trim', 1, 'pure-text', 1, 'error-msg', 'is not filled in properly.');

	for (var $i in document.forms) 
	{
// skip over the functions integers etc. 
		if(typeof document.forms[$i] != 'object')		{ continue; }
		var $func="var tmp=validate_form('"+$i+"'); return tmp;";
		document.forms[$i].onsubmit=new Function($func);
	}
	return true;
}}}

function validate_ip(what) 
{{{
	if (what.search(new RegExp('^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$')) != -1) {
		var bits = what.split('\\.');
		if (bits[0] > 255 || bits[1] > 255 || bits[2] > 255 || bits[3] > 255) {
			return false;
		}

		if (bits[0] == 0 && bits[1] == 0 && bits[2] == 0 && bits[3] == 0) {
			return false;
		}
		if(bits[3]==0 || bits[3]==255) {
			return 	false;
		}
		return what;

	} else {
		return false;
	}
 }}}

function md5(data) {
	return data;
}

if(!window.formvalidate)
{
	if(!window.log)						{ window.log=window.alert; }
	window.formvalidate=1;

	window.md5=md5;	
	if(typeof window.loadqueue !='undefined') 
		window.loadqueue('register_all_forms();');
	else if(!window.onload)
		window.onload=register_all_forms;
	else
		window.log("ERROR: Unable to initialise the input validation.");
}

// vi: ts=4
// vim: syn=javascript sw=4 st=4 tw=4 fdm=marker
