/* validator default error messages*/
var E_VAL_REQUIRED_VALUE =             "Please enter the value for %req_name%";
var E_VAL_MAXLEN_CHECK_FAILED =        "Please enter input with length less than or equal to %max_num% for %req_name%.";
var E_VAL_MINLEN_CHECK_FAILED =        "Please enter input with length more than or equal to %min_num% for %req_name%";
var E_VAL_ALNUM_CHECK_FAILED =         "Please provide an alpha-numeric input for %req_name%";
var E_VAL_ALNUM_S_CHECK_FAILED =       "Please provide an alpha-numeric(allow space) input for %req_name%";
var E_VAL_NUM_CHECK_FAILED =           "Please provide numeric input for %req_name%";
var E_VAL_ALPHA_CHECK_FAILED =         "Please provide alphabetic input for %req_name%";
var E_VAL_ALPHA_S_CHECK_FAILED =       "Please provide alphabetic(allow space) input for %req_name%";
var E_VAL_EMAIL_CHECK_FAILED =         "Please provide a valid email address for %req_name%";
var E_VAL_LESSTHANEQ_CHECK_FAILED =    "Value of %req_name% should be less than or equal to %max_num%";
var E_VAL_GREATERTHANEQ_CHECK_FAILED = "Value of %req_name% should be greater than or equal to %min_num%";
var E_VAL_REGEXP_CHECK_FAILED =        "Please provide a valid input for %req_name%";
var E_VAL_SHOULDSEL_CHECK_FAILED =     "Wrong option selected for %req_name%";
var E_VAL_SELMIN_CHECK_FAILED =        "Please select minimum %min_num% options for %req_name%";
var E_VAL_SELMAX_CHECK_FAILED =        "Please select maximum %max_num% options for %req_name%";
var E_VAL_SELONE_CHECK_FAILED =        "Please select an option for %req_name%";
var E_VAL_EQELMNT_CHECK_FAILED =       "Value of %req_name% should be same as that of %comp_req_name%";
var E_VAL_NEELMNT_CHECK_FAILED =       "Value of %req_name% should not be same as that of %comp_req_name%";
var E_VAL_EQ_CHECK_FAILED =            "Value of %req_name% should be equal to %equal_value%";
var E_VAL_LESSTHAN_CHECK_FAILED =      "Value of %req_name% should be less than %max_num%";
var E_VAL_GREATERTHAN_CHECK_FAILED =   "Value of %req_name% should be greater than %min_num%";
var E_VAL_URL_CHECK_FAILED =           "Value of %req_name% should be a valid URL";
var E_VAL_REMOTE_CHECK_FAILED =        "Please enter an valid value for %req_name%!";
var E_VAL_EQLEN_CHECK_FAILED =         "Length of %req_name% should be equal to %equal_len%";
var E_VAL_CHECK_ALL_FAILED =           "Some inputs of the form are NOT eligible!\nPlease enter correct values for the form.";

var VA_REQ =                   0;
var VA_MAXLEN =                1;
var VA_MINLEN =                2;
var VA_ALNUM =                 3;
var VA_ALNUM_S =               4;
var VA_NUM =                   5;
var VA_ALPHA =                 6;
var VA_ALPHA_S =               7;
var VA_EMAIL =                 8;
var VA_LESSTHANEQ =            9;
var VA_GREATERTHANEQ =         10;
var VA_REGEXP =                11;
var VA_SHOULDSEL =             12;
var VA_SELMIN =                13;
var VA_SELMAX =                14;
var VA_SELONE =                15;
var VA_EQELMNT =               16;
var VA_NEELMNT =               17;
var VA_EQ =                    18;
var VA_LESSTHAN =              19;
var VA_GREATERTHAN =           20;
var VA_CONDITION =             21;
var VA_URL =                   22;
var VA_REMOTE_CHECK =          23;
var VA_EQLEN =                 24;

var bSubmited = false;
var bDebug    = false;

function appendDebugMsg(debug_msg)
{
	if(!bDebug)
		return;
    dev_block = document.getElementById('snf_devel_output');
    if(!dev_block)
        return;
    dev_block_html = dev_block.innerHTML;
    dev_block_html += '<br>validator_dbg_msg: ' + debug_msg;
    dev_block.innerHTML = dev_block_html;
    return;
}

function sendRequest(mode, url, args, async, callback_success, callback_failed, cArgs, respType, timeout)
{
    // create object
    var httpRequest = false;
    if ( window.XMLHttpRequest ) { // mozilla, safari, opera, chrome, ie7
        httpRequest = new XMLHttpRequest();
    } else if ( window.ActiveXObject ) { // ie, avant, aol explorer
        try { httpRequest = new ActiveXObject("Msxml2.XMLHTTP") } // ie6
        catch (e) {
            try { httpRequest = new ActiveXObject("Microsoft.XMLHTTP") } // ie5
            catch(e) {
                httpRequest = false;
            }
        }
    }
    // object creation fail?
    if ( ! httpRequest ) {
        response = "Remote request failed: status code -2";
        cArgs != null ?  callback_failed(response, cArgs) :  callback_failed(response);
        return false;
    }

    // if GET with arguments append query string to url
    if ( mode == 'GET' && args.length ) url += '?' + args;

    // establish connection
    httpRequest.open(mode, url, async);

    // boolean timedOut; start out true
    // the response handler sets to false on success
    var timedOut = true;

    // create a timer to check the value of timedOut in (timeout) seconds;
    // if timedOut is true, abort the request and clean up
    setTimeout( function() {
        // timedOut true?
        if (timedOut) {
            httpRequest.abort(); // abort request
            //response = "Error: ajax request timed out";
        	//cArgs != null ?  callback_failed(response, cArgs) :  callback_failed(response);
        }
        // nullify httpRequest
        httpRequest = null;
    }, timeout * 1000 );
 

    // if POST, set necessary request headers
    if ( mode == 'POST' ) {
        httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        httpRequest.setRequestHeader('Content-Length', args.length);
    }

    // assign callback method via anonymous function
    httpRequest.onreadystatechange = function() {
        try {
            // response ready?
            if ( httpRequest.readyState == 4 ) {
                // request successful?
                if ( httpRequest.status == 200 ) {
                    // set timedOut to false
                    timedOut = false;
                    // set response
                    var response = respType == 'text' ?  httpRequest.responseText :  httpRequest.responseXML;

                    // pass to callback method
                    cArgs != null ?  callback_success(response, cArgs) :  callback_success(response);
                }
                else{
                	if(!bSubmited) { 
	                    response = "Remote request failed: status code " + httpRequest.status;
	                   	cArgs != null ?  callback_failed(response, cArgs) :  callback_failed(response);
                   	}
                }
            }
        } catch(e) {
        	response = "Remote request failed: status code -1";
        	cArgs != null ?  callback_failed(response, cArgs) :  callback_failed(response);
        }
    };

    // send request
    httpRequest.send(args);
}

function doubleval (mixed_var) {
    return (parseFloat(mixed_var) || 0);
}

function is_numeric (mixed_var) {
    if (mixed_var === '') {
        return false;
    }
    return !isNaN(mixed_var * 1);
}

function isset () {
    var a=arguments, l=a.length, i=0;
    
    if (l===0) {
        throw new Error('Empty isset'); 
    }
    
    while (i!==l) {
        if (typeof(a[i])=='undefined' || a[i]===null) { 
            return false; 
        } else { 
            i++; 
        }
    }
    return true;
}

function empty (mixed_var) {
    var key;
    
    if (mixed_var === "" ||
        mixed_var === 0 ||
        mixed_var === "0" ||
        mixed_var === null ||
        mixed_var === false ||
        mixed_var === undefined
    ){
        return true;
    }
 
    if (typeof mixed_var == 'object') {
        for (key in mixed_var) {
            return false;
        }
        return true;
    }
 
    return false;
}

function strlen (string) { 
    return string.length;
}

function str_replace(search, replace, str) {
	var regex = new RegExp(search, "g");
	return str.replace(regex, replace);
}

function is_array( mixed_var ) {  
    return typeof(mixed_var)=='object'&&(mixed_var instanceof Array);  
}

function in_array (needle, haystack) {
    var key = '';
    for (key in haystack) {
        if (haystack[key] == needle) {
            return true;
        }
    }
    return false;
}

function array_key_exists( needle, haystack ) {
    var key = '';
    for (key in haystack) {
        if (key == needle) {
            return true;
        }
    }
    return false;
}

function snfForm()
{
	this.form_id           = 0;
	this.error_msg_list    = new Array();
	this.element_real_name = new Array();
	this.validator         = null;
	this.error_box_style   = 'border-left: 3px solid red;';
	this.error_text_style  = 'color: orange;';
	this.check_fail_img_html = '';
	this.check_ok_img_html = '';
	this.waiting_img_html = '';
	this.is_rendering_waiting = new Array();
	
}

snfForm.prototype.setCheckFailImgHtml = function(html)
{
	this.check_fail_img_html = html;
}
snfForm.prototype.setCheckOkImgHtml = function(html)
{
	this.check_ok_img_html = html;
}
snfForm.prototype.setWaitingImgHtml = function(html)
{
	this.waiting_img_html = html;
}
snfForm.prototype.setErrorBoxStyle = function(error_box_style)
{
	this.error_box_style = error_box_style;
}
snfForm.prototype.setValidator = function(validator)
{
	this.validator = validator;
}
snfForm.prototype.setFormID   = function(form_id)
{
	this.form_id = form_id;
}
snfForm.prototype.addErrorMsg = function(req_name, error_msg)
{
	// add error messsage to error_msg_list, prevent duplicate the message for each req_name
	if(!array_key_exists(req_name, this.error_msg_list))
	{
		this.error_msg_list[req_name] = new Array();
	}
	var length = this.error_msg_list[req_name].length;
	var i;
	var b_dup = false;
	for(i=0;i<length;i++)
	{
		if(this.error_msg_list[req_name][i] == error_msg)
			b_dup = true;
	}
	if(!b_dup)
		this.error_msg_list[req_name][length] = error_msg;
}
snfForm.prototype.clearErrorMsg = function(req_name)
{
	if(array_key_exists(req_name, this.error_msg_list))
	{
		this.error_msg_list[req_name] = new Array();
	}
}
snfForm.prototype.setElementRealName = function(req_name, real_name)
{
	this.element_real_name[req_name] = real_name;
}
snfForm.prototype.getElementRealName = function(req_name)
{
	if(array_key_exists(req_name, this.element_real_name))
	{
		return this.element_real_name[req_name];
	}
	return null;
}
snfForm.prototype.renderWaiting = function(req_name)
{
	var element_check_img_id = 'snf_' + this.form_id + '_check_img_' + req_name;
	var element_check_img    = document.getElementById(element_check_img_id);
	if(!element_check_img)
		return;
	element_check_img.innerHTML = this.waiting_img_html;
	this.is_rendering_waiting[req_name] = true;
	return;
}
snfForm.prototype.clearWaiting = function(req_name)
{
	var element_check_img_id = 'snf_' + this.form_id + '_check_img_' + req_name;
	var element_check_img    = document.getElementById(element_check_img_id);
	if(!element_check_img)
		return;
	element_check_img.innerHTML = "";
	this.is_rendering_waiting[req_name] = false;
	return;
}
snfForm.prototype.appendError = function(req_name, error_msg)
{
	var element_box_id = 'snf_' + this.form_id + '_elmnt_' + req_name;
	var element_box    = document.getElementById(element_box_id);
	if(!element_box)
		return;

	var element_error_id = 'snf_' + this.form_id + '_error_' + req_name;
	var element_error    = document.getElementById(element_error_id);
	if(!element_error)
		return;

	var element_check_img_id = 'snf_' + this.form_id + '_check_img_' + req_name;
	var element_check_img    = document.getElementById(element_check_img_id);
	if(!element_check_img)
		return;

	var isIE = (window.ActiveXObject)?true:false;
	if(isIE)
	{
		element_box.style.setAttribute('cssText',this.error_box_style);
	}
	else
	{
		element_box.style.cssText = this.error_box_style;
	}

	var errorInnerHtml=element_error.innerHTML;
	errorInnerHtml += "&nbsp;-&nbsp;" + error_msg + "<br>";
	element_error.innerHTML = errorInnerHtml;
	element_error.style.display = 'block';
	
	if(!this.is_rendering_waiting[req_name])
	    element_check_img.innerHTML = this.check_fail_img_html;
	return;
}
snfForm.prototype.renderError = function(req_name)
{
	var element_box_id = 'snf_' + this.form_id + '_elmnt_' + req_name;
	var element_box    = document.getElementById(element_box_id);
	if(!element_box)
		return;

	var element_error_id = 'snf_' + this.form_id + '_error_' + req_name;
	var element_error    = document.getElementById(element_error_id);
	if(!element_error)
		return;

	var element_check_img_id = 'snf_' + this.form_id + '_check_img_' + req_name;
	var element_check_img    = document.getElementById(element_check_img_id);
	if(!element_check_img)
		return;

	var isIE = (window.ActiveXObject)?true:false;
	if(isIE)
	{
		element_box.style.setAttribute('cssText',this.error_box_style);
	}
	else
	{
		element_box.style.cssText = this.error_box_style;
	}

	var errorInnerHtml='';
	var i = 0;
	if(array_key_exists(req_name, this.error_msg_list))
	{
		var length = this.error_msg_list[req_name].length;
		for(i=0;i<length;i++)
		{
			var error_msg = this.error_msg_list[req_name][i];
			errorInnerHtml += "&nbsp;-&nbsp;" + error_msg + "<br>";
		}
	}
	element_error.innerHTML = errorInnerHtml;
	element_error.style.display = 'block';
	
	if(!this.is_rendering_waiting[req_name])
		element_check_img.innerHTML = this.check_fail_img_html;
	return;
}
snfForm.prototype.clearError = function(req_name)
{
	var element_box_id = 'snf_' + this.form_id + '_elmnt_' + req_name;
	var element_box    = document.getElementById(element_box_id);
	if(!element_box)
		return;

	var element_error_id = 'snf_' + this.form_id + '_error_' + req_name;
	var element_error    = document.getElementById(element_error_id);
	if(!element_error)
		return;

	var element_check_img_id = 'snf_' + this.form_id + '_check_img_' + req_name;
	var element_check_img    = document.getElementById(element_check_img_id);
	if(!element_check_img)
		return;

	var isIE = (window.ActiveXObject)?true:false;
	if(isIE)
	{
		element_box.style.setAttribute('cssText','');
	}
	else
	{
		element_box.style.cssText = '';
	}

	var errorInnerHtml='';
	element_error.innerHTML = errorInnerHtml;
	element_error.style.display = 'none';
	if(!this.is_rendering_waiting[req_name])
		element_check_img.innerHTML = this.check_ok_img_html;
}
snfForm.prototype.getElementValue = function(req_name)
{
	var form_obj = document.getElementById(this.form_id);
	if(!form_obj)
		return null;
	return eval('form_obj.' + req_name + '.value');
}
snfForm.prototype.setElementValue = function(req_name, value)
{
	var form_obj = document.getElementById(this.form_id);
	if(!form_obj)
		return;
	eval('form_obj.' + req_name + '.value="' + value + '"');
	return;
}

function snfValidator()
{
	this.rules_chain             = new Array();
	this.form                    = null;
	this.prev_validate_result    = new Array();
}

snfValidator.prototype.attachForm = function(form)
{
	this.form = form;
	this.form.setValidator(this);
}
snfValidator.prototype.addConditionRule = function(req_name,rule,conditions)
{
	var rule_chain = new Array();
	rule_chain['req_name']                      = req_name;
	rule_chain['rule']                          = new Array();
	rule_chain['rule']['va_code']               = VA_CONDITION;
	rule_chain['rule']['params']                = new Array();
	rule_chain['rule']['params']['conditions']  = conditions;
	rule_chain['rule']['params']['rule']        = rule;
	var rand = Math.round(Math.random()*10000);
	var str_rand = rand.toString();
	while(array_key_exists(str_rand, this.rules_chain))
	{
		rand = Math.round(Math.random()*10000);
		str_rand = rand.toString();
	}
	this.rules_chain[str_rand]   = rule_chain;
}
snfValidator.prototype.addRule = function(req_name,rule)
{
	var rule_chain                             = new Array();
	rule_chain['req_name']                     = req_name;
	rule_chain['rule']                         = rule;
	var rand = Math.round(Math.random()*10000);
	var str_rand = rand.toString();
	while(array_key_exists(str_rand, this.rules_chain))
	{
		rand = Math.round(Math.random()*10000);
		str_rand = rand.toString();
	}
	this.rules_chain[str_rand]   = rule_chain;
}
snfValidator.prototype.setErrorMsg = function(req_name, user_error_msg, default_error_msg, str_var_name, str_var_value)
{
	error_msg = '';
	if(!isset(user_error_msg) && !isset(default_error_msg))
	{
		return;
	}
	else
		error_msg = isset(user_error_msg) ? user_error_msg : default_error_msg;

    var real_name = this.form.getElementRealName(req_name);
    if(!isset(real_name))
        real_name = req_name;
    
    var req_value = this.form.getElementValue(req_name);
    error_msg = str_replace('%req_name%', real_name, error_msg);
    error_msg = str_replace('%req_value%', req_value, error_msg);
    if(isset(str_var_name) && isset(str_var_value))
    {
        error_msg = str_replace('%' + str_var_name + '%', str_var_value, error_msg);
    }
	this.form.addErrorMsg(req_name, error_msg);
	return error_msg;
}

snfValidator.prototype.validateRemoteCheck = function(req_name, input_value, rule)
{
	var has_error = array_key_exists(req_name, this.form.error_msg_list) && !empty(this.form.error_msg_list[req_name])
	if(isset(input_value) && !empty(input_value) && !has_error)
	{
		//xml_http   = createXMLHttpRequest();
		var server_url = rule['params']['server_url'];
		if(isset(server_url))
		{
			server_url += input_value;
			this.form.renderWaiting(req_name);
			var args = new Array();
			args['form'] = this.form;
			args['validator'] = this;
			args['req_name']  = req_name;
			args['rule']      = rule;
			args['input_value'] = input_value;
			sendRequest('GET', server_url, '', true, callbackRemoteCheckOK, callbackRemoteCheckFail, args, 'text', 90);
		}
	}
	return true;
}
function callbackRemoteCheckOK(resp,args)
{
	var para_req_name    = args['req_name'];
	var para_rule        = args['rule'];
	var para_input_value = args['input_value'];
	var para_form        = args['form'];
	var para_validator   = args['validator'];
	
	para_form.clearWaiting(para_req_name);

	var reg_exp   = para_rule['params']['reg_exp'];
	if(!para_validator._validateRegExp(resp, reg_exp))
	{
		var error_msg = para_rule['error_msg'];
		para_rule["last_error_msg"] = para_validator.setErrorMsg(para_req_name, error_msg, E_VAL_REMOTE_CHECK_FAILED);
		//alert(para_rule["last_error_msg"]);
		para_form.appendError(para_req_name, para_rule["last_error_msg"]);
		para_rule["last_req_value"] = para_input_value;
		para_rule["last_result"]    = false;	
	}
	else
	{
		para_rule["last_req_value"] = para_input_value;
		para_rule["last_result"]    = true;
		if(array_key_exists(para_req_name, para_form.error_msg_list) && !empty(para_form.error_msg_list[para_req_name]))
		{
			para_form.renderError(para_req_name);
		}
		else
		{
			para_form.clearError(para_req_name);
		}
	}
}
function callbackRemoteCheckFail(resp,args)
{
	var para_req_name    = args['req_name'];
	var para_rule        = args['rule'];
	var para_input_value = args['input_value'];
	var para_form        = args['form'];
	var para_validator   = args['validator'];
	
	para_form.addErrorMsg(para_req_name, resp);
	para_form.clearWaiting(para_req_name);
	para_rule["last_req_value"] = "";
	para_rule["last_result"]    = false;
	if(array_key_exists(para_req_name, para_form.error_msg_list) && !empty(para_form.error_msg_list[para_req_name]))
	{
		para_form.renderError(para_req_name);
	}
	else
	{
		para_form.clearError(para_req_name);
	}
}
snfValidator.prototype.validateReq = function(input_value,rule)
{
	if(!isset(input_value) || empty(input_value))
	{
	    return false;
	}
	return true;
}
snfValidator.prototype.validateMaxLen = function(input_value,rule)
{
	if(isset(input_value))
	{
		max_len=rule['params']['max_len'];
		input_length = strlen(input_value);
		if(input_length > max_len)
		{
			return false;
		}
	}
	return true;
}
snfValidator.prototype.validateMinLen = function(input_value,rule)
{
	if(isset(input_value) )
	{
     	min_len=rule['params']['min_len'];
		input_length = strlen(input_value);
		if(input_length < min_len)
		{
			return false;
		}
	}
	return true;
}
snfValidator.prototype._validateRegExp = function(input_value,reg_exp)
{
    var ret=false;
    if (typeof reg_exp === 'string') {
		eval('var js_reg_exp = ' + reg_exp + ';');
		ret = js_reg_exp.test(input_value);
	}
	return ret;
}
snfValidator.prototype.validateRegExp = function(input_value,rule)
{
	reg_exp=rule['params']['reg_exp'];
	//reg_exp.replace(/(\\)/g, "\\$1");
	//document.write('<pre>' + reg_exp + '</pre>');
	//alert(reg_exp);
	return this._validateRegExp(input_value,reg_exp);
}
snfValidator.prototype.validateNumeric = function(input_value,rule)
{
	if(strlen(input_value)>0)
	{
		if(false == is_numeric(input_value))
		{
			return false;
		}
	}
	else
	{
		return false;
	}
	return true;
}
snfValidator.prototype.validateLessThanEq = function(input_value,rule)
{
	if(false == this.validateNumeric(input_value, rule))
	{
		return false;
	}
	else
	{
		less_than = doubleval(rule['params']['less_than']);
		float_inputval = doubleval(input_value);
		if(float_inputval > less_than)
		{
			return false;
		}
	}
	return true;
}
snfValidator.prototype.validateGreaterThanEq = function(input_value,rule)
{
	if(false == this.validateNumeric(input_value, rule))
	{
		return false;
	}
	else
	{
		greater_than = doubleval(rule['params']['greater_than']);
		float_inputval = doubleval(input_value);
		if(float_inputval < greater_than)
		{
			return false;
		}
	}
	return true;
}
snfValidator.prototype.validateLessThan = function(input_value,rule)
{
	if(false == this.validateNumeric(input_value, rule))
	{
		return false;
	}
	else
	{
		less_than = doubleval(rule['params']['less_than']);
		float_inputval = doubleval(input_value);
		if(float_inputval >= less_than)
		{
			return false;
		}
	}
	return true;
}
snfValidator.prototype.validateGreaterThan = function(input_value,rule)
{
	if(false == this.validateNumeric(input_value, rule))
	{
		return false;
	}
	else
	{
		greater_than = doubleval(rule['params']['greater_than']);
		float_inputval = doubleval(input_value);
		if(float_inputval <= greater_than)
		{
			return false;
		}
	}
	return true;
}
snfValidator.prototype.validateShouldSel = function(input_value,rule)
{
	if(is_array(input_value))
	{
		for (var value in input_value  )
		{
			if(!in_array(value, rule['params']['sel_set']))
			{
				return false;
			}
		}
	}
	else
	{
		if(!in_array(input_value, rule['params']['sel_set']))
		{
			return false;
		}
	}
	return true;
}
snfValidator.prototype.validateSelMin = function(input_value,rule)
{
	if(is_array(input_value))
	{
		if(input_value.length < rule['params']['sel_min'])
			return false;
 		}
 		else
 		{
		if(!isset(input_value) && rule['params']['sel_min'] > 0)
			return false;
	}
	return true;
}
snfValidator.prototype.validateSelMax = function(input_value,rule)
{
	if(is_array(input_value))
	{
		if(input_value.length > rule['params']['sel_max'])
			return false;
	}
		else
	{
		if(!isset(input_value))
			return false;
	}
	return true;
}
snfValidator.prototype.validateSelOne = function(input_value,rule)
{
	if(is_array(input_value))
	{
		if(input_value.length != 1)
			return false;
	}
	else
	{
		if(!isset(input_value))
			return false;
	}
	return true;
}
snfValidator.prototype.validateEqElmnt = function(input_value,rule)
{
	if(isset(input_value) )
	{
		element_name=rule['params']['element_name'];
		element_value=this.form.getElementValue(element_name);
		if(input_value != element_value)
		{
			return false;
		}
	}
	return true;
}
snfValidator.prototype.validateNeElmnt = function(input_value,rule)
{
	if(isset(input_value) )
	{
		element_name=rule['params']['element_name'];
		element_value=this.form.getElementValue(element_name);
		if(input_value == element_value)
		{
			return false;
		}
	}
	return true;
}
snfValidator.prototype.validateEq = function(input_value,rule)
{
	if(!isset(input_value))
		return false;
	if(input_value != rule['params']['eq_value'])
		return false;
	return true;
}
snfValidator.prototype.validateEqLen = function(input_value,rule)
{
	if(!isset(input_value))
		return false;
	if(strlen(input_value) != rule['params']['eq_len'])
		return false;
	return true;
}
snfValidator.prototype.validateCondition = function(input_value,rule,req_name)
{
	var bApply     = true;
	var conditions = rule['params']['conditions'];
	var not_set_error_msg        = true;
	var not_record_last          = true;
	for (var condition in conditions  )
	{
		var condition_req_name       = conditions[condition]['req_name'];
		var condition_input_value    = this.form.getElementValue(condition_req_name);
		not_set_error_msg        = true;
		not_record_last          = true;
		if(!this._doValidate(condition_req_name, conditions[condition]['rule'], not_set_error_msg, not_record_last))
			bApply = false;
	}
	if(bApply)
	{
		var condition_rule           = rule['params']['rule'];
		not_set_error_msg            = false;
		rule['params']['rule']['last_req_value'] = null;
		rule['params']['rule']['last_result']    = null;
		if(!this._doValidate(req_name, condition_rule, not_set_error_msg))
			return false;
	}
	return true;
}
snfValidator.prototype.doAllValidate = function()
{
	var bret0 = true;
	for (var rule in this.rules_chain  )
	{
		req_name       = this.rules_chain[rule]['req_name'];
		if(!this._doValidate(req_name, this.rules_chain[rule]['rule'], false))
		    bret0 = false;
	}
	return bret0;
}
snfValidator.prototype.doValidate = function(req_name)
{
	var bret1 = true;
	for (var rule in this.rules_chain  )
	{
		if(req_name == this.rules_chain[rule]['req_name'])
		{
			if(!this._doValidate(req_name, this.rules_chain[rule]['rule'], false))
		    	bret1 = false;
		}
	}
	return bret1;
}
snfValidator.prototype.checkEvnChanged = function(req_name,rule)
{
	// check if the input value of the element and the condition related elements not changed.
	var input_value = this.form.getElementValue(req_name);
	var b_env_changed = false;
	
	// last input information not recorded, deemed as changed.
	if(!isset(rule["last_req_value"]))
		return true;
	if(isset(rule["last_req_value"]) && rule["last_req_value"] != input_value)
	{
		rule["last_req_value"] = null;
		rule["last_result"] = null;
		rule["last_error_msg"] = null;
		return true;
	}
	if(rule['va_code'] == VA_CONDITION)
	{
		var conditions = rule['params']['conditions'];
		for (var condition in conditions  )
		{
			var condition_rule       = conditions[condition]['rule'];
			var condition_req_name   = conditions[condition]['req_name'];
			var condition_input_value = this.form.getElementValue(condition_req_name);
			// last input information not recorded, deemed as changed.
			if(!isset(condition_rule["last_req_value"]))
			{
				rule["last_req_value"] = null;
				rule["last_result"] = null;
				rule["last_error_msg"] = null;
				return true;
			}
			if(isset(condition_rule["last_req_value"]) && condition_rule["last_req_value"] != condition_input_value)
			{
				rule["last_req_value"] = null;
				rule["last_result"] = null;
				rule["last_error_msg"] = null;
				condition_rule["last_req_value"] = null;
				condition_rule["last_result"] = null;
				condition_rule["last_error_msg"] = null;
				return true;
			}
		}
	}
	return 	false;
}
snfValidator.prototype._doValidate = function(req_name,rule,not_set_error_msg,not_record_last)
{
	if(not_record_last == null)
		not_record_last = false;

	//if(rule['va_code'] == VA_CONDITION)
	//{
	//	not_set_error_msg = true;
	//}

	var input_value = this.form.getElementValue(req_name);

	if(!this.checkEvnChanged(req_name,rule))
	{
		if(rule["last_result"] == false)
			this.setErrorMsg(req_name, rule["last_error_msg"]);
		return rule["last_result"];
	}

	var error_msg      = isset(rule['error_msg']) ? rule['error_msg'] : null;
	var bret           = true;
	switch(rule['va_code'])
	{
	case VA_REQ:
	    {
	        if(!this.validateReq(input_value,rule))
	        {
	            bret=false;
	            if(!not_set_error_msg)
	                rule["last_error_msg"] = this.setErrorMsg(req_name, error_msg, E_VAL_REQUIRED_VALUE);
	        }
	        break;
	    }
	case VA_MAXLEN:
	    {
	        if(!this.validateMaxLen(input_value,rule))
	        {
	            bret=false;
	            if(!not_set_error_msg)
	                rule["last_error_msg"] = this.setErrorMsg(req_name, error_msg, E_VAL_MAXLEN_CHECK_FAILED, 'max_num', rule['params']['max_len']);
	        }
	        break;
	    }
	case VA_MINLEN:
	    {
	        if(!this.validateMinLen(input_value,rule))
	        {
	            bret=false;
	            if(!not_set_error_msg)
	                rule["last_error_msg"] = this.setErrorMsg(req_name, error_msg, E_VAL_MINLEN_CHECK_FAILED, 'min_num', rule['params']['min_len']);
	        }
	        break;
	    }
	case VA_ALNUM:
	    {
	        if(!this._validateRegExp(input_value,'/^[A-Za-z0-9]+$/i'))
	        {
	            bret=false;
	            if(!not_set_error_msg)
	                rule["last_error_msg"] = this.setErrorMsg(req_name, error_msg, E_VAL_ALNUM_CHECK_FAILED);
	        }
	        break;
	    }
	case VA_ALNUM_S:
	    {
	        if(!this._validateRegExp(input_value,'/[A-Za-z0-9 ]+$/i'))
	        {
	            bret=false;
	            if(!not_set_error_msg)
	                rule["last_error_msg"] = this.setErrorMsg(req_name, error_msg, E_VAL_ALNUM_S_CHECK_FAILED);
	        }
	        break;
	    }
	case VA_NUM:
	    {
	        if(!this._validateRegExp(input_value,'/^[0-9]+(\\.[0-9]+)?$/i'))
	        {
	            bret=false;
	            if(!not_set_error_msg)
	                rule["last_error_msg"] = this.setErrorMsg(req_name, error_msg, E_VAL_NUM_CHECK_FAILED);
	        }
	        break;
	    }
	case VA_ALPHA:
	    {
	        if(!this._validateRegExp(input_value,'/^[A-Za-z]+$/i'))
	        {
	            bret=false;
	            if(!not_set_error_msg)
	                rule["last_error_msg"] = this.setErrorMsg(req_name, error_msg, E_VAL_ALPHA_CHECK_FAILED);
	        }
	        break;
	    }
	case VA_ALPHA_S:
	    {
	        if(!this._validateRegExp(input_value,'/^[A-Za-z ]+$/i'))
	        {
	            bret=false;
	            if(!not_set_error_msg)
	                rule["last_error_msg"] = this.setErrorMsg(req_name, error_msg, E_VAL_ALPHA_S_CHECK_FAILED);
	        }
	        break;
	    }
	case VA_EMAIL:
	    {
	        if(!this._validateRegExp(input_value,'/^([^@\\s]+)@((?:[-a-z0-9]+\\.)+[a-z]{2,3})$/i'))
	        {
	            bret=false;
	            if(!not_set_error_msg)
	                rule["last_error_msg"] = this.setErrorMsg(req_name, error_msg, E_VAL_EMAIL_CHECK_FAILED);
	        }
	        break;
	    }
	case VA_URL:
	    {
	        reg_exp = '/^(https?|ftps?):\\/\\/(([a-z0-9-]+\\.)+[a-z]{2,6}|\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})(:[0-9]+)?(\\/?|\\/\\S+)$/i';
	        
	        if(!this._validateRegExp(input_value, reg_exp))
	        {
	            bret=false;
	            if(!not_set_error_msg)
	                rule["last_error_msg"] = this.setErrorMsg(req_name, error_msg, E_VAL_URL_CHECK_FAILED);
	        }
	        break;
	    }
	case VA_LESSTHANEQ:
	    {
	        if(!this.validateLessThanEq(input_value,rule))
	        {
	            bret=false;
	            if(!not_set_error_msg)
	                rule["last_error_msg"] = this.setErrorMsg(req_name, error_msg, E_VAL_LESSTHANEQ_CHECK_FAILED, 'max_num', rule['params']['less_than']);
	        }
	        break;
	    }
	case VA_GREATERTHANEQ:
	    {
	        if(!this.validateGreaterThanEq(input_value,rule))
	        {
	            bret=false;
	            if(!not_set_error_msg)
	                rule["last_error_msg"] = this.setErrorMsg(req_name, error_msg, E_VAL_GREATERTHANEQ_CHECK_FAILED, 'min_num', rule['params']['greater_than']);
	        }
	        break;
	    }
	case VA_LESSTHAN:
	    {
	        if(!this.validateLessThan(input_value,rule))
	        {
	            bret=false;
	            if(!not_set_error_msg)
	                rule["last_error_msg"] = this.setErrorMsg(req_name, error_msg, E_VAL_LESSTHAN_CHECK_FAILED, 'max_num', rule['params']['less_than']);
	        }
	        break;
	    }
	case VA_GREATERTHAN:
	    {
	        if(!this.validateGreaterThan(input_value,rule))
	        {
	            bret=false;
	            if(!not_set_error_msg)
	                rule["last_error_msg"] = this.setErrorMsg(req_name, error_msg, E_VAL_GREATERTHAN_CHECK_FAILED, 'min_num', rule['params']['greater_than']);
	        }
	        break;
	    }
	case VA_REGEXP:
	    {
	        if(!this.validateRegExp(input_value,rule))
	        {
	            bret=false;
	            if(!not_set_error_msg)
	                rule["last_error_msg"] = this.setErrorMsg(req_name, error_msg, E_VAL_REGEXP_CHECK_FAILED);
	        }
	        break;
	    }
	case VA_SHOULDSEL:
	    {
	        if(!this.validateShouldSel(input_value,rule))
	        {
	            bret=false;
	            if(!not_set_error_msg)
	                rule["last_error_msg"] = this.setErrorMsg(req_name, error_msg, E_VAL_SHOULDSEL_CHECK_FAILED);
	        }
	        break;
	    }
	case VA_SELMAX:
	    {
	        if(!this.validateSelMax(input_value,rule))
	        {
	            bret=false;
	            if(!not_set_error_msg)
	                rule["last_error_msg"] = this.setErrorMsg(req_name, error_msg, E_VAL_SELMAX_CHECK_FAILED, 'max_num', rule['params']['sel_max']);
	        }
	        break;
	    }
	case VA_SELMIN:
	    {
	        if(!this.validateSelMin(input_value,rule))
	        {
	            bret=false;
	            if(!not_set_error_msg)
	                rule["last_error_msg"] = this.setErrorMsg(req_name, error_msg, E_VAL_SELMIN_CHECK_FAILED, 'min_num', rule['params']['sel_min']);
	        }
	        break;
	    }
	case VA_SELONE:
	    {
	        if(!this.validateSelOne(input_value,rule))
	        {
	            bret=false;
	            if(!not_set_error_msg)
	                rule["last_error_msg"] = this.setErrorMsg(req_name, error_msg, E_VAL_SELONE_CHECK_FAILED);
	        }
	        break;
	    }
	case VA_EQELMNT:
	    {
	        if(!this.validateEqElmnt(input_value,rule))
	        {
	            bret=false;
	            if(!not_set_error_msg)
	                rule["last_error_msg"] = this.setErrorMsg(req_name, error_msg, E_VAL_EQELMNT_CHECK_FAILED, 'comp_req_name', rule['params']['element_name']);
	        }
	        break;
	    }
	case VA_NEELMNT:
	    {
	        if(!this.validateNeElmnt(input_value,rule,req_data))
	        {
	            bret=false;
	            if(!not_set_error_msg)
	                rule["last_error_msg"] = this.setErrorMsg(req_name, error_msg, E_VAL_NEELMNT_CHECK_FAILED, 'comp_req_name', rule['params']['element_name']);
	        }
	        break;
	    }
	case VA_EQ:
	    {
	        if(!this.validateEq(input_value,rule))
	        {
	            bret=false;
	            if(!not_set_error_msg)
	                rule["last_error_msg"] = this.setErrorMsg(req_name, error_msg, E_VAL_EQ_CHECK_FAILED, 'equal_value', rule['params']['eq_value']);
	        }
	        break;
	    }
	case VA_CONDITION:
	    {
	        if(!this.validateCondition(input_value,rule,req_name))
	        {
	            bret=false;
	        }
	        break;
	    }
	case VA_REMOTE_CHECK:
		{
			//this.form.renderWaiting(req_name);
	        if(!this.validateRemoteCheck(req_name,input_value,rule))
	        {
	            bret=false;
	            if(!not_set_error_msg)
	                rule["last_error_msg"] = this.setErrorMsg(req_name, error_msg, E_VAL_REMOTE_CHECK_FAILED);
	        }
	        //this.form.clearWaiting(req_name);
	        break;
		}
	case VA_EQLEN:
	    {
	        if(!this.validateEqLen(input_value,rule))
	        {
	            bret=false;
	            if(!not_set_error_msg)
	                rule["last_error_msg"] = this.setErrorMsg(req_name, error_msg, E_VAL_EQLEN_CHECK_FAILED, 'equal_len', rule['params']['eq_len']);
	        }
	        break;
	    }
	}
	if(!not_record_last)
	{
		rule["last_req_value"] = input_value;
		rule["last_result"]    = bret;
	}
	return bret;
}

var snf_form_array = new Array();
var snf_validator_array = new Array();

function snfValidateAll(form_id)
{
	var var_form = snf_form_array[form_id];
	var var_validator = snf_validator_array[form_id];
	
	var element_name_list = new Array();
	for (var rule in var_validator.rules_chain  )
	{
		var req_name = var_validator.rules_chain[rule]['req_name'];
		var b_dup = false;
		var length = element_name_list.length;
		for(var i = 0; i < length; i++)
		{
			if(element_name_list[i] == req_name)
			{
				b_dup = true;
				break;
			}
		}
		if(!b_dup)
		{
			element_name_list[length] = req_name;
		}
	}
	
	var bret = true;
	var length = element_name_list.length;
	for(var i = 0; i < length; i++)
	{
		if(!snfValidate(form_id, element_name_list[i]))
			bret = false;
	}
	if(bret == false)
	{
		alert(E_VAL_CHECK_ALL_FAILED);
	}
	return bret;
}
function snfValidate(form_id, element_name)
{
	var var_form = snf_form_array[form_id];
	var var_validator = snf_validator_array[form_id];

	var bret=true;
	if(isset(var_form) && isset(var_validator))
	{
		var_form.clearErrorMsg(element_name);
		if(!var_validator.doValidate(element_name))
		{
			var_form.renderError(element_name);
			bret = false;
		}
		else
			var_form.clearError(element_name);
		
		appendDebugMsg('check for condition related element for ' + element_name);
		for (var rule in var_validator.rules_chain  )
		{
			var r_rule = var_validator.rules_chain[rule]['rule'];
			var r_req_name = var_validator.rules_chain[rule]['req_name']
			if(r_rule['va_code'] == VA_CONDITION)
			{
				var conditions = r_rule['params']['conditions'];
				for (var condition in conditions  )
				{
					condition_req_name       = conditions[condition]['req_name'];
					if(condition_req_name == element_name)
					{
						appendDebugMsg('related element find: ' + r_req_name);
						var_form.clearErrorMsg(r_req_name);
						if(!var_validator.doValidate(r_req_name))
						{
						    appendDebugMsg('validate failed, render error!');
							var_form.renderError(r_req_name);
							bret = false;
						}
						else
						{
							appendDebugMsg('validate ok!');
							var_form.clearError(r_req_name);
						}
					}
				}
			}
		}
		appendDebugMsg('check for condition related element for ' + element_name + ' OK!');
	}
	return bret;
}
