var _CURRENT_FORM;

function initialiseForm(form, fromAnOnBlur) {
	_CURRENT_FORM = form;
	
	if(fromAnOnBlur) {
		limitValidationErrorsTo(fromAnOnBlur);
	} else {
		clearValidationErrorLimit();
	}
	clearValidationErrorLimit();
		
	_HAS_HAD_FORM_ERROR = false;
	clearValidationErrorCache();
}

function hasHadFormError() {
	return _HAS_HAD_FORM_ERROR || !_ERROR_CACHE;
}

/**
 * Returns group with the correct classname
 */
function findIndexOf(group,index){
	var i, group;
	for( i=0 ; i < group.length ; i++ ) {
		if(group[i].className.indexOf(index) > -1){
			return group[i];
		}
	}
}

function clearErrorMessage(holderDiv){
	$$('span.message', holderDiv.parentNode).each(function(el) {
		Element.hide(el);
	});
}

function clearAllErrorMessages(){
	$$('span.message').each(function(el) {
		Element.hide(el);
	});
}

function require(fieldName,cachedError) {
	el = _CURRENT_FORM.elements[fieldName];
	
	// see if the field is an optionset
	if( el == null ) {
		
		var descendants = _CURRENT_FORM.getElementsByTagName('*');
		
		el = $(fieldName);
		
		if( el == null )
			return true;
		
		if( Element.hasClassName( el, 'optionset' ) ) {	
			el.type = 'optionset';	
				
			var options = el.getElementsByTagName('input');
			
			for( var i = 0; i < options.length; i++ ) {
				if( options[i].checked )
					if( el.value != null )
						el.value += ',' + options[i].value;
					else
						el.value = options[i].value;
			}
		}
		
	}

		
	if(el != null){
		// Sets up radio and checkbox validation
		if(el.type == 'checkbox' || el.type == 'radio' ){
			var set = el.checked;
		}else{
			var set = el.value;
		}
		
		
		
		var baseEl;
		
		// Sometimes require events are triggered of 
		// associative elements like labels ;-p
		if(el.type){
			if( el.parentNode.className.indexOf('form') != -1) set = true;
			baseEl = el;
		
		} else {
			if(_CURRENT_FORM.elements[fieldName]) {
			//Some elements are nested and need to be "got"
				var i, hasValue = false;
				if(_CURRENT_FORM.elements[fieldName].length > 1){
					for( i=0 ; i < el.length ; i++ ) {
						if(el[i].checked && el[i].value) hasValue = true;
					}

					if(hasValue) set = true;
					else set = "";
					baseEl = el[0].parentNode.parentNode;

				} else {
					set = "";
					baseEl = el.parentNode;	
				}

			} else {
				set = true;
			}
		}
		
		// This checks to see if the input has a value, and the field is not a readonly.
		if( ( typeof set == 'undefined' || set == "" ) ) {
			//fieldgroup validation
			var fieldLabel = findParentLabel(baseEl);

			// Some fields do-not have labels, in 
			// which case we need a blank one
			if(fieldLabel == null || fieldLabel == ""){
				fieldlabel = "this field";	
			}
			
			var errorMessage = "Please fill out \"$FieldLabel\", it is required."
			if(baseEl.requiredErrorMsg) errorMessage = baseEl.requiredErrorMsg;
			else if(_CURRENT_FORM.requiredErrorMsg) errorMessage = _CURRENT_FORM.requiredErrorMsg;
			
			validationError(baseEl, errorMessage.replace('$FieldLabel', fieldLabel),"required",cachedError);
			return false;
			
		}else{
			if(!hasHadFormError()){
				clearErrorMessage(baseEl.parentNode);
			}
			return true;
		}
	}
	
	return true;
}

/**
 * Returns the label of the blockset which contains the classname left
 */
function findParentLabel(el){
	// If the el's type is HTML then were at the uppermost parent, so return 
	// null. its handled by the validator function anyway :-)
	if(el){
		if(el.className == "undefined"){
			return null;
		}else{
			if(el.className){
				if(el.className.indexOf('field') == 0){
					labels = el.getElementsByTagName('label');
					if(labels){
						left = findIndexOf(labels,'left')
						right = findIndexOf(labels,'right')
						if(left){
							return strip_tags(left.innerHTML);
						}else if(right){
							return strip_tags(right.innerHTML);
						}else{
							return findParentLabel(el.parentNode);
						} 
					}
				}else{
					return findParentLabel(el.parentNode);
				}
			}else{
				return findParentLabel(el.parentNode);
			}
		}
	}
	// backup
	return "this";
}

/**
 * Adds a validation error to an element
 */
function validationError(field,message, messageClass, cacheError){
	if(typeof(field) == 'string') {
		field = $(field);
	}
	
	if(cacheError) {
		_ERROR_CACHE[_ERROR_CACHE.length] = {
			"field": field,
			"message": message,
			"messageClass": messageClass
		}
		return;
	}
	
	// The validation function should only be called if you've just left a field, 
	// or the field is being validated on final submission
	if(_LIMIT_VALIDATION_ERRORS && _LIMIT_VALIDATION_ERRORS != field){
		clearErrorMessage(field.parentNode);
		return;
	}
	
	_HAS_HAD_FORM_ERROR = true;
	
	// See if the tag has a reference to the validationMessage (quicker than the one below)
	var validationMessage = field.validationMessage;
	
	// Cycle through the elements to see if it has a span 
	// ( for a validation or required messages )
	if(!validationMessage) {
		
		//Get the parent holder of the element 
		var FieldHolder = field.parentNode;
		var allSpans = FieldHolder.getElementsByTagName('span');
		validationMessage = findIndexOf(allSpans,'message');
	}
	
	// If we didn't find it, create it
	if(!validationMessage) {
		validationMessage = document.createElement('span');
		FieldHolder.appendChild(validationMessage);
	}
	
	// Keep a reference to it
	field.validationMessage = validationMessage;
	
	// Set the attributes
	validationMessage.className = "message " + messageClass;
	validationMessage.innerHTML = message;
	validationMessage.style.display = "block";
}

/**
 * Set a limitation so that only validation errors for the given element will actually be shown
 */
 
var _LIMIT_VALIDATION_ERRORS = null;
function limitValidationErrorsTo(field) {
	_LIMIT_VALIDATION_ERRORS = field;
}

function clearValidationErrorLimit() {
	_LIMIT_VALIDATION_ERRORS = null;
}

function clearValidationErrorCache(){
	_ERROR_CACHE = new Array();
}

function showCachedValidationErrors(){
	for(i = 0; i < _ERROR_CACHE.length; i++){
		validationError(_ERROR_CACHE[i]["field"],
		_ERROR_CACHE[i]["message"],
		_ERROR_CACHE[i]["messageClass"],
		false);
	}
}

function strip_tags(text) {
	return text.replace(/<[^>]+>/g,'');
}
