/* ========================================================================= */
/* Validator object - r020 (05.02.2010)
/* Tested on Firefox 3.x; Explorer 6,7,8; Opera 8,9
/* ========================================================================= */

// Built-in regular expressions
var REGEX_INT = 1;
var REGEX_MAIL = 2;
var REGEX_PHONE = 3;

function Validator()
{
	// Properties
	this.objects = new Object();
	this.validateCSS = 'background-color:%%COLOR%%;';
	this.validateContainerCSS = 'line-height:150%; vertical-align:top; display:none;';
	this.validateErrMsgCSS = 'font-size:8pt; color:#FF8020; background-color:#FFFFA0; border:#FF8020 1px solid; padding:2px; position:absolute; line-height:normal; display:none;';
	this.validateIconUrl = 'img/validate-error.png';

	// A global variable
	__globalValidatorVariable = this;

	// Add element for validation, attach the notification icon and text
	this.add = function (id, min, max, regEx, attachFuncion, ifEmpty, errorMsg)
	{
		if (this.objects[id])
			tmp = this.objects[id];
		else
			var tmp = new Object();

		tmp['min'] = (!min ? null : min);
		tmp['max'] = (!max ? null : max);
		tmp['regEx'] = (!regEx ?  null : regEx);
		tmp['attachFunc'] = (!attachFuncion ? null : attachFuncion);
		tmp['onchange'] = null;  // Additional onchange javascript
		tmp['ifEmpty'] = !(!ifEmpty);
		tmp['result'] = false;
		tmp['errorDesc'] = (!errorMsg ? 'Invalid input value' : errorMsg);
		this.objects[id] = tmp;

		// Append notification icon
		if (document.getElementById(id)) {
			var obj = document.getElementById(id);

			var divHTML = '<span id="'+id+'Container" style="'+this.validateContainerCSS+'">'+
				'<img src="'+this.validateIconUrl+'" style="cursor:pointer;" hspace="3" onmouseover="show(\''+id+'ErrMsg\')" onmouseout="hide(\''+id+'ErrMsg\')">'+
				'<span id="'+id+'ErrMsg" style="'+this.validateErrMsgCSS+'">Invalid input value</span>'+
				'</span>';
			obj.parentNode.innerHTML += divHTML;
		}
	}

	// Append onchange events
	this.attachEvents = function ()
	{
		// Chemistry ... strEv must be declared in a function
		// ... and there must be separate function call for each event
		for(var id in this.objects)
			this.attachEventById(id);
	}

	this.attachEventById = function (id)
	{
		if (document.getElementById(id)) {
			var obj = document.getElementById(id);

			if (obj.tagName.toLowerCase() == 'select') {
				var strEv = parseElementEvent(obj, 'onchange');
				if (strEv)
					obj.onchange = function() { __globalValidatorVariable.validate(this); eval(strEv); };
				else
					obj.onchange = function() { __globalValidatorVariable.validate(this) };
			}
			else {
				var strEv = parseElementEvent(obj, 'onblur');
				if (strEv)
					obj.onblur = function() { __globalValidatorVariable.validate(this); eval(strEv); };
				else
					obj.onblur = function() { __globalValidatorVariable.validate(this) };
			}
		}
	}

	// Set error message for an element to be dispayed if error is raized
	this.setErrorMessage = function (id, msg)
	{
		if (!this.objects[id])
			return false;

		this.objects[id]['errorDesc'] = msg;
		return true;
	}

	// Validate element
	this.validate = function (el)
	{
		if (typeof(el) == 'string')
			var el = document.getElementById(el);

		if (!el || !this.objects[el.id])
			return;

		this.objects[el.id]['result'] = false;
		valObj = this.objects[el.id];

		if (valObj['ifEmpty'] && (el.value == '' || (el.tagName.toLowerCase() == 'select' && el.value <= 0))) {
			this.objects[el.id]['result'] = true;
			this.raiseError(el, -1);
		}
		else {
			if (valObj['min'] && (valObj['regEx'] == REGEX_INT && valObj['min'] > el.value ||
								  valObj['regEx'] != REGEX_INT && valObj['min'] > el.value.length))
				this.raiseError(el, 1);
			else
			if (valObj['max'] && (valObj['regEx'] == REGEX_INT && valObj['max'] < el.value ||
								  valObj['regEx'] != REGEX_INT && valObj['max'] < el.value.length))
				this.raiseError(el, 2);
			else
			if (valObj['regEx'] && !this.validateRegEx(el))
				this.raiseError(el, 3);
			else
			if (valObj['attachFunc'] && !valObj['attachFunc'](el))
				this.raiseError(el, 4);
			else {
				this.raiseError(el, 0);
				this.objects[el.id]['result'] = true;
			}
		}
		if (this.objects[el.id]['onchange'])
			eval(this.objects[el.id]['onchange']);
	}

	// Use regular expression (if present) to validate the value
	this.validateRegEx = function (el)
	{
		var regEx = this.objects[el.id]['regEx'];
		try {
			switch (regEx) {
				case REGEX_INT:
					return (el.value.replace(/[^0-9]/gi, '') == el.value);

				case REGEX_MAIL:
					return (el.value.match(/([a-z0-9._-]+@[a-z0-9._-]+\.[a-z]{2,4})/gi, '') !== null);

				case REGEX_PHONE:
					if (el.value != el.value.replace(/[^0-9\+\-\ ]/gi, ''))
						return false;
					return (el.value.replace(/[^0-9]/gi, '').length >= this.objects[el.id]['min']);

				default:
					return (el.value.replace(regEx, '') == el.value);
			}
		}
		catch(e) {
			return false;
		}
		return false;
	}

	// Mark as error or correct field
	this.raiseError = function (el, errCode, customMsg)
	{
		if (errCode < 0) {
			el.style.cssText = '';
			return;
		}
		
		var bgcolor = (errCode == 0 ? '#F0FFF0' : '#FFF0F0');
		el.style.cssText = this.validateCSS.replace('%%COLOR%%', bgcolor);

		// Set Error message
		if (document.getElementById(el.id+'Container') && this.objects[el.id]['errorDesc'] != '') {
			if (document.getElementById(el.id+'ErrMsg'))
				document.getElementById(el.id+'ErrMsg').innerHTML = (!customMsg ? this.objects[el.id]['errorDesc'] : customMsg);
			
			document.getElementById(el.id+'Container').style.display = (errCode == 0 ? 'none' : '');
		}
	}

	// Check all fields
	this.checkResults = function ()
	{
		try {
			var ifOk = true;
			for (var id in this.objects) {
				//if (this.objects[id]['result'] == false)
				this.validate(id);
				ifOk = ifOk && this.objects[id]['result'];
			}
			return ifOk;
		}
		catch(e) {
			return false;
		}
		return false;
	}
}

// Parses event value of an element ant returns it as string
function parseElementEvent(obj, eventName)
{
	if (!obj)
		return null;

	var strEv = obj.getAttribute(eventName, null);
	if (strEv) {
		strEv = strEv.toString();
		if (strEv.indexOf('function') >= 0 && strEv.indexOf('{') >= 0) {
			var p1 = strEv.indexOf('{');
			var p2 = strEv.indexOf('}', p1);
			strEv = strEv.substring(p1+1, p2);
		}
	}
	return strEv;
}
