
function fc_parseExpressionSet(srule){	
	var expressionSet = [];
	var expressions = srule.split(" ");
	for(var i=0; i<expressions.length; i++){
		expressionSet = expressionSet.concat(fc_parseExpression(expressions[i]));
	}
	return expressionSet;
}

function fc_parseExpression(expression){	
	var reg = new RegExp("==|!=|>=|<=|>|<");
	var operator = reg.exec(expression);	
	if(operator) {		
		var fields = expression.split(operator);
		return {
			selector: fields[0], 
			operator: operator, 
			value: fields[1],
			negative: false
			};
	} else {		
		if(expression.indexOf("!")==-1) {
			return {
				selector: expression,
				negative: false
				};
		} else {			
			return {				
				selector: expression.substring(1,expression.length), 
				negative: true
				};
		}
	}
}

function fc_evaluateExpressionSet(expressionSet){	
	var check = true;
	for(var i=0; i<expressionSet.length; i++){
		check = check && fc_evaluateExpression(expressionSet[i]);
	}
	return check;
}

function fc_evaluateExpression(expression){
	var evaluation = false;
	var formula = "";
	if (expression.operator){
		var selector = $("#"+expression.selector).val();

		var field = fc_getFieldValue(expression.selector);		
		var value = fc_getFieldValue(expression.value);
		formula = field + expression.operator + value;
		//alert(formula);
		eval("evaluation = (" + formula + ")");
	} else {
		if(expression.selector.indexOf("(")!=-1 && expression.selector.indexOf(")")!=-1){
			var myfun = expression.selector.substring(0,expression.selector.indexOf("("));
			var myfield = expression.selector.substring(expression.selector.indexOf("(")+1,expression.selector.indexOf(")"));
			myfun = "fc_rule_function_" + myfun;
			formula = myfun.toLowerCase() + "(" + fc_getFieldValue(myfield) + ")"; 
			//alert(formula);
			eval("evaluation = (" + formula + ")");
			if(expression.negative==true){
				if(evaluation) evaluation = false;
				else evaluation = true;
			}			
		} else {
			if(expression.selector=="") return true;
			if(expression.selector=="!") return false;
			evaluation = $("#"+expression.selector).attr('checked');
			if(expression.negative==true) {
				if(evaluation) evaluation = false;
				else evaluation = true;
			}
		}
	}
	return evaluation;
}

function fc_getFieldValue(raw){
	var value = raw;
	if(fc_isNumber(value)){
		if(value.length==0) value = "'" + value + "'";
		// anything else?
	} else {
		if(value.indexOf("'")==-1) {
			value = $("#"+value).val();
			if(fc_isNumber(value)){
				if(value.length==0) value = "'" + value + "'";
				// anything else?
			} else {				
				value = "'" + value + "'";	
			}				
		}
	}
	return value;
}

function fc_isNumber(sText){	
//	if(!sText){
//		return false;
//	} else {
//		if(sText=='') return false;
//		else {
		   var ValidChars = "0123456789.-";
		   var IsNumber=true;
		   var Char; 
		   for (var i = 0; i < sText.length && IsNumber == true; i++) { 
		      Char = sText.charAt(i); 
		      if (ValidChars.indexOf(Char) == -1) IsNumber = false;      
		   }
		   return IsNumber;   
//		}
//	} 
 }

function fc_rule_function_isnumber(value){
	//alert("stext: " + value);
	return fc_isNumber(value);
}


//function isNumeric(sText,decimals,negatives) {
//	var isNumber=true;
//	var numDecimals = 0;
//	var validChars = "0123456789";
//	if (decimals)  validChars += ".";
//	if (negatives) validChars += "-";
//	var thisChar;
//	for (i = 0; i < sText.length && isNumber == true; i++) {  
//		thisChar = sText.charAt(i); 
//		if (negatives && thisChar == "-" && i > 0) isNumber = false;
//		if (decimals && thisChar == "."){
//			numDecimals = numDecimals + 1;
//			if (i==0 || i == sText.length-1) isNumber = false;
//			if (numDecimals > 1) isNumber = false;
//		}
//		if (validChars.indexOf(thisChar) == -1) isNumber = false;
//	}
//	return isNumber;
//}


function fc_parseRule(srule,scontext,infoMessage,warningMessage,errorMessage,echos){
	rule = {};
	rule.expressions = fc_parseExpressionSet(srule);
	if(fc_validateString(scontext)) rule.context = fc_parseExpressionSet(scontext);
	if(fc_validateString(infoMessage)) rule.infoMessage = infoMessage;
	if(fc_validateString(warningMessage)) rule.warningMessage = warningMessage;
	if(fc_validateString(errorMessage)) rule.errorMessage = errorMessage;
	if(fc_validateString(echos)) rule.echos = echos;
	return rule;
}

function fc_validateString(cad){
	if(cad && cad!=null && cad!="") return true;
	return false;
}

function fc_checkRule(rule){	
	var mustEvaluate = true;
	if(rule.context){		
		if(!fc_evaluateExpressionSet(rule.context)) mustEvaluate = false;
	}	
	if(mustEvaluate==true){
		//if(rule.context) alert("evaluating: " + fc_evaluateExpressionSet(rule.expressions));
		return fc_evaluateExpressionSet(rule.expressions);
	} else {
		return false;
	}
}

function fc_checkRuleSet(rules){
	var checking = {};
	// counters
	checking.infos = 0;
	checking.warnings = 0;
	checking.errors = 0;
	checking.mismatches = 0;
	// messages
	checking.infoMessages = [];
	checking.errorMessages = [];
	checking.warningMessages = [];
	// echos
	checking.echos = [];	
	for(var i=0; i<rules.length; i++){
		if(fc_checkRule(rules[i])){
			checking.mismatches++;
			if(rules[i].infoMessage) {
				checking.infos++;
				checking.infoMessages = checking.infoMessages.concat(rules[i].infoMessage);
			}
			if(rules[i].warningMessage) {
				checking.warnings++;
				checking.warningMessages = checking.warningMessages.concat(rules[i].warningMessage);
			}
			if(rules[i].errorMessage) {
				checking.errors++;
				checking.errorMessages = checking.errorMessages.concat(rules[i].errorMessage);
			}
			if(rules[i].echo) checking.echos = checking.echos.concat(rules[i].echo.split(" "));
		}
	}
	return checking;
}


function fc_validate(source) {		
	var errors = 0;	
	//if($("#" + source.id).attr("disabled")==true) alert(source.id);
	if($("#" + source.id) && ($("#" + source.id).attr("disabled")==undefined || $("#" + source.id).attr("disabled")==false)){
		//if($("#" + source.id).attr("disabled")==false) {
		//alert(source.id + " -> " + $("#" + source.id) + " : " +  $("#" + source.id).attr("disabled"));
		if(source.validationRules && source.validationRules.length>0){
			var checking;
			//try { 
			    checking = fc_checkRuleSet(source.validationRules);
//			} catch (error){
//			    alert("JORL: " + error);
//			}
			source.cleanMessages();
			if(checking.infos>0) source.reportInfo(checking.infoMessages.join('\n'),checking.echos);
			if(checking.warnings>0) source.reportWarning(checking.warningMessages.join('\n'),checking.echos);
			if(checking.errors>0) source.reportError(checking.errorMessages.join('\n'),checking.echos);		
			// validate recursively children
			errors = checking.errors;
		}
	}
	if(source.children) {
		for(var i=0; i<source.children.length; i++){
			errors += fc_validate(source.children[i]);
		}		
	}	
	return errors;
}



//function validate(source){
//	var errors = 0;
//	var message = "";
//	var echos = [];
//	if (source.validationRules.length>0){
//		for(var i=0; i<source.validationRules.length; i++){			
//			var evaluate = true;
//			if(source.validationRules[i].contextRules){			
//				if(!evaluateRules(source.validationRules[i].contextRules)) evaluate = false;
//			}
//			//own evaluation
//			if(evaluate){				
//				if(!evaluateRule(source.validationRules[i].rule)){
//					errors++;
//					message+= source.validationRules[i].errorMessage + "\n";					
//					if(source.validationRules[i].echo) echos = echos.concat(source.validationRules[i].echo.split(" "));
//				}
//			}
//		}
//		if(errors>0) source.reportError(message,echos);
//		else source.cleanMessages();
//	}
//	for(var i=0; i<source.children.length; i++){
//		errors+=validate(source.children[i]);
//	}
//	return errors;
//}
//
//
//function parseValidationRule(rule,errorMessage,context){
//	var validationRule = {};
//	validationRule.rule = parseRule(rule);
//	validationRule.errorMessage = errorMessage;
//	if(context){
//		var crules = context.split(" ");
//		validationRule.contextRules = [];
//		for(var i=0; i<crules.length;i++){
//			validationRule.contextRules = validationRule.contextRules.concat(parseRule(crules[i]));
//		}
//	}
//	return validationRule;
//}
