/**
 * @projectDescription 	Form field object with ability to validate itself and respond to set conditions and rules
 * @version 			1.0
 * @author 				Alex Heyd - alex.heyd@rga.com - AIM: "overwritten"
 * @date				03/09/2010
 * @lastUpdate 			03/09/2010 
 * @QATech 				n/a
 * @QAPassed 			NO
 * @dependency 			helpers.js
 * @param {Object}		options
 * @param {Boolean}		options.required If field is required or not
 * @param {String}		options.errorMsg Error message for the field
 * @param {Object}		options.rules See $.validationRules in helpers.js for a list of possible properties
 * @param {Object}		options.conditions 
 * @param {Object}		options.conditions.required Key is the name of the field upon which the condition must be met, value is rules to apply
 * @param {Object}		options.conditions.enabled Key is the name of the field upon which the condition must be met, value is rules to apply
 * @param {Object}		options.conditions.visible Key is the name of the field upon which the condition must be met, value is rules to apply
 */

/*
EXAMPLE OF OPTIONS.FIELDS:

var fields = {
	"firstName": {
		required: true,
		errorMsg: "Please enter your first name.",
		rules: {
			onlyLetters: true, maxLength: 30
		},
		conditions: {
			required: {
				"lastName": {
					value: true // i.e filled in or checked
				}
			} 
		}
	}
}
*/

(function($){
	var undefined;
		
	$.Field = function(options){
		this.defaults = { value: '', conditions: {}, dependency: {}, errorMsg: 'Invalid Field' };
		
		var
			self = this,
			settings = $.extend(true, {}, this.defaults, options);

		this.$element = settings.$element;
		
		/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		 * start:private
		 * >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
		function _init(){
			self.setValue();
			
			$.listen('isValid.field.' + self.getName(), function(){
				self.hideError();
			});
			
			$.listen('isInvalid.field.' + self.getName(), function(){
				self.showError();
			});
			
			$.listen('setDependency.' + self.getName(), function(e, fieldObj){
				self.setDependency(fieldObj);
			});
			
			$.listen('valueChanged.' + self.getName(), function(){
				self.setValue();
			});
			
			$.listen('checkConditions', function(){
				self.checkConditions();
			});
			
			$.listen('enabled.' + self.getName(), function(e, bool){
				if (bool) self.$element.removeAttr('disabled'); else self.$element.attr('disabled', true);
			});
			
			$.listen('required.' + self.getName(), function(e, bool){
				self.setRequired(bool);
			});
			
			$.listen('visible.' + self.getName(), function(e, bool){
				if (bool) self.$element.show(); else self.$element.hide();
			});
			
			self.$element.change(function(){
				$.dispatch('valueChanged.' + self.getName());
				$.dispatch('checkConditions');
			});
			
			// if custom init method is provided, execute it
			if (this.init) this.init();
		};
		
		// end:private
		
		/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		 * start:public
		 * >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
		
		this.checkConditions = function(){
			
			$.each(this.getConditions(), function(conditionType, conditions){
				var allConditionsMet = true;
				
				$.each(conditions, function(conditionName, conditionRules){
					var isMet = self.dependency[conditionName].validate(conditionRules, true);
					if(!isMet) allConditionsMet = false;
				});
				
				$.dispatch(conditionType + '.' + self.getName(), [allConditionsMet]);
			});
		};
		
		this.validate = function(rules, conditionCheck){
			var
				valid = true,
				fieldValue = this.getValue();
				
			rules = rules || this.getRules();
			conditionCheck = conditionCheck || false;
			
			var _validate = function(){
				if (!$.validate(fieldValue, rules)) valid = false;
			}
			
			if (fieldValue == '' || fieldValue == null){
				if (conditionCheck) _validate();
				else if (this.isRequired()) valid = false;
			}
			else {
				_validate();
			}
			
			if (!conditionCheck){
//				if (valid) $.dispatch('isValid.field.' + self.getName()); else $.dispatch('isInvalid.field.' + self.getName());
				if (valid) this.hideError(); else this.showError();
			}

			return valid;
		};
		
		this.isRequired = function(){
			return settings.required;
		};
		
		this.isBlank = function(){
			return (this.getValue() == '');
		};
		
		this.getErrorMsg = function(){
			return settings.errorMsg;
		};
		
		this.getName = function(){
			return settings.name;
		};
		
		this.getValue = function(){
			return settings.value;
		};
		
		this.getRules = function(){
			return settings.rules;
		};
		
		this.getConditions = function(){
			return settings.conditions;
		}
		
		this.setRequired = function(bool){
			settings.required = bool;
		};
		
		this.setDependency = function(fieldObj){
			if (this.dependency == undefined) this.dependency = {};
			this.dependency[fieldObj.getName()] = fieldObj;
		};
		
		this.setRules = function(rules){
			settings.rules = $.extend(true, settings.rules, rules);
		};
		
		this.setConditions = function(conditions){
			settings.conditions = $.extend(true, settings.conditions, conditions);
		};
		
		this.setValue = function(val){
			if (val == undefined){
				var $elem = this.$element;
				var value = null;
				
				if ($elem.is(':radio') || $elem.is(':checkbox')){
					var isChecked = $elem.is(':checked');
					var $checked = $elem.filter(':checked');
					if (isChecked) value = $checked.val();
					
					if (isChecked && $elem.is(':checkbox')){
						value = [];
						
						$elem.filter(':checked').each(function(){
							value.push($(this).val())
						});
					}
				}
				else {
					value = $elem.val();
				}
				
				val = value;
			}
			
			settings.value = val;
		};
		
		// end:public

		_init();
	};
	
	$.Field.prototype.showError = function(){
		this.$element.addClass('invalid');
	}
	
	$.Field.prototype.hideError = function(){
		this.$element.removeClass('invalid');
	}
})(jQuery);


