function getFieldValue(form, fieldName) {
	var fieldsCount = 0;
	for (i = 0; i < form.elements.length; i++) {
		if (form.elements[i].name == fieldName) {
			fieldsCount++;
		}
	}
	
	var check;
	if (fieldsCount > 1) {
		// radio, multicheckbox
		var values = new Array();
		var j = 0;
		var elements = new Array();
		var k = 0;

		for (i = 0; i < form.elements.length; i++) {
			if (form.elements[i].name == fieldName) {
				elements[j++] = form.elements[i];

				if (form.elements[i].checked) {
					if (form.elements[i].type == 'radio') {
						// radio
						return form.elements[i].value;
					}

					// multicheckbox
					values[k++] = form.elements[i].value;
				}
			}
		}
		
		if ((values.length == 0) && (j > 0) && (elements[0].type == 'radio')) {
			return "";
		}
		
		return values;
	} else {
		var field = form[fieldName];
		
		if (field.type == "checkbox") {
			// checkbox
			return field.checked.toString();
		} else if (field.type == "select-multiple") {
			// multiselect
			var values = new Array();
			var j = 0;
			for (i = 0; i < field.options.length; i++) {
				if (field.options[i].selected) {
					values[j++] = field.options[i].value;
				}
			}
		
			return values;
		} else {
			// standard
			return field.value;
		}
	}
}

function formValidatorsMessageFormat (message, messageArgsArr) {
	var formatedMessage = message;

	for (i = 0; i < messageArgsArr.length; i++) {
		formatedMessage = formatedMessage.replace('{' + i + '}', messageArgsArr[i]);
	}
	return formatedMessage;
}

function formValidatorsValidateInteger(fieldValue, validatorParameters, messageKeys, messageKey) {
	var re = new RegExp('^(-?)(\\d*)$');
	if (!re.test(fieldValue)) {
		return formValidatorsMessageFormat(messageKeys['IntegerValidator'], []);
	}

	var minValue = validatorParameters['minValue'];
	var maxValue = validatorParameters['maxValue'];
	var value = parseInt(fieldValue, 10);
	
	if (isNaN(value)) {
		return formValidatorsMessageFormat(messageKeys['IntegerValidator'], []);
	}
	if (minValue != null && value < minValue) {
		return formValidatorsMessageFormat(messageKeys['IntegerValidator.MIN'], [minValue]);
	}
	if (maxValue != null && value > maxValue) {
		return formValidatorsMessageFormat(messageKeys['IntegerValidator.MAX'], [maxValue]);
	}

	return 'OK';
}

function compareStringsAsNumbers(string1, string2) {
	if (string1.length > string2.length) {
		return 1;
	}

	if (string1.length == string2.length) {
		for (i = 0; i < string1.length; i++) {
			if (string1.charAt(i) > string2.charAt(i)) {
				return 1;
			}
			if (string1.charAt(i) < string2.charAt(i)) {
				return -1;
			}
		}
		
		return 0;
	}

	return -1;
}

function compare(value1, value2) {
	if (value1.charAt(0) == '-') {
		if (value2.charAt(0) == '-') {
			return compare(value2.substring(1, value2.length), value1.substring(1, value2.length));
		} else {
			return false;
		}
	} else if (value2.charAt(0) == '-') {
		return true;
	}

	var dotIndex1 = value1.indexOf('.');
	var dotIndex2 = value2.indexOf('.');
	var integerPart1 = '';
	var fractionPart1 = '';
	var integerPart2 = '';
	var fractionPart2 = '';

	if (dotIndex1 != -1) {
		integerPart1 = value1.substring(0, dotIndex1);
		fractionPart1 = value1.substring(dotIndex1 + 1, value1.length);
	} else {
		integerPart1 = value1;
	}

	if (dotIndex2 != -1) {
		integerPart2 = value2.substring(0, dotIndex2);
		fractionPart2 = value2.substring(dotIndex2 + 1, value2.length);
	} else {
		integerPart2 = value2;
	}
	
	if (compareStringsAsNumbers(integerPart1, integerPart2) == 1) {
		return true;
	}
	if ((compareStringsAsNumbers(integerPart1, integerPart2) == 0) && (compareStringsAsNumbers(fractionPart1, fractionPart2) == 1)) {
		return true;
	}

	return false;
}

function trimZeros(number) {
	var leadingZerosNumber = 0;
	var begin = 0;
	if (number.charAt(0) == '-') {
		begin = 1;
	}

	for (i = begin; i < number.length; i++) {
		if (number.charAt(i) == '0') {
			leadingZerosNumber++;
		} else {
			break;
		}
	}

	var trailingZerosNumber = 0;
	if (number.indexOf('.') != -1) {
		for (i = number.length - 1; i >= 0; i--) {
			if (number.charAt(i) == '0') {
				trailingZerosNumber++;
			} else {
				break;
			}
		}
	}
	
	number = number.substring(begin + leadingZerosNumber, number.length);
	number = number.substring(0, number.length - trailingZerosNumber);
	if (begin == 1) {
		number = '-' + number;
	}
	
	return number;
}

function formValidatorsValidateDecimal(fieldValue, validatorParameters, messageKeys, messageKey) {
	var re = new RegExp('^(-?)(\\d*)(\\.?)(\\d*)$');
	if (!re.test(fieldValue)) {
		return formValidatorsMessageFormat(messageKeys['DecimalValidator'], [validatorParameters['scale'], validatorParameters['precision']]);
	}

	fieldValue = trimZeros(fieldValue);
	
	var dotIndex = fieldValue.indexOf('.');
	var scale = validatorParameters['scale'];
	var precision = validatorParameters['precision'];
	
	if (dotIndex != -1) {
		if (((fieldValue.substring(0, dotIndex).length) > scale) || ((fieldValue.substring(dotIndex + 1, fieldValue.length).length) > precision)) {
			return formValidatorsMessageFormat(messageKeys['DecimalValidator'], [scale, precision]);
		}
	} else {
		if ((fieldValue.length) > scale) {
			return formValidatorsMessageFormat(messageKeys['DecimalValidator'], [scale, precision]);
		}
	}

	var minValue = validatorParameters['minValue'];
	var maxValue = validatorParameters['maxValue'];
	
	if ((maxValue != null) && compare(fieldValue, trimZeros(maxValue))) {
		return formValidatorsMessageFormat(messageKeys['DecimalValidator.MAX'], [scale, precision, maxValue]);
	}
	if ((minValue != null) && compare(trimZeros(minValue), fieldValue)) {
		return formValidatorsMessageFormat(messageKeys['DecimalValidator.MIN'], [scale, precision, minValue]);
	}
	
	return 'OK';
}

function formValidatorsValidateStringPattern(fieldValue, validatorParameters, messageKeys, messageKey) {
	var pattern = validatorParameters['pattern'];
	var re = new RegExp(pattern);		
			
	if (!re.test(fieldValue)) {
		return formValidatorsMessageFormat(messageKeys[messageKey], [pattern]);
	} else {
		return 'OK';
	}
}

function formValidatorsValidateEMail(fieldValue, validatorParameters, messageKeys, messageKey) {
	var pattern = '[\\w\\-\\_\\.]+(\\.[\\w\\-\\_\\.]+)*@[\\w\\-\\_]+(\\.[\\w\\-\\_]+)*(\\.[\\w\\-\\_]{2,4})';
	if (validatorParameters['pattern'] != null) {
		pattern = validatorParameters['pattern'];
	}
	var re;
	var separator = validatorParameters['separator'];
			
	if (separator == undefined) {
		re = new RegExp('^' + pattern + '$');
	} else {
		re = new RegExp('^' + pattern + "([\\s]*" + separator + "[\\s]*" + pattern + ")*$");
	}	
	
	if (!re.test(fieldValue)) {
		return formValidatorsMessageFormat(messageKeys[messageKey], []);
	} else {
		return 'OK';
	}
}

function formValidatorsValidateTwoFieldIdentity(form, validatorParameters, messageKeys, messageKey) {
	var field1Name = validatorParameters['field1Name'];
	var field2Name = validatorParameters['field2Name'];
	if(eval('form.' + field1Name) == null || eval('form.' + field2Name) == null) {
		return 'OK'; // field(s) not visible
	}
	var field1Value = eval('form.' + field1Name + '.value');
	var field2Value = eval('form.' + field2Name + '.value');
	
	if(field1Value != field2Value) {
		return formValidatorsMessageFormat(messageKeys[messageKey], []);
	} else {
		return 'OK';
	}
}

function formValidatorsValidateHtmlTags(fieldValue, validatorParameters, messageKeys, messageKey) {
	if ((fieldValue.indexOf("<")!=-1) || (fieldValue.indexOf(">")!=-1)) {
		return formValidatorsMessageFormat(messageKeys[messageKey], []);	
	}
	
	return "OK";
}

function formValidatorsValidatePassword(fieldValue, validatorParameters, messageKeys, messageKey) {
	var minCount = validatorParameters['minCount'];
	var minNumberCount = validatorParameters['minNumberCount'];
	var minBigLetterCount = validatorParameters['minBigLetterCount'];
	var minSmallLetterCount = validatorParameters['minSmallLetterCount'];

	var count = 0;
	var numberCount = 0;
	var bigLetterCount = 0;
	var smallLetterCount = 0;

	for (i = 0; i < fieldValue.length; i++) {
		count++;
		var c = fieldValue.charAt(i);
		
		if(c>='a' && c<='z') {
			smallLetterCount++;
		} else if(c>='A' && c<='Z') {
			bigLetterCount++;
		} else if(c>='0' && c<='9') {
			numberCount++;
		}
	}
	
    if (count >= minCount && numberCount >= minNumberCount && bigLetterCount >= minBigLetterCount && smallLetterCount >= minSmallLetterCount) {
	    return "OK";
	} else {
		return formValidatorsMessageFormat(messageKeys[messageKey], [minCount, minNumberCount, minBigLetterCount, minSmallLetterCount]);
	}
}

function formValidatorsValidateNip(fieldValue, validatorParameters, messageKeys, messageKey) {
	var WEIGHTS = [6, 5, 7, 2, 3, 4, 5, 6, 7];
	var nip = fieldValue.replace(/-/g, "");
        
	if (nip.length != 10) {
		return formValidatorsMessageFormat(messageKeys[messageKey], []);
	}
        
	var sum = 0;
	for (i = 0; i < 9; i++) {
		var c = nip.charAt(i);
		if (c < '0' || c > '9') {
			return formValidatorsMessageFormat(messageKeys[messageKey], []);
		}
		sum += (c - '0') * WEIGHTS[i];
	}
	sum = (sum % 11) % 10;
	if (sum != nip.charAt(9) - '0') {
		return formValidatorsMessageFormat(messageKeys[messageKey], []);
	}
	
	return "OK";
}

function formValidatorsValidatePesel(fieldValue, validatorParameters, messageKeys, messageKey) {
	var WEIGHTS = [1, 3, 7, 9, 1, 3, 7, 9, 1, 3];
	
	if (fieldValue.length != 11) {
		return formValidatorsMessageFormat(messageKeys[messageKey], []);
	}
        
	var sum = 0;
	for(i = 0; i < 10; i++) {
		var c = fieldValue.charAt(i);
		if (c < '0' || c > '9') {
			return formValidatorsMessageFormat(messageKeys[messageKey], []);
		}
		
		sum += (c - '0') * WEIGHTS[i];
	}
        
	sum = (10 - (sum % 10)) % 10;
	if (sum != fieldValue.charAt(10) - '0') {
		return formValidatorsMessageFormat(messageKeys[messageKey], []);
	}
	
	var year = parseInt(fieldValue.substring(0, 2), 10);
	var month = parseInt(fieldValue.substring(2, 4), 10);
	var day = parseInt(fieldValue.substring(4, 6), 10);
	
	if (month >= 0 && month < 20) {
		month -= 0;
		year += 1900;
	} else if (month >= 20 && month < 40) {
		month -= 20;
		year += 2000;
	} else if (month >= 40 && month < 60) {
		month -= 40;
		year += 2100;
	} else if (month >= 60 && month < 80) {
		month -= 60;
		year += 2200;
	} else if (month >= 80 && month < 100) {
		month -= 80;
		year += 1800;
	} else {
		return formValidatorsMessageFormat(messageKeys[messageKey], []);
	}
	
	var date = new Date(year, month -1, day);
	if ((date.getFullYear() != year) || (date.getMonth() != (month - 1)) || (date.getDate() != day)) {
		return formValidatorsMessageFormat(messageKeys[messageKey], []);
	}
	
	return "OK";        
}

function formValidatorsValidateFieldChoice(form, validatorParameters, messageKeys, messageKey) {
	var minValue = validatorParameters['minValue'];
	var maxValue = validatorParameters['maxValue'];
	var fields = new Array();
	var fieldsNumber = 0;

	for (parameterName in validatorParameters) {
		if (parameterName.search("field") == 0) {
			fields[fieldsNumber++] = validatorParameters[parameterName];
		}
	}
	
	var setFieldsCount = 0;

	for (i = 0; i < fieldsNumber; i++) {
		var field = form[fields[i]];
		if ((field.value != null) && (field.value != '')) {
			setFieldsCount++;
		}
	}
	
   	if ((minValue != 0) && (setFieldsCount < minValue)) {
   		return formValidatorsMessageFormat(messageKeys['FieldChoiceValidator.MIN'], [minValue, fields.join(', ')]);
   	} 
   	if ((maxValue != 0) && (setFieldsCount > maxValue)) {
		return formValidatorsMessageFormat(messageKeys['FieldChoiceValidator.MAX'], [maxValue, fields.join(', ')]);
   	}
	
	return "OK";
}

function getDate(dateString, format) {
	if (format == "yyyy-MM-dd") {
		if (!new RegExp("^\\d\\d\\d\\d-\\d\\d-\\d\\d$").test(dateString)) {
			return false;
		}
	
		var year = parseInt(dateString.substring(0, 4), 10);
		var month = parseInt(dateString.substring(5, 7), 10) - 1;
		var day = parseInt(dateString.substring(8, 10), 10);
		
		var date = new Date(year, month, day);
		if ((date.getFullYear() != year) || (date.getMonth() != month) || (date.getDate() != day)) {
			return false;
		} else {
			return date;
		}
	} else if (format == "yyyy-MM-dd HH:mm") {
		if (!new RegExp("^\\d\\d\\d\\d-\\d\\d-\\d\\d \\d\\d:\\d\\d$").test(dateString)) {
			return false;
		}

		var year = parseInt(dateString.substring(0, 4), 10);
		var month = parseInt(dateString.substring(5, 7), 10) - 1;
		var day = parseInt(dateString.substring(8, 10), 10);
		var hour = parseInt(dateString.substring(11, 13), 10);
		var minute = parseInt(dateString.substring(14, 16), 10);
		
		var date = new Date(year, month, day, hour, minute);
		if ((date.getFullYear() != year) || (date.getMonth() != month) || (date.getDate() != day) || (date.getHours() != hour) || (date.getMinutes() != minute)) {
			return false;
		} else {
			return date;
		}
	} 
	
	// unhandled format
	return true;
}

function formValidatorsValidateDate(fieldValue, validatorParameters, messageKeys, messageKey) {
	var date = getDate(fieldValue, validatorParameters['format']);
	if (!date) {
		return formValidatorsMessageFormat(messageKeys[messageKey], []);
	} else {
		return "OK";
	}
}

function formValidatorsValidateDateDifference(form, validatorParameters, messageKeys, messageKey) {
	var date1 = form[validatorParameters['date1']].value;
	var date2 = form[validatorParameters['date2']].value;
	
	if ((date1 != null) && (date1 != '')) {
		var result = formValidatorsValidateDate(date1, validatorParameters, messageKeys, 'DateValidator');
		if (result != "OK") {
			return result;
		}
	} 
	
	if ((date2 != null) && (date2 != '')) {
		var result = formValidatorsValidateDate(date2, validatorParameters, messageKeys, 'DateValidator');
		if (result != "OK") {
			return result;
		}
	}
	
	if ((date1 == null) || (date2 == null) || (date1 == '') || (date2 == '')) {
		return "OK";
	}
	
	var format = validatorParameters['format'];
	var date1Value = getDate(date1, format);
	var date2Value = getDate(date2, format);
	
	if ((date1Value == true) || (date2Value == true)) {
		// unhandled format
		return "OK";
	} 
	
	var diff = date2Value.getTime() - date1Value.getTime();

	if ((validatorParameters['min'] != null) && (diff < validatorParameters['min'])) {
		return formValidatorsMessageFormat(messageKeys['DateDifferenceValidator.MIN'], []);
	}
	if ((validatorParameters['max'] != null) && (diff > validatorParameters['max'])) {
		return formValidatorsMessageFormat(messageKeys['DateDifferenceValidator.MAX'], []);
	}
	
	return "OK";
}

function formValidatorsValidateTime(fieldValue, validatorParameters, messageKeys, messageKey) {
	var format = validatorParameters['format'];
	
	if (format == "HH:mm") {
		if (!new RegExp("^\\d\\d:\\d\\d$").test(fieldValue)) {
			return formValidatorsMessageFormat(messageKeys[messageKey], []);
		}
	
		var hour = parseInt(fieldValue.substring(0, 2), 10);
		var minute = parseInt(fieldValue.substring(3, 5), 10);

		if ((hour < 0) || (hour > 23) || (minute < 0) || (minute > 59)) {
			return formValidatorsMessageFormat(messageKeys[messageKey], []);
		}
	} 		
	
	return "OK";
}

function formValidatorsValidateFieldNotEmptyIf(form, validatorParameters, messageKeys, messageKey) {
	var field = form[validatorParameters['fieldIf']];
	var fieldIf = field.value;
	var fieldNotEmpty = form[validatorParameters['fieldNotEmpty']].value;
	var fieldIfValue = validatorParameters['fieldIfValue'];
	if (validatorParameters['reverse'] == 'true') {
		reverse = true;
	} else {
		reverse = false;
	}
	
	var fieldsCount = 0;
	for (i = 0; i < form.elements.length; i++) {
		if (form.elements[i].name == validatorParameters['fieldIf']) {
			fieldsCount++;
		}
	}
	
	var check;
	if (fieldsCount > 1) {
		// radio, multicheckbox
		check = false;
		otherValueChecked = false;
		for (i = 0; i < form.elements.length; i++) {
			if (form.elements[i].name == validatorParameters['fieldIf'] && form.elements[i].checked) {
				if (form.elements[i].value == fieldIfValue) {
					check = true;
				} else {
					otherValueChecked = true;
				}
			}
		}
		
		check = check && !otherValueChecked;
	} else {
		if (field.type == "checkbox") {
			// checkbox
			check = (fieldIfValue == "true") && field.checked;
		} else if (field.type == "select-multiple") {
			// multiselect
			check = false;
			otherValueChecked = false;
			for (i = 0; i < field.options.length; i++) {
				if (field.options[i].selected) {
					if (field.options[i].value == fieldIfValue) {
						check = true;
					} else {
						otherValueChecked = true;
					}
				}
			}
		
			check = check && !otherValueChecked;
		} else {
			check = (field.value == fieldIfValue);
		}
	}
	
	if ((check == !reverse) && ((fieldNotEmpty == null) || (fieldNotEmpty == ''))) {
		return formValidatorsMessageFormat(messageKeys[messageKey], []);
	}
	
	return "OK";
}

