// Title: Tigra Form Validator PRO
// URL: http://www.softcomplex.com/products/tigra_form_validator_pro/
// Version: 1.2
// Date: 04/05/2005 (mm/dd/yyyy)
// Notes: Registration needed to use this script legally. Visit official site for details.

// regular expressions or function to validate the format
var re_dt = /^(\d{1,2})\-(\d{1,2})\-(\d{4})$/,
re_tm = /^(\d{1,2})\:(\d{1,2})\:(\d{1,2})$/,
a_formats = {
	'alpha'   : /^[a-zA-Z\.\-]*$/,
	'alphanum': /^\w+$/,
	'alphanumspace': /^[\w\s\.]+$/,
	'unsigned': /^\d+$/,
	'integer' : /^[\+\-]?\d*$/,
	'real'    : /^[\+\-]?\d*\.?\d*$/,
	'email'   : /^[\w-\.]+\@[\w\.-]+\.[a-z]{2,4}$/,
	'phone'   : /^[\d\.\s\-]+$/,
	'address' : /^[\w\s]+\s.+$/,
	'date'    : function (s_date) {
		// check format
		if (!re_dt.test(s_date))
			return false;
		// check allowed ranges	
		if (RegExp.$1 > 31 || RegExp.$2 > 12)
			return false;
		// check number of day in month
		var dt_test = new Date(RegExp.$3, Number(RegExp.$2-1), RegExp.$1);
		if (dt_test.getMonth() != Number(RegExp.$2-1))
			return false;
		return true;
	},
	'time'    : function (s_time) {
		// check format
		if (!re_tm.test(s_time))
			return false;
		// check allowed ranges	
		if (RegExp.$1 > 23 || RegExp.$2 > 59 || RegExp.$3 > 59)
			return false;
		return true;
	}
};

function vconfig() {
	this.alert = 0;
	this.alert_class = [];
	this.to_disable = [];
	this.messages = {
		'setup' : [
			'No form name passed to validator construction routine',
			'No array of "%form%" form fields passed to validator construction routine',
			'Form "%form%" can not be found in this document',
			'Can not find area for error message box (id="error_%form%")',
			'Incomplete "%n%" form field descriptor entry. Attribute "%attr%" is missing',
			'Can not find form field "%n%" in the form "%form%"',
			'Can not find label tag (id="%t%")',
			'Can not verify match. Field "%m%" was not found'
		],
		'fill' : [
			'"%l%" is a required field',
			'"%v%" is not valid value for "%l%"',
			'Value for "%l%" must be at least %mn% characters long',
			'Value for "%l%" must be no longer than %mx% characters',
			'"%l%" must match "%ml%"',
			'"%l%" is required when %dpn% is %dpv%'
		],
		'boxes' : [
			'<table cellpadding="0" cellspacing="0" border="0" width="100%" style="margin-bottom:10px">'
				+ '<tr><td bgcolor="#CCCC33"><table cellpadding="15" cellspacing="1" border="0" width="100%">'
				+ '<tr><td bgcolor="#FFFFCC" style="color: red;">%error%</td></tr>'
				+ '</table></td></tr><tr><td height="10">&nbsp;</td></tr></table>',
			'<table cellpadding="0" cellspacing="0" border="0" width="100%">'
				+ '<tr><td bgcolor="#CCCC33"><table cellpadding="15" cellspacing="1" border="0" width="100%">'
				+ '<tr><td bgcolor="#FFFFCC" style="color: green; font-weight: bold;">Submitting ...</td></tr>'
				+ '</table></td></tr><tr><td height="10">&nbsp;</td></tr></table>'
		],
		'confirm' : ['The "%form%" form is to be submitted. Are you sure?']
	}
}

// validator counstruction routine
function validator(s_form, a_fields, o_cfg) {
	this.f_error = validator_error;
	

	var o_cfg_full = new vconfig();
	validator_build_cfg(o_cfg, o_cfg_full);
	this.o_cfg = o_cfg_full;

	this._alert = o_cfg_full.alert;
	
	this.f_alert = this._alert & 4
		? function(s_msg) { alert(s_msg); return false }
		: function() { return false };
		
	this.s_errcss = o_cfg_full.alert_class;
		
	// check required parameters
	if (!s_form)	
		return this.f_alert(this.f_error('setup', 0));
	this.s_form = s_form;
	
	if (!a_fields || typeof(a_fields) != 'object')
		return this.f_alert(this.f_error('setup', 1));
	this.a_fields = a_fields;
	
	this.a_2disable = o_cfg_full.to_disable;
	
	
	this.exec = validator_exec;
}

// validator execution method
function validator_exec() {
	var o_form = document.forms[this.s_form];
	if (!o_form)	
		return this.f_alert(this.f_error('setup', 2));
		
	// clear error messages box from previous errors	
	var e_errbox = get_element('error_' + this.s_form),
	b_dom = document.body && document.body.innerHTML;
	
	if ((this._alert & 2) || (this._alert & 8)) {
		if (b_dom && !e_errbox)
			return this.f_alert(this.f_error('setup', 3));
			
		if (b_dom) {
			e_errbox.style.display = 'none';
			e_errbox.innerHTML = '';
		}
	}

	var a_reqattrs = ['l'];
	
	// check integrity of the form fields description structure
	for (var n_key in this.a_fields) {
		// check input description entry
		this.a_fields[n_key]['n'] = n_key;
		for (n_attr in a_reqattrs)
			if (!this.a_fields[n_key][a_reqattrs[n_attr]])
				return this.f_alert(this.f_error('setup', 4, this.a_fields[n_key], {'attr' : a_reqattrs[n_attr]}));
		o_input = o_form.elements[n_key];
		if (!o_input)
			return this.f_alert(this.f_error('setup', 5, this.a_fields[n_key]));
		this.a_fields[n_key].o_input = o_input;
	}

	// reset labels highlight
	if (b_dom)
		for (var n_key in this.a_fields) 
			if (this.a_fields[n_key]['t']) {
				var s_labeltag = this.a_fields[n_key]['t'], e_labeltag = get_element(s_labeltag);
				if (!e_labeltag)
					return this.f_alert(this.f_error('setup', 6, this.a_fields[n_key]));
				this.a_fields[n_key].o_tag = e_labeltag;
				
				// normal state parameters assigned here
				e_labeltag.className = this.s_errcss[1];
			}

	// collect values depending on the type of the input
	for (var n_key in this.a_fields) {
		o_input = this.a_fields[n_key].o_input;
		this.a_fields[n_key]['v'] = null;
		// >> checkbox validation doesn't work properly. needs to be reimplemented
		if (o_input.type == 'checkbox') { // checkbox
			if (o_input.checked && o_input.value)
				this.a_fields[n_key]['v'] = o_input.value;
		}
		else if (o_input.value) // text, password, hidden 
			this.a_fields[n_key]['v'] = o_input.value;
		else if (o_input.options && o_input.selectedIndex > -1) // select
			this.a_fields[n_key]['v'] = o_input.options[o_input.selectedIndex].value;
		else if (o_input.length > 0) // radiobuton
			for (var n_index = 0; n_index < o_input.length; n_index++)
				if (o_input[n_index].checked) {
					this.a_fields[n_key]['v'] = o_input[n_index].value;
					break;
				}
	}
	
	// check for errors
	var n_errors_count = 0, s_correct,
		n_another, o_format_check, b_format_func;
	for (var n_key in this.a_fields) {
		o_field = this.a_fields[n_key];
		o_format_check = o_field['f'] 
			? (a_formats[o_field['f']]
				? a_formats[o_field['f']]
				: o_field['f'])
			: null;
		b_format_func = (o_format_check + '').indexOf('function') > -1;

		// reset previous error if any
		o_field.n_error = null;
//		alert(typeof(o_format_check) != 'function' && o_field['v']!=null && !o_format_check.test(o_field['v']))
		// check reqired fields
		if (o_field['r'] && !o_field['v']) {
			o_field.n_error = 1;
			n_errors_count++;
		}
		// check match	
		else if (o_field['m']) {
			for (var n_key2 in this.a_fields)
				if (n_key2 == o_field['m']) {
					n_another = n_key2;
					break;
				}
			if (n_another == null)
				return this.f_alert(this.f_error('setup', 7, o_field));
			if (this.a_fields[n_another]['v'] != o_field['v']) {
				o_field['ml'] = this.a_fields[n_another]['l'];
				o_field.n_error = 5;
			n_errors_count++;
			}
		}
		// check depencies
		else if (this.a_fields[n_key]['dp']) {
			var s_name, s_value;
			if (typeof(this.a_fields[n_key]['dp']) == 'object') {
				s_name  = this.a_fields[n_key]['dp'][0];
				s_value = this.a_fields[n_key]['dp'][1];
			}
			else
				s_name = this.a_fields[n_key]['dp'];

			if (!this.a_fields[n_key]['v'] && ((s_value && this.a_fields[s_name]['v'] == s_value) || (!s_value && this.a_fields[s_name]['v']))) {
				this.a_fields[n_key]['dpn'] = this.a_fields[s_name]['l'];
				this.a_fields[n_key]['dpv'] = s_value ? 'set to "' + s_value + '"' : 'specified';
			
				this.a_fields[n_key].n_error = 6;
				n_errors_count++;
			}
		}
		// skip further tests if no value
		else if (!o_field['v']) {
			continue;
		}
		// check length
		else if (o_field['mn'] && String(o_field['v']).length < o_field['mn']) {
			o_field.n_error = 3;
			n_errors_count++;
		}
		else if (o_field['mx'] && String(o_field['v']).length > o_field['mx']) {
			o_field.n_error = 4;
			n_errors_count++;
		}
		// check format
		else if (o_format_check && (
				(b_format_func && (s_correct = o_format_check(o_field['v'], o_form)) != true)
			|| (!b_format_func && o_field['v'] && !o_format_check.test(o_field['v']))
				)
			) {
			o_field.n_error = typeof(s_correct) != 'string' ? 2 : s_correct;
			n_errors_count++;
		}
	}

	// collect error messages and highlight captions for errorneous fields
	var s_html_message = '',
		s_alert_message = '',
		e_first_error;

	if (n_errors_count) {
		for (var n_key in this.a_fields) {
			var n_error_type = this.a_fields[n_key].n_error, s_message = '';
				
			if (n_error_type) {
				s_message = this.f_error('fill', n_error_type - 1, this.a_fields[n_key]);
				if (!s_message)
					s_message = n_error_type;
			}

			if (s_message) {
				if (!e_first_error)
					e_first_error = o_form.elements[n_key];
	
				s_html_message += s_message + '<br />';
				s_alert_message += s_message + "\n";

				// highlighted state parameters assigned here
				if (b_dom && this.s_errcss && this.a_fields[n_key].o_tag)
					this.a_fields[n_key].o_tag.className = this.s_errcss[0];
			}
		}

		// display message in the document if new browser
		s_html_message = this.f_error('boxes', 0, {'error' : s_html_message});
		
		// check if custom error proceeding function is defined		
		if (typeof(this._alert) != 'function') {
			if (this._alert & 1)
				// display error dialog box if on
				alert(s_alert_message);
			// check if error messages are to be inserted into HTML box 
			if (b_dom && (this._alert & 2)) {
				e_errbox.innerHTML = s_html_message;
				e_errbox.style.display = 'block';
			}
			// set focus to first errorneous field
			if (e_first_error.focus && e_first_error.type != 'hidden')
				try {
					e_first_error.focus();
				}
				catch (e) {
				}
			// cancel form submission if errors detected
			return false;
		}
	}
	
	if (typeof(this._alert) == 'function')
		// call custom error proceeding function
		return this._alert(s_alert_message, s_html_message, e_errbox);
	
	else {
		if ((this._alert & 16) && !confirm(this.f_error('confirm', 0)))
			return false;
		if (b_dom && (this._alert & 8)) {
			e_errbox.innerHTML = this.f_error('boxes', 1);
			e_errbox.style.display = 'block';
		}
			
		// block submit button if exists
		for (n_key in this.a_2disable) {
			var e_input = get_element(this.a_2disable[n_key]);
			if (e_input && e_input.disabled != null)
				e_input.disabled = true;
		}
	}
	return true;
}

function validator_build_cfg(o_fragment, o_fragment_def) {
	for (var s_ in o_fragment)
		if (o_fragment[s_] != null) {
			if (typeof(o_fragment[s_]) == 'object') {
				if (typeof(o_fragment_def[s_]) != 'object')
					alert("Type mismatch (" + s_ + "). Array in place of scalar.");
				validator_build_cfg(o_fragment[s_], o_fragment_def[s_]);
			}
			else {
				if (typeof(o_fragment_def[s_]) == 'object')
					alert("Type mismatch (" + s_ + "). Scalar in place of array.");
				o_fragment_def[s_] = o_fragment[s_];
			}
		}
}

function validator_error(s_group, n_index) {
	var s_ = this.o_cfg.messages[s_group][n_index], n_i = 2, s_key;
	if (!s_) return false;
	if (typeof(s_) == 'function') s_ = s_(this.s_form);
	for (; n_i < arguments.length; n_i ++)
		for (s_key in arguments[n_i])
			s_ = s_.replace('%' + s_key + '%', arguments[n_i][s_key]);
	s_ = s_.replace('%form%', this.s_form);
	return s_
}

function get_element (s_id) {
	return (document.all ? document.all[s_id] : (document.getElementById ? document.getElementById(s_id) : null));
}