// form 2.0
// requires dom 3.3, functions 1.3

var fieldChecker = {
	invalidClass: "invalid",
	
	add: function(obj, ruleSet) {
		// adds fieldChecker functionality to input field.
		// ruleset is associative array of validation rules, default values and error messages
		obj = elm.get(obj);
		if (obj == null) return false;
		
		// mark field as not modified
		obj.fieldChecker_modified = false;
		
		// add relevant rules from specified ruleset.
		obj.fieldChecker_ruleSet = new Array();
		var classNames = cls.get(obj);
		var i;
		var ruleName;
		for (i = 0; i < classNames.length; i++) {
			ruleName = classNames[i];
			if ((typeof ruleSet[ruleName] != "undefined") && (ruleSet[ruleName] != null)) {
				obj.fieldChecker_ruleSet[ruleName] = ruleSet[ruleName];
			}
		}
		
		// try to add label
		if (obj.getAttribute("id") != null) {
			var labels = document.getElementsByTagName("label");
			for (i = 0; i < labels.length; i++) {
				if (labels[i].getAttribute("for") == obj.getAttribute("id")) {
					obj.fieldChecker_label = labels[i];
				}
			}
		}
		
		// on focus insert default value, on blur remove it
		evt.add(obj, "focus", fieldChecker.setDefaultValue);
		evt.add(obj, "blur", fieldChecker.clearDefaultValue);
		
		// check field when user changes content of input field
		evt.add(obj, "keyup", function(e) { fieldChecker.setModified(e); fieldChecker.check(e); });
		
		// check field now
		fieldChecker.check(obj);
		return true;
	},
	
	setDefaultValue: function(obj) {
		if (typeof obj.tagName == "undefined") { // item is not HTML element
			var e = evt.fix(obj);
			obj = evt.getTarget(e);
		}
		// obj is now HTML element, so we can use it
		if (obj.fieldChecker_modified) return true; // object's value has been modified so we should not change it
		if (elm.getValue(obj) == "") {
			for (rule in obj.fieldChecker_ruleSet) {
				if (typeof obj.fieldChecker_ruleSet[rule].def != "undefined") {
					elm.setValue(obj, obj.fieldChecker_ruleSet[rule].def);
					return true;
				}
			}
		}
		return true;
	},
	
	clearDefaultValue: function(obj) {
		if (typeof obj.tagName == "undefined") { // item is not HTML element
			var e = evt.fix(obj);
			obj = evt.getTarget(e);
		}
		// obj is now HTML element, so we can use it
		if (obj.fieldChecker_modified) return true; // object's value has been modified so we should not change it
		for (rule in obj.fieldChecker_ruleSet) {
			if (typeof obj.fieldChecker_ruleSet[rule].def != "undefined") {
				if (elm.getValue(obj) == obj.fieldChecker_ruleSet[rule].def) {
					elm.setValue(obj, "");
					return true;
				}
			}
		}
		return true;
	},
	
	setModified: function(obj) {
		if (typeof obj.tagName == "undefined") { // item is not HTML element
			var e = evt.fix(obj);
			obj = evt.getTarget(e);
		}
		// obj is now HTML element, so we can use it
		obj.fieldChecker_modified = true;
		return true;
	},
	
	check: function(obj) {
		// this function checks if field value is valid.
		// obj can be event targeted to field, or field itself.
		var passed = false;
		var ruleName = "";
		var target = obj;
		if (typeof obj.tagName == "undefined") { // item is not HTML element
			obj = evt.getTrigger(obj);
		}
		// obj is now HTML element, so we can check it
		for (rule in obj.fieldChecker_ruleSet) {
			// check by fn and exit if invalid
			if (typeof obj.fieldChecker_ruleSet[rule].fn != "undefined") {
				if (!obj.fieldChecker_ruleSet[rule].fn(elm.getValue(obj))) {
					fieldChecker.setInvalid(obj, rule);
					return false;
				}
			}
			// check by reg and exit if invalid
			if (typeof obj.fieldChecker_ruleSet[rule].reg != "undefined") {
				if (elm.getValue(obj).search(obj.fieldChecker_ruleSet[rule].reg) < 0) {
					fieldChecker.setInvalid(obj, rule);
					return false;
				}
			}
		}
		// passed tests, set it valid
		fieldChecker.setValid(obj);
		return true;
	},
	
	setValid: function(obj) {
		obj.fieldChecker_error = null;
		cls.remove(obj, fieldChecker.invalidClass);
		return true;
	},
	
	setInvalid: function(obj, rule) {
		if (!obj.disabled && (typeof rule != "undefined") && (rule != null)) {
			obj.fieldChecker_error = obj.fieldChecker_ruleSet[rule].err;
		}
		cls.add(obj, fieldChecker.invalidClass);
		return true;
	},
	
	isValid: function(obj) {
		return cls.has(obj, fieldChecker.invalidClass);
	},
	
	setLabel: function(obj, label) {
		obj.fieldChecker_label = label;
		return true;
	},
	
	getLabel: function(obj, resultType) {
		// TODO - modify result by resultType
		// defined result types: plain, html
		var result = "";
		if (obj.fieldChecker_label) {
			result = result + obj.fieldChecker_label.innerHTML;
			result = result.replace(/[:]?\s*$/g,"");
			result = result.trim();
			result = result.removeInlineHtml();
		}
		return result;
	},
	
	getMessage: function(obj) {
		// returns error message of the object if any
		if ((typeof obj.fieldChecker_error != "undefined") && (obj.fieldChecker_error != null)) {
			var result = obj.fieldChecker_error;
			var label = fieldChecker.getLabel(obj, "plain");
			if (label == "") label = obj.getAttribute("title");
			if ((label == "") || (label == null)) label = obj.name;
			result = result.replace(/\{label\}/g, '"' + label + '"');
			result = result.replace(/\{value\}/g, '"' + elm.getValue(obj) + '"');
			return result;
		}
		return "";
	}
}


var formChecker = {
	invalidClass: "invalid",
	invalidMsgTitle: "Warning, some fields are not filled properly:",
	
	add: function(obj, ruleSet) {
		// adds formChecker functionality to form.
		// ruleset is associative array of validation rules, default values and error messages
		obj = elm.get(obj);
		if (obj == null) return false;
		
		// init fieldChecker for each input in form
		obj.formChecker_fields = new Array();
		
		var inputs = obj.getElementsByTagName("input");
		var inputType;
		for (i = 0; i < inputs.length; i++) {
			inputType = inputs[i].getAttribute("type");
			if ((inputType == "text") || (inputType == "password") || (inputType == "file")) {
				fieldChecker.add(inputs[i], form_ruleSet);
				obj.formChecker_fields[obj.formChecker_fields.length] = inputs[i];
			}
		}
		
		var textareas = obj.getElementsByTagName("textarea");
		for (i = 0; i < textareas.length; i++) {
			fieldChecker.add(textareas[i], form_ruleSet);
			obj.formChecker_fields[obj.formChecker_fields.length] = textareas[i];
		}
		evt.add(obj, "submit", formChecker.submit);
		return true;
	},
	
	check: function(obj) {
		// this function checks if all fields in form are valid.
		// obj can be an event targeted to a form, or the form itself.
		var i;
		var passed = true;
		var ruleName = "";
		var target = obj;
		if (typeof obj.tagName == "undefined") { // item is not HTML element
			var e = evt.fix(obj);
			obj = evt.getTarget(e);
		}
		// obj is now HTML element, so we can check it
		obj.formChecker_error = "";
		for (i = 0; i < obj.formChecker_fields.length; i++) {
			if (!obj.formChecker_fields[i].disabled && !fieldChecker.check(obj.formChecker_fields[i])) {
				passed = false;
				obj.formChecker_error += fieldChecker.getMessage(obj.formChecker_fields[i]) + "\r\n";
			}
		}
		if (!passed) {
			formChecker.setInvalid(obj);
			return false;
		}
		formChecker.setValid(obj);
		return true;
	},
	
	setValid: function(obj) {
		obj.formChecker_error = null;
		cls.remove(obj, formChecker.invalidClass);
		return true;
	},
	
	setInvalid: function(obj, field) {
		cls.add(obj, formChecker.invalidClass);
		return true;
	},
	
	displayMessage: function(obj) {
		var msg = formChecker.invalidMsgTitle.removeInlineHtml();
		msg += "\r\n" + obj.formChecker_error;
		alert(msg);
	},
	
	submit: function(obj) {
		// obj could be form or event
		var e = null; // submit event
		if (typeof obj.tagName == "undefined") { // item is not HTML element
			// e = evt.fix(obj);
			e = obj;
			obj = evt.getTrigger(e);
		}
		// obj is now HTML form element, so we can check it
		if (!formChecker.check(obj)) {
			// form invalid, display error messages
			formChecker.displayMessage(obj);
			if (e != null) evt.cancel(e);
			return false;
		}
		return true;
	}

}




var form_ruleSet = {}

// basic private definitions
form_ruleSet._df                    = {};
form_ruleSet._df.specChars          = " \!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF\xD7\xF7";
form_ruleSet._df.alphaLowercaseISO  = "\xDF\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF";
form_ruleSet._df.alphaUppercaseISO  = "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD8\xD9\xDA\xDB\xDE";
form_ruleSet._df.alphaLowercaseUTF  = "\u00E1\u00E9\u0115\u00ED\u00F3\u00FA\u016F\u00FD\u017E\u0161\u010D\u0159\u010F\u0165\u0148" + form_ruleSet._df.alphaLowercaseISO;
form_ruleSet._df.alphaUppercaseUTF  = "\u00C1\u00C9\u0114\u00CD\u00D3\u00DA\u016E\u00DD\u0160\u017D\u010c\u0158\u010E\u0164\u0147" + form_ruleSet._df.alphaUppercaseISO;

form_ruleSet.percentage = {
	// number -  exponential form allowed, unlimited decimal digits
	reg: new RegExp("^(([0-9]{1,2})|(100{1}))?$"),
	err: "Field {label} must contain a number from 0 to 100."
};
form_ruleSet.number = {
	// notNegative -  positive numbers and zero, exponential form allowed, unlimited decimal digits
	reg: new RegExp("^([\+\-]?[0-9]{1,}([\.][0-9]{1,})?(e[\+\-]{1}[0-9]{1,2})?)?$"),
	err: "Field {label} must contain number."
};
form_ruleSet.notNegative = {
	// notNegative -  only positive numbers (without zero), exponential form allowed, unlimited decimal digits
	reg: new RegExp("^([\+]?[0-9]{1,}([\.][0-9]{1,})?(e[\+\-]{1}[0-9]{1,})?)?$"),
	err: "Field {label} must contain positive number or 0."
};
form_ruleSet.positive = {
	reg: new RegExp("^(([\+]?[0-9]*[1-9]{1}[0-9]*([\.][0-9]{1,})?(e[\+\-]{1}[0-9]{1,})?)|([\+]?[0-9]{1,}([\.][0-9]*[1-9]{1}[0-9]*){1}(e[\+\-]{1}[0-9]{1,})?))?$"),
	err: "Field {label} must contain number greater than 0."
};
form_ruleSet.email = {
	reg: new RegExp("^([a-zA-Z0-9]+[a-zA-Z0-9\._-]*[a-zA-Z0-9]+@[a-zA-Z0-9]+[a-zA-Z0-9\._-]*[a-zA-Z0-9]+[\.]{1}[a-zA-Z]{2,4})?$"),
	err: "Field {label} must contain a valid e-mail address."
};
form_ruleSet.safeChars = {
	reg: new RegExp("^[0-9a-zA-Z_]{0,}$"),
	err: "Field {label} must contain only safe characters."
};
form_ruleSet.alphaLowercase = {
	reg: new RegExp("^.*$"),
	// reg: new RegExp("^[a-z" + form_ruleSet._df.alphaLowercaseUTF + " ]{1,}$")),
	err: "Field {label} must contain only lowercase alphabet characters."
};
form_ruleSet.alphaUppercase = {
	reg: new RegExp("^.*$"),
	// new RegExp("^[A-Z" + form_ruleSet._df.alphaUppercaseUTF + " ]{1,}$")),
	err: "Field {label} must contain only uppercase alphabet characters."
};
form_ruleSet.alpha = {
	reg: new RegExp("^.*$"),
	// reg: new RegExp("^[a-zA-Z" + form_ruleSet._df.alphaUppercaseUTF + form_ruleSet._df.alphaLowercaseUTF + " ]{1,}$")),
	err: "Field {label} must not contain numbers or special characters."
};
form_ruleSet.alphanumeric = {
	reg: new RegExp("^.*$"),
	// reg: new RegExp("^[a-zA-Z" + form_ruleSet._df.alphaUppercaseUTF + form_ruleSet._df.alphaLowercaseUTF + "0-9 ]{1,}$"))
	err: "Field {label} must contain only alphanumeric characters."
};
form_ruleSet.text = {
	reg: new RegExp("^.*$"),
	// reg: new RegExp("^[a-zA-Z" + form_ruleSet._df.alphaUppercaseUTF + form_ruleSet._df.alphaLowercaseUTF + "0-9" + specChars + "]{1,}$")),
	err: "Field {label} must contain only text."
};
form_ruleSet.dynamicParams = {
	reg: new RegExp("^[ -~" + form_ruleSet._df.alphaUppercaseUTF + form_ruleSet._df.alphaLowercaseUTF + "]{0,}$"),
	err: "Field {label} must not contain any numbers or special characters except \"-\" or \"~\"."
};
form_ruleSet.color = {
	reg: new RegExp("^([#]{1}[0-9a-fA-F]{6})?$"),
	err: "Field {label} must contain hexadecimal RGB color definition (for example #336699)."
};
form_ruleSet.url = {
	reg: new RegExp("^(http(s)?://(([a-zA-Z0-9]+([-_.]?[a-zA-Z0-9])*\.([a-zA-Z]){2,4})|(([0-9]){1,3}\.([0-9]){1,3}\.([0-9]){1,3}\.([0-9]){1,3}))(:[0-9]{2,5})?(/([-!_:~&=$?.|;,%a-zA-Z0-9[\\]]|(%[0-9a-fA-F]{2}))*)*)?$"),
	def:  "http://",
	err: "Field {label} must contain valid URL (for example \"http://www.google.com\")."
};
form_ruleSet.telephone = {
	reg: new RegExp("^[0-9()+-/ ]{0,}$"),
	err: "Field {label} must contain a valid phone number."
};
form_ruleSet.domains = {
	// general check for the list of domains made problems (MS IE)
	// the following regular expression were unsuccessfully tried and then commented out:

	// reg: new RegExp("^(([a-zA-Z0-9]+([-_\.]?[a-zA-Z0-9])*\.[a-zA-Z]{2,4})[,\f\n\r]\n?)*$"),
	// reg: new RegExp("^(([a-zA-Z0-9]+([-_\.]?[a-zA-Z0-9])*[\.]{1}[a-zA-Z]{2,4})([ \f\n\r]*[,]?[ \f\n\r]*)+)*$"),
	// reg: new RegExp("^(([a-zA-Z0-9]+([-_\.]?[a-zA-Z0-9])*[\.]{1}[a-zA-Z]{2,4}(\/{1}[-_~&=\?\.a-zA-Z0-9]*)*)[,]?)*$"),

	// current solution only checks whether characters are from the valid set
	// the reg.expr. also contains various white spaces to enable the comfortable editing
	// ( white space char (\s) did not work)
	reg: new RegExp("^[0-90-9a-zA-Z\-\_\.\~\&\=\?,\r\n\t\f ]{0,}$"),
	err: "Field {label} must contain domain names."
};
// local specific items.
// international, no exponential form - old version without internationalization
form_ruleSet.numeric = {
	reg: new RegExp("^[\+\-]?[0-9 ]{0,}$"),
	err: "Field {label} must contain only numbers."
};
form_ruleSet.floatNumber = {
	// 2 decimal digits
	reg: new RegExp("^[\+\-]?[0-9]*([.][0-9]*)?$"),
	err: "Field {label} must contain only numbers with floating point."
};
form_ruleSet.date = {
	// in format (D)D.(M)M.YYYY
	reg: new RegExp("^([0-9]{1,2}[.][0-9]{1,2}[.][0-9]{4}){0,1}$"),
	err: "Field {label} must contain date in format (D)D.(M)M.YYYY."
};
form_ruleSet.required = {
	fn:
		function(str) {
			return (str.search(/\S/) < 0) ? false : true;
		},
	err: "Field {label} must not be empty."
};
form_ruleSet.multipleEmails = {
	// requires checks.email
	fn:
		function(str) {
			if (str == "") return true;
			var addresses = str.split(','); // Array of Strings
			var fieldOK = true; // Boolean
			var rule = form_ruleSet.email; // RegExp
			var i; // Int
			var actualAddress; // String
			for (i = 0; i < addresses.length; i++) {
				if (addresses[i].trim) actualAddress = addresses[i].trim();
				else actualAddress = addresses[i];
				fieldOK = fieldOK && ((actualAddress.search(rule) < 0) ? false : true);
			}
			return fieldOK;
		},
	err: "Field {label} must contain only valid e-mail addresses separated by commas \",\"."
};




