(function($){
	var undefined;
	
	$.regex = {
		phone:		/^[+]?([0-9]*[\.\s\-\(\)]|[0-9]+){10,24}$/,
		email: 		/^([a-zA-Z0-9])+([\.a-zA-Z0-9_-])*@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-]+)+$/,
		zip: 		/(^\d{5}$)|(^\d{5}-\d{4}$)/,
		name:		/^([a-zA-Z0-9-.\s])+$/,
		address: 	/^([a-zA-Z0-9-.\s])+$/,
		alphanumeric: /^[a-zA-Z0-9\s-]+$/,
		noHTML: 	/<("[^"]*"|'[^']*'|[^'">])*>/
	};

	$.extend({
		validationRules: {
			"customPassword": function(value){
				var isValid = {
					hasNumber: false, hasUppercase: false, hasLowercase: false, hasSpecial: false
				};
				
				var specialChars = "!@#$%^&*()+=-[]\\\';,./{}|\":<>?~_";
				
				$.each(value, function(k, letter){
					letter = letter || value.charAt(k);
					var isSpecial = false;
					var isNumber = false;
					
					$.each(specialChars, function(k, special){
						if (letter == special){
							isValid.hasSpecial = true;
							isSpecial = true;
						}
					});
					
					if (!isNaN(letter)){
						isValid.hasNumber = true;
						isNumber = true;
					}
					
					if (letter == letter.toUpperCase() && !isSpecial && !isNumber) isValid.hasUppercase = true;
					if (letter == letter.toLowerCase() && !isSpecial && !isNumber) isValid.hasLowercase = true;
				});
				
				var validCount = 0;
				$.each(isValid, function(ruleName, valid){
					if (valid) validCount++;
				});
				
				return (validCount >= 3);
			}
			,"value": function(value, val){
				var proceed = false;
				
				if (typeof val == 'boolean'){
					proceed = (val != '');
				}
				else if (typeof val == 'string'){
					proceed = (value == val);
				}
				else if ($.isArray(val)){
					$.each(val, function(k, v){
						if (value == v) proceed = true;
					});
				}
				
				return proceed;
			}
			,"regex": function(value, regex){
				return regex.test(value);
			}
			,"format": function(value, format){
				return $.validationRules.regex(value, $.regex[format]);
			}
			,"between": function(value, range){
				var numberRange = [];
				var start = range[0];
				var end = range[1];
				
				for(var i = start; i <= end; i++){
					numberRange.push(i);
				}

				return this.value(value, numberRange);
			}
			,"under": function(value, num){
				return value < num;
			}
			,"minLength": function(value, min){
				return value.length >= min;
			}
			,"maxLength": function(value, max){
				return value.length <= max;
			}
			,"onlyNumbers": function(value, bool){
				return (bool) ? !isNaN(value) : true;
			}
			,"onlyLetters": function(value, bool){
				// changed this to remove only letters validation on name fields
				return true;
//				return (bool) ? /^[a-zA-Z ]+$/.test(value) : true; 
			}
			,"match": function(value, selector){
				return (value == $j(selector).val());
			}
			,"ban": function(value, letters){
				var proceed = true;

				$.each(letters, function(k, character){
					if (value.indexOf(character) > -1) proceed = false;
				});
				
				return proceed;
			}
		},
		validate: function(value, rules){
			var _isValid = true;
			
			if (rules != undefined) {
				$.each(rules, function(ruleName, ruleProps){
					if ($.validationRules[ruleName] && !$.validationRules[ruleName](value, ruleProps)) _isValid = false;
				});
			}
			
			if (rules == undefined && value == '') _isValid = false; 
			if (value == null) _isValid = false;
			
			if ($.validationRules['format'](value, 'noHTML')) _isValid = false;
			
			return _isValid;
		},
		listen: function(evt, fn){
			$(document).bind(evt, fn);
		},
		dispatch: function(evt, args){
			$(document).trigger(evt, args);
		}
	});
	
	$.fn.extend({
		exists: function(){
			return ($(this).size() > 0);
		}
	})
		
	$.Form = function(options){
		this.defaults = {
			useAjax: true, fields: {}, ajaxOptions: { dataType: 'json' , type: 'POST' }, beforeSubmit: function(){ return true; }
		};
		
		var
			_self = this,
			_settings = $.extend(true, {}, this.defaults, options);
			
		this.$element = _settings.$element;
		this.fields = {};
		
		/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		 * start:private
		 * >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
		function _init(){
			// build field objects
			$.each(_settings.fields, function(fieldName, fieldProperties){
				if (_self.$element.find('[name=' + fieldName + ']').exists()){
					fieldProperties.name = fieldName;
					fieldProperties.$element = _self.$element.find('[name=' + fieldName + ']');
					_self.fields[fieldName] = new $.Field(fieldProperties);
				}
			});
			
			// sets up dependency objects for condition checks
			$.each(_settings.fields, function(name, rules){
				if (_self.fields[name] != undefined){
					var fieldObj = _self.fields[name];
					var conditions = fieldObj.getConditions();
					
					$.each(conditions, function(conditionType, condition){
						$.each(condition, function(conditionFieldName, conditionRules){
							$.dispatch('setDependency.' + name, [_self.fields[conditionFieldName]]);
						});
					});
				}
			});
			
			_self.$element.submit(function(e){
				$.dispatch('valueChanged');
				$.dispatch('formSubmission');
				_self.submit(e);
			});
			
			// if custom init method is provided, execute it
			if (this.init) this.init();
		};
		
		// end:private
		
		/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		 * start:public
		 * >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
		
		this.submit = function(e){
		    if (_settings.beforeSubmit()){
				var validated = this.validate();

				if (!validated || _settings.useAjax) e.preventDefault();
				
				if (validated && _settings.useAjax){
					var opts = _settings.ajaxOptions;
					opts.data = this.getValues();
// :MERGE: Inserted Begin					
					var myAvaya = new MyAvayaHandle ();
					var jsonstring = JSON.stringify(_settings.ajaxOptions.data).replace(/\"value=/g,"");
					jsonstring = jsonstring.replace(/\"\"/g,"\\\"");
					jsonstring = jsonstring.replace(/\\\\/g,"\\");
					jsonstring = jsonstring.replace(/\\\"/g,"\"");
					//alert(jsonstring);
					
					if (typeof _settings.ajaxOptions.name != 'undefined') {
					    if (_settings.ajaxOptions.name == "subscribe")
					    myAvaya.UpdateSubscription(parseInt(regID),"[" + jsonstring + "]");
					    
					    if (_settings.ajaxOptions.name == "contentpreferences")
					    myAvaya.UpdateContentPreferences(parseInt(regID),"[" + jsonstring + "]");
					    
					    if (_settings.ajaxOptions.name == "myprofile")
					    myAvaya.UpdateRegistrationPerson(parseInt(regID),"[" + jsonstring + "]");
					    
					    if (_settings.ajaxOptions.name == "UpdateManageSubscription")
					    myAvaya.UpdateManageSubscription(parseInt(regID),"[" + jsonstring + "]");
					}
// :MERGE: Inserted End					
					$.ajax(_settings.ajaxOptions);
// :MERGE: Inserted Begin
					if (typeof document.forms["regform"] != 'undefined')
                    document.forms["regform"].submit();
                    
                    if (typeof document.forms["MyAvayaEmailPreferencesForm"] != 'undefined')
                    document.forms["MyAvayaEmailPreferencesForm"].submit();
// :MERGE: Inserted End
				}
			}
			else {
				e.preventDefault();
			}
		};
		
		this.getValues = function(){
			var values = {};
			
			$.each(this.fields, function(fieldName, fieldObj){
				var val = fieldObj.getValue();
				if (val != '') values[fieldName] = val;
			});
			
			return values;
		};
		
		this.validate = function(){
			// loop thru fields and validate
			// if a field doesnt validate, valid = false
			// if !valid display error, return false
			// if valid, hide error, ajax call/submit form
			var valid = true;
			
			$.each(this.fields, function(fieldName, fieldObj){
				if (!fieldObj.validate()) valid = false;
			});
			
			return valid;
		};
		
		// end:public
		
		_init();
	};
	
	$.Field = function(options){
		this.defaults = { value: '', conditions: {}, dependency: {} };
		
		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(e){
				_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();
				
				var params = {
					$element: _self.$element, visible: bool
				}
				
				$.dispatch('conditionCheck', [params]);
			});
			
			_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();
				
			
			this.checkConditions();
			
			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) 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');
	}
})($j);
