var CT = (typeof(CT) == 'undefined') ? {} : CT;

CT.FieldsValidator = function(config) {
	this.config = config;
	this.validationItems = [];
	this.alreadyRunBefore = false;
	this.validated = false;

	if (this.config && this.config.custom) {
		for (var field in this.config.custom) {
			this.validationItems.push(field);
		}
	} else {
		var types = ['span', 'div'];
		for (var i = 0, j = 0; i < types.length; i++) {
			containers = document.getElementsByTagName(types[i]);
			if (containers) {
				for (j = 0; j < containers.length; j++) {
					if (containers[j].id && containers[j].id.indexOf('_validator') > 0) {
						this.validationItems.push( 
							containers[j].id.substring(0, containers[j].id.indexOf('_validator')) 
						);
					}
				}
			}
		}
	}
}


CT.FieldsValidator.prototype.toString = function() {
	return 'FieldsValidator';
}


CT.FieldsValidator.prototype.ThrowError = function(message) {
	var error = new Error();
	error.name = this.toString();
	error.message = message;
	throw error;
}


CT.FieldsValidator.prototype.Validate = function() {
	this.validated = true;
	if (this.validationItems) {		
		for (var i = 0; i < this.validationItems.length; i++) {
			this.validated = this.CheckField(this.validationItems[i]) ? this.validated : false;
			if (!this.alreadyRunBefore) {
				this.AttachOnChangeValidator(this.validationItems[i]);
			}
		}
	}
	this.alreadyRunBefore = true;
}


CT.FieldsValidator.prototype.CheckField = function(name) {
	var CleanErrorMessages = function(name, config) {
		if (config) {
			if (config.defaultErrorMessage) {
				if (typeof(config.defaultErrorMessage) == 'string') {
					RemoveErrorMessage(name, config.defaultErrorMessage);
				} else if (config.defaultErrorMessage[name]) {
					RemoveErrorMessage(name, config.defaultErrorMessage[name]);
				}	
			}
			if (config.custom && config.custom[name] && config.custom[name].errorMessage) {
				RemoveErrorMessage(name, config.custom[name].errorMessage);
			}
		}
	}
	
	var DisplayErrorMessage = function(name, message) {
		var container = document.getElementById(name + '_validator');
		if (container) {
			var messageTextNode = document.createTextNode(message);
			container.appendChild(messageTextNode);
		}
	}

	var RemoveErrorMessage = function(name, message) {
		var container = document.getElementById(name + '_validator');
		if (container) {
			if (container.hasChildNodes) {
				for (var i = 0; i < container.childNodes.length; i++) {
					if (container.childNodes[i].nodeType == 3 /* TEXT_NODE */) {
						if (container.childNodes[i].nodeValue == message) {
							container.removeChild(container.childNodes[i]);
						}
					}
				}
			}
		}
	}

	var CheckFieldNonEmpty = function(field) {
		var result = false;
		var value;
		for (var i = 0; i < field.length; i++) {
			if (field[i].type) {
				switch (field[i].type) {
					case 'radio':
					case 'checkbox': 
						result = field[i].checked ? true : false;
						break;

					case 'select-one':
					case 'select-multiple': 
						value = field[i].options[field[i].selectedIndex].value.replace(/\s/gi,'');
						result = value.length ? true : false;
						break;

					case 'text':
					case 'textarea':
					case 'password': 
						value = field[i].value.replace(/\s/gi, '');
						result = value.length ? true : false;
						break;
				}
			}
			if (result) {
				break;
			}
		}
		return result;
	}

	var CheckFieldByPattern = function(field, pattern) {
		var regex = {
			'email'  : /^\s*\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*\s*$/gi,
			'url'    : /^\s*(\w+):\/\/([^\/:]+)(:\d*)?([^# ]*)\s*$/gi,
			'number' : /^\s*(-|\+)?\d+((,|\.)\d+)?\s*$/gi
		};
		return regex[pattern] ? CheckFieldByRegex(field, regex[pattern]) : true;
	}

	var CheckFieldByRegex = function(field, regex) {
		var result = false;
		for (var i = 0; i < field.length; i++) {
			if (field[i].type) {
				switch (field[i].type) {
					case 'text':
					case 'textarea':
					case 'password': 
						result = (field[i].value.match(regex) ? true : false);
						break;
					default: 
						result = true; // no sense to check radio buttons values etc. - true
				}
			}
			if (result) {
				break;
			}
		}
		return result;
	}

	var CheckFieldByFunction = function(field, func) {
		if (typeof(func) == 'function') {
			var result = false;
			for (var i = 0; i < field.length; i++) {
				result = result || func.call(field[i]);
			}
			return result;
		}
		return true;
	}
	
	var field = document.getElementsByName(name);
	CleanErrorMessages(name, this.config);
	if (CheckFieldNonEmpty(field)) {
		if (this.config && this.config.custom && this.config.custom[name])	{
			if (this.config.custom[name].regex || this.config.custom[name].pattern || this.config.custom[name].func) {
				var byPattern, byRegex, byFunction;				
				if (this.config.custom[name].pattern) {
					byPattern = CheckFieldByPattern(field, this.config.custom[name].pattern);
				}
				if (this.config.custom[name].regex) {
					byRegex = CheckFieldByRegex(field, this.config.custom[name].regex);
				}
				if (this.config.custom[name].func) {
					byFunction = CheckFieldByFunction(field, this.config.custom[name].func);
				}
				if (!byPattern && !byRegex && !byFunction) {
					var message = (this.config.custom[name].errorMessage) ? this.config.custom[name].errorMessage : '';
					if (message) DisplayErrorMessage(name, message);
					return false;
				}
			}			
		}
	} else {
		if (this.config && this.config.defaultErrorMessage) {
			if (typeof(this.config.defaultErrorMessage) == 'string') {
				DisplayErrorMessage(name, this.config.defaultErrorMessage);
			}
			else if (this.config.defaultErrorMessage[name]) {
				DisplayErrorMessage(name, this.config.defaultErrorMessage[name]);
			}				
		}
		return false;
	}		
	return true;
}


CT.FieldsValidator.prototype.AttachOnChangeValidator = function(name) {
	var elements = document.getElementsByName(name);
	if (elements) {
		for (var i = 0; i < elements.length; i++) {
			if (elements.item(i)) {
				elements.item(i).validator = this;
				elements.item(i).onchange = function () {
					this.validator.CheckField(this.name);
				};
			}
		}
	}
}