// <m name="Form Validator"
//    author="Edwin Rijvordt (erijvordt@consultdata.nl)"
//    version="1.0"
//    type="component"
//    language="JavaScript"> Client-side generic Javascript validator class for HTML input fields.
// </m>

// Special formats, corresponding to the format strings #pct, #amt_pos, #amt
// and #max999 respectively.  Note that if these are modified, the same changes
// must be made to the expressions in fciBusiness.MessageValidator.
var FMT_PERCENTAGE = "^((\\.\\d{1,4})|(\\d{1,2}(\\.\\d{1,4})?)|100(\\.0{1,4})?)$";
var FMT_AMOUNT_POS = "^((\\.\\d{1,2})|(\\d{1,14}(\\.\\d{1,2})?))$";
var FMT_AMOUNT     = "^-?((\\.\\d{1,2})|(\\d{1,14}(\\.\\d{1,2})?))$";
var FMT_MAX999     = "^\\d{1,3}$";

function Validator(alertHandler) {
    this.alert = Validator_alert;
    this.addField = Validator_addField;
    this.setFields = Validator_setFields;
    this.validate = Validator_validate;
    this.validateField = Validator_validateField;
    this.validateFormat = Validator_validateFormat;
    this.evalFunction = Validator_evalFunction;
    this.fixLimits = Validator_fixLimits;

    this.checkRequired = true;
    this.alertHandler = alertHandler;
    this.fields = new Array();
}

function ValidatedField(name) {
    this.name = name;
}

function Validator_alert(msg) {
    if (this.alertHandler != null) {
		this.alertHandler.alert(msg);
    } else {
        alert(msg);
    }
}

function Validator_addField(name, label, type, required, minLength, maxLength, minValue, maxValue, format, options) {
    var f = new ValidatedField(name);
    f.name = name;
    f.label = label;
    f.type = type;
    f.required = required;
    f.minLength = minLength;
    f.maxLength = maxLength;
    f.minValue = minValue;
    f.maxValue = maxValue;
    f.format = format;
    f.options = options;
    this.fields[this.fields.length] = f;
}

function Validator_setFields(arr) {
    this.fields = new Array();
    for( var i = 0; i < arr.length; i += 10 ) {
        if (arr[i] == null) {
            break;
        }
        this.addField(arr[i], arr[i+1], arr[i+2], arr[i+3], arr[i+4],
                      arr[i+5], arr[i+6], arr[i+7], arr[i+8], arr[i+9]);
    }
}

function Validator_validate(form) {
    for( var i = 0; i < this.fields.length; ++i ) {
        var f = this.fields[i];
        if (!this.validateField(f, form)) {
            return false;
        }
    }
    return true;
}

function Validator_fixLimits(type, min, max) {
    if (min != -1 && max != -1) {
        return [min, max];
    }
    if (type == "i1") {
        if (min == -1) { min = -128; }
        if (max == -1) { max = 127; }
    } else if (type == "i2") {
        if (min == -1) { min = -32768; }
        if (max == -1) { max = 32767; }
    } else if (type == "i4") {
        if (min == -1) { min = -2147483648; }
        if (max == -1) { max = 2147483647; }
    } else if (type == "i8") {
        if (min == -1) { min = -9223372036854775808; }
        if (max == -1) { max = 9223372036854775807; }
	} else if (type == "ui1") {
        if (min == -1) { min = 0; }
        if (max == -1) { max = 255; }
    } else if (type == "ui2") {
        if (min == -1) { min = 0; }
        if (max == -1) { max = 65535; }
    } else if (type == "ui4") {
        if (min == -1) { min = 0; }
        if (max == -1) { max = 4294967295; }
    } else if (type == "ui8") {
        if (min == -1) { min = 0; }
        if (max == -1) { max = 18446744073709551615; }
    }
    return [min, max];
}

function Validator_validateFormat(field, form, value) {
    if (!field.required && value.length == 0) {
        // Assume the 'field is required' error has already been given earlier.
        return true;
    }

    var format = field.format;
    var label = format;
    if (format == "#pct") {
        format = FMT_PERCENTAGE;
        label = "percentage (0..100.0000)";
    } else if (format == "#amt") {
        format = FMT_AMOUNT;
        label = "money amount ([-]N14.2)";
    } else if (format == "#amt_pos") {
        format = FMT_AMOUNT_POS;
        label = "positive money amount (N14.2)";
    } else if (format == "#max999") {
        format = FMT_MAX999;
        label = "number between 0 and 999";
    }
	var re = new RegExp(format);
	if (!re.test(value)) {
		setConstraintsError(MsgHandler.invalidFormat(field.label, label, format == field.format));
		this.alert(getConstraintsError());
		form[field.name].focus();
		return false;
	}
    return true;
}

function Validator_evalFunction(field, form, value) {
    var funcName = field.options[0];
    var funcArg1 = field.options[1];
    var funcArg2 = field.options[2];

    var msg = eval(funcName + "(document.forms.main,'" + field.label + "','" + value + "','" + funcArg1 + "','" + funcArg2 + "')");
    if (msg != null) {
        setConstraintsError(msg);
		this.alert(getConstraintsError());
		form[field.name].focus();
        return false;
    }
	return true;
}

function Validator_validateField(field, form) {
    var isRequired = field.required && this.checkRequired;

	if (field.type == "string") {
        var value = wtrim(form[field.name].value);
		if (!checkText(CST_ANY, isRequired, value, field.label, field.minLength, field.maxLength, -1, -1)) {
            this.alert(getConstraintsError());
            form[field.name].focus();
            return false;
        }
		if (field.format != null && field.format.length > 0 && !this.validateFormat(field, form, value)) {
			return false;
		}
        if (field.options != null && field.options.length > 0 && !this.evalFunction(field, form, value)) {
            return false;
        }
	} else if (field.type == "ui1" || field.type == "ui2" || field.type == "ui4" || field.type == "ui8" ||
               field.type == "i1"  || field.type == "i2"  || field.type == "i4" || field.type == "i8") {
        var value = wtrim(form[field.name].value);
        var limits = this.fixLimits(field.type, field.minValue, field.maxValue);
        var minValue = limits[0];
        var maxValue = limits[1];
        var type = (minValue != -1 && minValue >= 0) ? CST_NUMERIC_POS : CST_NUMERIC;
		if (!checkText(type, isRequired, value, field.label, field.minLength, field.maxLength, minValue, maxValue)) {
            this.alert(getConstraintsError());
            form[field.name].focus();
            return false;
        }
        if (value.length > 0) {
			if (field.format != null && field.format.length > 0 && !this.validateFormat(field, form, value)) {
				return false;
			}
			if (field.options != null && field.options.length > 0 && !this.evalFunction(field, form, value)) {
				return false;
			}
        }
	} else if (field.type == "decimal") {
        var value = wtrim(form[field.name].value);
        var type = (field.minValue != -1 && field.minValue >= 0) ? CST_FLOAT_POS : CST_FLOAT;
		if (!checkText(type, isRequired, value, field.label, field.minLength, field.maxLength, field.minValue, field.maxValue)) {
            this.alert(getConstraintsError());
            form[field.name].focus();
            return false;
        }
        if (value.length > 0) {
			if (field.format != null && field.format.length > 0 && !this.validateFormat(field, form, value)) {
				return false;
			}
			if (field.options != null && field.options.length > 0 && !this.evalFunction(field, form, value)) {
				return false;
			}
        }
	} else if (field.type == "number") {
        var value = wtrim(form[field.name].value);
        var type = (field.minValue != -1 && field.minValue >= 0) ? CST_NUMERIC : CST_NUMERIC_POS;
		if (!checkText(type, isRequired, value, field.label, field.minLength, field.maxLength, field.minValue, field.maxValue)) {
            this.alert(getConstraintsError());
            form[field.name].focus();
            return false;
        }
        if (value.length > 0) {
			if (field.format != null && field.format.length > 0 && !this.validateFormat(field, form, value)) {
				return false;
			}
			if (field.options != null && field.options.length > 0 && !this.evalFunction(field, form, value)) {
				return false;
			}
        }
	} else if (field.type == "any") {
        var value = wtrim(form[field.name].value);
		var type;
        var type = (field.minValue != -1 && field.minValue >= 0) ? CST_ANY : CST_ANY;
		if (!checkText(type, isRequired, value, field.label, field.minLength, field.maxLength, field.minValue, field.maxValue)) {
            this.alert(getConstraintsError());
            form[field.name].focus();
            return false;
        }
        if (value.length > 0) {
			if (field.format != null && field.format.length > 0 && !this.validateFormat(field, form, value)) {
				return false;
			}
			if (field.options != null && field.options.length > 0 && !this.evalFunction(field, form, value)) {
				return false;
			}
        }
	} else if (field.type == "email") {
        var value = wtrim(form[field.name].value);
		var type;
        var type = (field.minValue != -1 && field.minValue >= 0) ? CST_EMAIL : CST_EMAIL;
		if (!checkText(type, isRequired, value, field.label, field.minLength, field.maxLength, field.minValue, field.maxValue)) {
            this.alert(getConstraintsError());
            form[field.name].focus();
            return false;
        }
        if (value.length > 0) {
			if (field.format != null && field.format.length > 0 && !this.validateFormat(field, form, value)) {
				return false;
			}
			if (field.options != null && field.options.length > 0 && !this.evalFunction(field, form, value)) {
				return false;
			}
        }
	} else if (field.type == "alphanumeric") {
        var value = wtrim(form[field.name].value);
        var type = (field.minValue != -1 && field.minValue >= 0) ? CST_ALNUMEX : CST_ALNUM;
		if (!checkText(type, isRequired, value, field.label, field.minLength, field.maxLength, field.minValue, field.maxValue)) {
            this.alert(getConstraintsError());
            form[field.name].focus();
            return false;
        }
        if (value.length > 0) {
			if (field.format != null && field.format.length > 0 && !this.validateFormat(field, form, value)) {
				return false;
			}
			if (field.options != null && field.options.length > 0 && !this.evalFunction(field, form, value)) {
				return false;
			}
        }
    } else if (field.type == "fixed.14.4") {
        var value = wtrim(form[field.name].value);
        var type = (field.minValue != -1 && field.minValue >= 0) ? CST_FIXED144_POS : CST_FIXED144;
		if (!checkText(type, isRequired, value, field.label, field.minLength, field.maxLength, field.minValue, field.maxValue)) {
            this.alert(getConstraintsError());
            form[field.name].focus();
            return false;
        }
        if (value.length > 0) {
			if (field.format != null && field.format.length > 0 && !this.validateFormat(field, form, value)) {
				return false;
			}
			if (field.options != null && field.options.length > 0 && !this.evalFunction(field, form, value)) {
				return false;
			}
        }
	} else if (field.type == "date") {
		var month = form[field.name + "Month"].value;
		var day = form[field.name + "Day"].value;
		var year = form[field.name + "Year"].value;
        var status = checkDate(isRequired, true, day, month, year, field.label);
        if (status != 0) {
			this.alert(getConstraintsError());
			switch(status) {
				case 4:
					form[field.name + "Day"].focus();
                    break;
				case 3:
					form[field.name + "Month"].focus();
                    break;
                default:
					form[field.name + "Year"].focus();
                    break;
			}
			return false;
        }
	} else if (field.type == "enumeration") {
        if (isRequired && !checkOptionList(form[field.name], field.label, field.minValue, field.maxValue)) {
            this.alert(getConstraintsError());
            form[field.name].focus();
            return false;
        }
    } else if (field.type == "group") {
        var g = getItemGroup(parseInt(field.options));
        var count = g.items.length;
        if (isRequired && count < field.minLength) {
            if (count == 0) {
				setConstraintsError("No '" + field.label + "' items were specified.");
            } else {
				setConstraintsError("Not enough '" + field.label + "' items were specified.");
            }
			this.alert(getConstraintsError());
			return false;
        }
	} else {
		this.alert("validateField: unknown item field type: " + field.type);
        return false;
	}
    return true;
}
