/*
	@elem: Field to validate, required
	@message: Message to display upon failure, required
	@type: Method of validation to use, defaults to 'text'
	@match: What the field should match during certain types of validation, defaults to null
	@required: Whether a value is required or not, defaults to true
	@alert_type: inline or popup, defaults to false and uses ActivaValidate alert handling
	@message_box: Element to display message in for inline alerts, defaults to false
*/
function ActivaRule(elem, message, type, match, required, alert_type, message_box)
{
	this.elem = elem;
	this.message = message;
	this.type = type;
	this.match = match;
	this.required = required;
	this.alert_type = alert_type;
	this.message_box = message_box;
	
	this.validate = function() {
		this.elem = domcheck(this.elem);
		
		// Begin by trimming the value
		this.elem.value = trim(this.elem.value);
		
		if ( !this.required ) {
			if ( !this.elem.value ) {
				return true;
			}
		}

		switch ( type ) {
			// Field must have any kind of value
			case "text":
				if ( !this.elem.value ) {
					return false;
				}
				break;
			// Field must be checked
			case "checkbox":
				if ( !this.elem.checked ) {
					return false;
				}
				break;
			// Field must match email regex
			case "email":
				var reg = /\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,6}/;
				
				if ( !reg.test(this.elem.value) ) {
					return false;
				}
				break;
			// Field must match phone regex
			case "phone":
				this.elem.value = this.trim(this.elem.value);
				this.elem.value = this.trimChar(this.elem.value, /\s/);
				this.elem.value = this.trimChar(this.elem.value, /-/);
				this.elem.value = this.trimChar(this.elem.value, /\(/);
				this.elem.value = this.trimChar(this.elem.value, /\)/);

				var reg = /^([\d]{10})$/;

				if ( !reg.test(this.elem.value) ) {
					return false;
				}
				break;
			// Field must be checked
			case "checkbox":
				if ( !this.elem.checked ) {
					return false;
				}
				break;
			// Field must contain an equal or lesser amount of characters
			case "shorter":
				if ( parseInt(this.elem.value.length) > parseInt(this.match) ) {
					return false;
				}
				break;
			// Field must contain an equal or greater amount of characters
			case "longer":
				if ( parseInt(this.elem.value.length) < parseInt(this.match) ) {
					return false;
				}
				break;
			// Field must contain amount of characters within valid range
			case "between":
				var ranges = this.match.split('-');
				var min = parseFloat(ranges[0]);
				var max = parseFloat(ranges[1]);
				
				if ( isNaN(parseFloat(this.elem.value.length)) || parseFloat(this.elem.value.length) > max || parseFloat(this.elem.value.length) < min ) {
					return false;
				}
				break;
			// Field must match amount of characters
			case "length":
				if ( parseInt(this.elem.value.length) != parseInt(this.match) ) {
					return false;
				}
				break;
			// Field must be less than or equal to requirement
			case "less":
				var max = parseFloat(this.match);
				
				if ( isNaN(parseFloat(this.elem.value)) || parseFloat(this.elem.value) > max ) {
					return false;
				}
				break;
			// Field must be greater than or equal to requirement
			case "greater":
				var min = parseFloat(this.match);
				
				if ( isNaN(parseFloat(this.elem.value)) || parseFloat(this.elem.value) < min ) {
					return false;
				}
				break;
			// Field must contain value within valid range
			case "range":
				var ranges = this.match.split('-');
				var min = parseFloat(ranges[0]);
				var max = parseFloat(ranges[1]);
				
				if ( isNaN(parseFloat(this.elem.value)) || parseFloat(this.elem.value) > max || parseFloat(this.elem.value) < min ) {
					return false;
				}
				break;
			// Field must match passed regex
			case "match":
				if(this.elem.type == 'radio'){
					var rgroup = document.getElementsByName(this.elem.name);
					for(var i = 0; i < rgroup.length; i++){
						if(rgroup[i].checked && this.match == rgroup[i].value){ return true; }
					}
					return false;
				} else {
					if ( !this.match.test(this.elem.value) ) {
						return false;
					}
				}
				break;
		}
		
		return true;
	}
	
	// Must pass default ActivaValidate message box, in case rule does not have its own message box
	this.alert = function(message_box) {
		switch ( this.alert_type ) {
			case "inline":
				if ( this.message_box ) {
					this.message_box.innerHTML = this.message;
					this.message_box.style.display = '';
				} else {
					message_box.innerHTML = this.message;
					message_box.style.display = '';
				}
				break;
			case "popup":
			case "alert":
				alert(this.message);
				break;
		}
	}
	
	this.ltrim = function(string)
	{
		return string.replace(/^\s*/, '');
	}
	
	this.rtrim = function(string)
	{
		return string.replace(/\s*$/, '');
	}
	
	this.trim = function(string)
	{
		if ( typeof(string) == 'undefined' ) {
			return false;
		}
		return this.rtrim(this.ltrim(string));
	}
	
	this.trimChar = function(str, reg) {
		var reg = reg;
		while (reg.test(str)) {
			str = str.replace(reg, '');
		}
		
		return str;
	}
}

/*
	@form: Form that will be validated
*/
function ActivaForm(form)
{
	this.form = form;
	this.rules = new Array();
	this.extra = new Array();
	
	// Manually add onload event so it can grab reference to DOM object, and not a string
	registerEvent(window, 'load', createDelegate(this, 'load'));

	this.load = function() {
		this.form = domcheck(this.form);
	}
	
	this.addRule = function(elem, message, type, match, required, alert_type, message_box) {
		if ( typeof(type) == 'undefined' ) {
			type = 'text';
		}
			
		if ( typeof(match) == 'undefined' ) {
			match = '';
		}
		
		if ( typeof(required) == 'undefined' ) {
			required = true;
		}
		
		if ( typeof(alert_type) == 'undefined' ) {
			alert_type = false;
		}
		
		if ( typeof(message_box) == 'undefined' ) {
			message_box = false;
		}
		
		var rule = new ActivaRule(elem, message, type, match, required, alert_type, message_box);
		this.rules.push(rule);
	}
	
	this.addExtra = function(func) {
		this.extra.push(func);
	}
}

/*
	@form: ActivaForm, required
	@alert_type: Style of alerts, inline or popup, defaults to popup
	@message_box: Element to display message in for inline alerts, defaults to null
*/
function ActivaValidate(form, alert_type, message_box)
{
	this.form = form;
	
	if ( typeof(alert_type) == 'undefined' ) {
		alert_type = 'popup';
	}
		
	if ( typeof(message_box) == 'undefined' ) {
		message_box = false;
	} else {
		this.message_box = domcheck(message_box);
	}
	
	this.alert_type = alert_type;
	
	// Manually add onsubmit event so that form HTML does not require it
	registerEvent(this.form.form, 'submit', createDelegate(this, 'validate'));
	
	this.validate = function(e) {
		// Always reset message box to nothing
		
		if ( this.message_box ) {
			this.message_box.style.display = 'none';
			this.message_box.innerHTML = '';
		}
		
		// Validate rules
		for ( var i=0; i<this.form.rules.length; i++ ) {
			var rule = this.form.rules[i];
			
			if ( !rule.validate() ) {
				if ( rule.alert_type ) {
					// ActivaRule has override alert handling
					rule.alert(this.message_box);
				} else {
					// ActivaValidate is handling the alert
					switch ( this.alert_type ) {
						case "inline":
							this.message_box.innerHTML = rule.message;
							this.message_box.style.display = '';
							break;
						case "popup":
						case "alert":
							alert(rule.message);
							break;
					}
				}
				if ( typeof(rule.elem) != 'undefined' ) { 
					rule.elem.focus();
				}
				
				// Prevents form from posting (required when you manually register onsubmit event)
				if ( e.preventDefault ) {
					e.preventDefault();
				}
				return false;
			}
		}
		
		// Validate extra functions
		for ( var i=0; i<this.form.extra.length; i++ ) {
			var result = this.form.extra[i].call();
			
			if ( !result ) {
				// Prevents form from posting (required when you manually register onsubmit event)
				if ( e.preventDefault ) {
					e.preventDefault();
				}
				return false;
			}
		}
		
		// Form has successfully validated
		return true;
	}
}