// < business rules >


function encodeURL(identifier, params, engine, field, data) {
	var result = "";
	for (var parameterIndex = 0; parameterIndex < params.length; parameterIndex++) {
		result += escape(params.getStringValue(parameterIndex));
	}
	return result;
}


function IsEqualBusinessRule_execute(identifier, params, engine, field, data) {
	if (params.length != 2) {
		logger.error("The isEqual rule requires exactly two parameters");
	}
	return params.getStringValue(0) == params.getStringValue(1);
}

function isEqual(identifier, params, engine, field, data) {
	if (params.length != 2) {
		logger.error("The isEqual rule requires exactly two parameters");
	}
	return params.getStringValue(0) == params.getStringValue(1);
}

function GetValueBusinessRule_execute(identifier, params, engine, field, data) {
	if (params.length > 1) {
		logger.error("Invalid number of parameters. Either supply the name of the field as parameter or specify no parameters (the value of the current field is returned).");
		return undefined;
	} else {
		// determine the field of which we're to get the value
		var targetField;
		if (params.length == 0) {
			targetField = field;
		} else {
			targetField = engine.getForm().getFieldForFieldName(params.getStringValue(0));
		}
		// return the value of the field
		return engine.getForm().getValueForField(engine, data, targetField);
	}
}

function GetDisplayValueBusinessRule_execute(identifier, params, engine, field, data) {

	// check the number of parameters
	if (params.length > 1) {
		logger.error("Invalid number of parameters. Either supply the name of the field as a parameter or specify no parameters (the display value of the current field is returned).");
		return undefined;
	}

	// determine the field of which the display value is requested
	var targetField;
	if (params.length == 0) {
		targetField = field;
	} else {
		targetField = engine.getForm().getFieldForFieldName(params.getStringValue(0));
	}

	// invoke the GetDisplayValue behaviour for targetField
	var result = engine.getForm().invokeBehaviourOnField(engine, "GetDisplayValue", data, targetField);
	if (result == undefined) {
		// no result was returned; return the value of the field instead.
		result = engine.getForm().getValueForField(engine, data, targetField);
	}

	return result;
}

function SetValueBusinessRule_execute(identifier, params, engine, field, data) {
	if (params.length == 2) {
		var fieldName = params.getStringValue(0);
		var value = params.getStringValue(1);
		if (value == undefined) {
			value = "";
		}
		var valueField = engine.getForm().getFieldForFieldName(fieldName);
		engine.getForm().setValueForField(engine, data, valueField, value);
		return value;
	} else {
		logger.error("The setValue rule requires exactly two parameters: the name of the field for which to retrieve the value and the value to which to set the field.");
		return undefined;
	}
}

function SetErrorMsgBusinessRule_execute(identifier, params, engine, field, data) {
	if (params.length == 2) {
		var isValid = engine.execute(params[0], field);
		if (!isValid) {
			logger.info("validate: it is not valid");
			var errorMsg = params.getStringValue(1);
			BusinessRulesEngine_setErrorMsgForFieldName(field.id, errorMsg);
		}
		return isValid;
	} else {
		logger.error("The validate business rule requires exactly two parameters: the boolean condition to check and the error msg to set on the field if the condition is false");
		return undefined;
	}
}

function IsNotEmptyBusinessRule_execute(identifier, params, engine, field, data) {
	var value;
	if (!params || params.length == 0) {
		value = engine.getForm().getValueForField(engine, data, field);
	} else if (params.length == 1) {
		value = params.getStringValue(0);
	} else {
		logger.error("The isNotEmpty rule requires at most one parameter");
	}

	var result = true;
	logger.info("IsNotEmptyBusinessRule_execute: value="+value);
	if (!value || value == null || value.toString().replace(/^\s*|\s*$/g,"").length == 0) {
		logger.info("isNotEmpty: empty value detected, isNotEmpty=false");
		result = false;
	}
	return result;
}

function isNotEmpty(identifier, params, engine, field, data) {
	var value;
	if (!params || params.length == 0) {
		value = engine.getForm().getValueForField(engine, data, field);
	} else if (params.length == 1) {
		value = params.getStringValue(0);
	} else {
		logger.error("The isNotEmpty rule requires at most one parameter");
	}

	var result = true;
	logger.info("isNotEmpty: value="+value);
	if (!value || value == null || value.toString().replace(/^\s*|\s*$/g,"").length == 0) {
		logger.info("isNotEmpty: empty value detected, isNotEmpty=false");
		result = false;
	}
	return result;
}

function IsEmptyBusinessRule_execute(identifier, params, engine, field, data) {
	var value;
	if (!params || params.length == 0) {
		value = engine.getForm().getValueForField(engine, data, field);
	} else if (params.length == 1) {
		value = params.getStringValue(0);
	} else {
		logger.error("The isEmpty rule requires at most one parameter");
	}

	var result = false;
	logger.info("value="+value);
	if (!value || value == null || value.toString().replace(/^\s*|\s*$/g,"").length == 0) {
		logger.info("isEmpty: empty value detected, isEmpty=true");
		result = true;
	}
	return result;
}


function IsInRangeBusinessRule_execute(identifier, params, engine, field, data) {
	logger.enterMethod("isInRange("+identifier+", "+field+")");
	var result;
	var minValue;
	var maxValue;
	if (params.length != 3) {
		logger.error("isInRange requires exactly three parameters: the value to check, the minimum value and the maximum value");
	} else {
		var doubleValue = params.getDoubleValue(0);
		if (doubleValue) {
			logger.info("isInRange: doubleValue="+doubleValue);
			minValue = params.getDoubleValue(1, Number.NEGATIVE_INFINITY);
			maxValue = params.getDoubleValue(2, Number.POSITIVE_INFINITY);
			logger.info("isInRange: checking whether number "+doubleValue+" is in ["+minValue+","+maxValue+"]");
			result = (doubleValue >= minValue && doubleValue <= maxValue);
		} else {
			var dateValue = engine.getDateParameter(field, params[0]);
			if (dateValue) {
				minValue = params.getDateValue(1);
				maxValue = params.getDateValue(2);
				logger.info("isInRange: checking whether date " + dateValue + " is in [" + minValue + ", " + maxValue + "]");
				result = true;
				if (minValue) {
					result = result && (dateValue >= minValue);
				}
				if (maxValue) {
					result = result && (dateValue <= maxValue);
				}
			} else {
				logger.error("Checking whether "+value+" is in range is not supported");
			}
		}
	}
	logger.exitMethod();
	return result;
}

function GetLengthBusinessRule_execute(identifier, params, engine, field, data) {
	var result;
	if (params.length != 1) {
		logger.error("length requires exactly one parameter: the value to return the length of");
	} else {
		var value = params.getStringValue(0);
		if (value) {
			result = value.length;
		} else {
			// no value -> length is 0
			result = 0;
		}
	}
	return result;
}

function BooleanBusinessRules_matches(identifier) {
	return "not" == identifier || "and" == identifier || "or" ==  identifier || "boolean" ==  identifier;
}

function BooleanBusinessRules_execute(identifier, params, engine, field, data) {
	var result;
	var i;
	if ("not" == identifier) {
		if (params.length != 1) {
			logger.error("This business rule requires exactly one parameter: the boolean value to negate.");
		}
		result = params.getBooleanValue(0);
		result = ! result;
	} else if ("and" == identifier) {
		result = true;
		for (i = 0; result && i < params.length; i++) {
			result = result && params.getBooleanValue(i);
		}
	} else if ("or" == identifier) {
		result = false;
		for (i=0; !result && i < params.length; i++) {
			result = result || params.getBooleanValue(i);
		}
	} else if ("boolean" == identifier) {
		if (params.length != 1) {
			logger.error("This business rule requires exactly one parameter: the value to interpret as a boolean.");
		}
		result = params.getBooleanValue(0);
	} else {
		logger.error("This function doesn't handle business rules named '"+identifier+"'");
	}
	return result;
}

function RegexBusinessRule_matches(identifier) {
	return "regex" == identifier || "regularExpression" == identifier;
}

function RegexBusinessRule_execute(identifier, params, engine, field, data) {
	// check if the number of parameters is valid
	if ((params.length == 0) || (params.length > 2)) {
		logger.error("A regular expression requires one or two parameters.");
	}

	// evaluate the parameter containing the regular expression
	// note that because the entire string must be matched by a regular expression so we surround the
	// regular expression with ^ (start of string) and $ (end of string).
	var pattern = "^" + params.getStringValue(0) + "$";

	// look up the value that must be matched against the regular expression
	var value;
	if (params.length == 1) {
		value = engine.getForm().getValueForField(engine, data, field);
	} else {
		value = params.getStringValue(1);
	}
	if (value == undefined) {
		value = "";
	}

	var result = (value.search(pattern) > -1);

	logger.info("regularExpression('" + value + "', '" + pattern + "') = " + result);

	return result;
}

function DateBusinessRules_matches(identifier) {
	return "today" == identifier || "formatDate" == identifier || "date" == identifier || "addToDate" == identifier;
}

function DateBusinessRules_execute(identifier, params, engine, field, data) {
	var result;
	var date;
	if ("today" == identifier) {
		if (params.length != 0) {
			logger.error("The today rule takes no parameters.");
		}
		var now = new Date();
		result = new Date(now.getFullYear(), now.getMonth(), now.getDate());
	} else if ("formatDate" == identifier) {
		if (params.length == 2) {
			date = params.getDateValue(0);
			if (date == undefined) {
				logger.error("formatDate: unable to determine the date (first parameter).");
			} else {
				var format = params.getStringValue(1);
				if (format == undefined) {
					logger.error("formatDate: unable to determine the format (second parameter).");
				} else {
					result = formatDate(date, format);
				}
			}
		} else {
			logger.error("The formatDate rule requires exactly two parameters: the date to format and the formatting string.");
		}
	} else if ("date" == identifier) {
		if (params.length == 1) {
			// try to parse the single parameter value into a date
			result = params.getDateValue(0);
		} else if (params.length == 3) {
			var year = params.getIntValue(0);
			var month = params.getIntValue(1);
			var day = params.getIntValue(2);
			if (year != undefined || month != undefined || day != undefined) {
				result = new Date(year, month - 1, day);
			}
		} else {
			logger.error("The date rule requires exactly one or three parameters: the value to interpret as a Boolean. You passed "+params.getLength()+" parameters");
		}
	} else if ("addToDate" == identifier) {
		if (params.length != 3) {
			logger.error("The addToDate rule requires three parameters: the date, the amount, and the unit.");
		} else {
			// retrieve the values of the parameters
			date = params.getDateValue(0);
			if (date == undefined) {
				logger.error("addToDate: could not determine the date value (first parameter).");
			}
			var amount = params.getIntValue(1);
			if (amount == undefined) {
				logger.error("addToDate: could not determine the amount value (second parameter).");
			}
			var unit = params.getStringValue(2);
			if (unit == undefined) {
				logger.error("addToDate: could not determine the unit value (third parameter).");
			}
			// now perform the actual addition
			if (unit == "day") {
				date.setDate(date.getDate() + amount);
			} else if (unit == "week") {
				date.setDate(date.getDate() + (7 * amount));
			} else if (unit == "month") {
				date.setMonth(date.getMonth() + amount);
			} else if (unit == "year") {
				date.setFullYear(date.getFullYear() + amount);
			} else {
				logger.error("addToDate: invalid unit specified: " + unit);
			}
			result = date;
		}
	} else {
		logger.error("This function doesn't handle business rules named '"+identifier+"'");
	}
	return result;
}

function ConcatBusinessRule_execute(identifier, params, engine, field, data) {
	var result = "";
	for (var parameterIndex = 0; parameterIndex < params.length; parameterIndex++) {
		var value = params.getStringValue(parameterIndex);
		if (value) {
			result += params.getStringValue(parameterIndex);
		}
	}
	return result;
}

function DelimitedConcatBusinessRule_execute(identifier, params, engine, field, data) {

	// check if the number of parameters is valid
	if (params.length < 1) {
		logger.error("This business rule requires at least one parameter containing the delimiter.");
	}

	// look up the delimiter
	var delimiter = params.getStringValue(0);
	if (delimiter == undefined) {
		logger.error("delimiter == undefined.");
	}

	// look up the values that must be taken into the result
	var values = new Array();
	for (var parameterIndex = 1; parameterIndex < params.length; parameterIndex++) {
		var parameterValue = params.getStringValue(parameterIndex);
		if ((parameterValue != undefined) && (parameterValue != "")) {
			values.push(parameterValue);
		}
	}

	// construct the result string
	var result = "";
	for (var valueIndex = 0; valueIndex < values.length; valueIndex++) {
		result += values[valueIndex];
		if (valueIndex < (values.length - 1)) {
			result += delimiter;
		}
	}

	return result;
}

function IsValueSelectedBusinessRule_execute(identifier, params, engine, field, data) {

	// check if the number of parameters is valid
	if (params.length != 1) {
		logger.error("The isValueSelected business rule requires one parameter.");
	}

	var value = params.getStringValue(0);
    if (value == undefined) {
    	logger.error("Could not determine value for which to check if it was selected in field: " + field.id);
    }

    return engine.containsValueForFieldName(field.id, value);
}

function IsValidBusinessRule_execute(identifier, params, engine, field, data) {

	// check if the number of parameters is valid
	if (params.length != 1) {
		logger.error("This business rule requires one parameter: the id of the field.");
	}

	// evaluate the parameter containing the fieldname
	var fieldName = params.getStringValue(0);
	if (fieldName == undefined) {
		logger.error("Could not determine the id of the field.");
	}

	// look up the current error message of the field (if any) to validate and clear it
	var errorMessage = null;
	if (engine.existsErrorMsgForFieldName(fieldName)) {
		errorMessage = engine.getErrorMsgForFieldName(fieldName);
		engine.clearErrorMsgForFieldName(fieldName);
	}

	// invoke the Validate behaviour
	var fieldToValidate = engine.getForm().getFieldForFieldName(fieldName);
	engine.invokeBehaviourOnField("Validate", fieldToValidate);
	var isValid = !engine.existsErrorMsgForFieldName(fieldName);
	logger.info("isValid('" + fieldName + "') = " + isValid);

	// reset the error message
	if (errorMessage == null) {
		engine.clearErrorMsgForFieldName(fieldName);
	} else {
		engine.setErrorMsgForFieldName(fieldName, errorMessage);
	}

	return isValid;
}

function GetLabelOfItemBusinessRule_execute(identifier, params, engine, field, data) {

	// check if the number of parameters is valid
	if ((params.length == 0) || (params.length > 2)) {
		logger.error("This business rule expects one or two parameters (the item value and optionally a key.");
	}

	// evaluate the parameter containing the item value
	var value = params.getStringValue(0);
	if (value == undefined) {
		logger.error("Invalid value supplied to the " + identifier + " business rule.");
	}

	// currently multiple itemsets are not supported client-side, so we ignore the second parameter
	// (if specified)

	// look up the label of the item
	var label = engine.getLabelOfItemForFieldName(value, field.id);

	// If label is missing, use value instead
	if (!label || label == null) {
		label = value;
	}

	return label;
}

// </ business rules >
