/**
 * @created March 2010
 * @usage 
 * 1. Add a 'validate' to the form you want validated.
 * 2. Add a 'required' class to the block level elements housing the fields you want validated. 
 * 3. Add 'req' to the required fields (for radio buttons just add it to the first one).
 * 4. ids and field names must be identical
 * 5. Do what you need to in FormValidator.php and watch it work.
 * 
 * Special cases:
 * # Add a 'match' class to elements that just confirm the input of the one before it.
 * # For really special cases you can set it up in a page specific script and pass the
 * arguments to $p.Validate.handle
 * 
 * -Rob
 * 
 */
if (typeof($p) == 'undefined') $p = {};
if (typeof($p.valConfig) == 'undefined') $p.valConfig = {};

$p.Validate = function() {
	// Private variables for the whole class
	var _validateUrl = null;
	var _field = null;
	var _fieldName = null;
	var _container = null;
	var _els = [];
	var _valid = false;
	var _form = null;
	var _submitted = false;
	
	// Ajax call and parsing result
	function send(query, isForm){
		$.post(
				_validateUrl,
				query,
				function(data){
					_valid = data['valid'];
					// Set up the elements we'll be effecting
					if(_els.length == 0) {
						if(!_valid) {
							$(data['fields']).each(function(){
								_els.push(document.getElementById(this));
							});
						} else {
							_els.push(document.getElementById(_fieldName));
						}
					}
					if(_valid && !isForm){
						$(_els).each(function(){
							clearFields(this);
							clearErrors();
						});
					} else if(_valid) {
						// _submitted keeps IE from submitting twice
						if(!_submitted){
							// if we have a custom action when it's valid do it
							if(typeof($p.valConfig.formAction) != 'undefined'){
								$p.valConfig.formAction();
							} else {
								_form.submit();
							}
						}
						_submitted = true;
					} else {
						// apply errors
						displayErrors(data['errors'], data['fields']);
						$(_els).each(function(){
							_container = $(this).parents('fieldset')[0];
							highlightFields(this);
						});	
						// For form submissions we need to refresh the captcha
						if(isForm && typeof(Recaptcha) != 'undefined'){
							Recaptcha.reload();	
						}
					}
				},
				'json'
			);		
	}
	// The publicly available 'handle' function figures out the query and what's needed
	function process(field, value, container, els, form, match){
		_field = field;
		var query = {};
		if($(field).is('form')){
			query['form'] = _field.name;
			$(field).find(':input').each(function(){
				query[this.name] = this.value;
			});
			_form = field;
		} else {
			_fieldName = typeof(field) == 'string' ? field : field.name;
			_value = value || field.value;
			_container = container || $(field).parents('fieldset')[0];
			_form = form || $(field).parents('form')[0];
			var _match = match || $(field).hasClass('match');
			query[_fieldName] = _value;
			if(typeof(_match) != 'undefined' && _match != false){	
				if(typeof(_match) == 'boolean'){
					var first = $(field).parents('fieldset').find('input')[0];
					query[first.name] = first.value;					
				} else {
					query[match[0]] = match[1];
				}
			}
		}
		query['form'] = _form.name;
		_els = els || [];
		send(query, $(field).is('form'));
	}
	// Show fields with errors
	function highlightFields(el){
		$(el).removeClass('valid');
		$(el).addClass('error');
		
		checkFieldSet(_container);
	}
	// Remove error class
	function clearFields(el){
		$(el).removeClass('error');
		$(el).addClass('valid');
		checkFieldSet(_container);
	}
	// Remove error message
	function clearErrors(){
		if(document.getElementById(_fieldName + 'Error')){
			removeError('#' + _fieldName + 'Error');
		}			
	}
	// Effects on block element
	function checkFieldSet(_container){
		if($(_container).find('error').length == 0){
			$(_container).removeClass('invalid');	
		}
		if($(_container).find('.valid').length == $(_container).find('.req').length){
			$(_container).addClass('valid');			

		} else if ($(_container).find('.error').length > 0) {
			$(_container).removeClass('valid');
			$(_container).addClass('invalid');			
		}
	}
	// Create error container
	function displayErrors(errors, fields){
		// If the element doesn't exist
		if(!document.getElementById('errors')){
			var errorBox = document.createElement('div');
			errorBox.setAttribute('id', 'errors');
			errorBox.className = 'errors';
			var list = document.createElement('ol'); 
			$(errorBox).append(list);
			$(errorBox).prependTo($('#main'));
		}
		var i = 0;
		// Populate with errors
		$(fields).each(function(){
			var el = (this + 'Error');
			// If an error already exists for this field remove it if it's not the same error
			if((document.getElementById(el) && document.getElementById(el).innerHTML != errors[i]) || !document.getElementById(el)){
				if(document.getElementById(el)){
					document.getElementById(el).innerHTML = errors[i];
				} else {
					// Create the error
					var li = document.createElement('li');
					li.setAttribute('id', el);
					// Add a class to location fields that can be swapped out for easy removal
					if($('#' + this).parents('ul').hasClass('dynamicLocation')){
						li.className = 'dynamicLocErr';
					}
					if(document.getElementById(this) && document.getElementById(this).name.indexOf('shipTo_') != -1){
						li.className = 'shippingErr';
					}
					li.innerHTML = errors[i];
					$('#errors ol').append(li);		
				}
			}
			i++;
		});
	}
	// Remove error
	function removeError(error){
		$(error).remove();
		//Check error state
		$p.errorState();
	}
	// Hook everything up
	function init(url){
		_validateUrl = url;
		// Hijack the form on submit
		$('form.validate').submit(function(event){
			event.preventDefault();
			process(this);
		});
		
		// Basic Validotion for text fields
		$('.required input.req').live('blur', function(){
			this.value = $p.trim(this.value);
			process(this);
		});
		
		// Same thing for selects
		if($('.required select').length > 0){
			$('.required select').live('change', function(){
				process(this);
			});	
		}
		
		// So that text fields lose focus before submit is clicked
		$('form.validate input.submit').mouseover(function(){
			$('.req').each(function(){
				this.blur();
			});				
		});
	}
	// The public API
	return {
		init:init,
		handle:process
	}
}();

$(document).ready(function(){
	$p.Validate.init('/web-service/validate');
});
 