(function($){
	$.fn.extend({
		setupValidation: function(options) {

			var defaults = {
				submitBtnSelector		: 'a:last',
				dialogSelector			: 'div.dialog',
				ctrlHiddenSelector	: ':input[name="performAction"]'
				
				// submitIfValid		: true
			};
			 
			var options = $.extend(defaults, options);

			// 1 item alone (a form)
			// FIXME  || $(this).get(0).tagName.toLowerCase() != 'form'
			if (this.length !== 1) {
				return false;
			}
			// FIXME : spit an error if !found any of the items with selectors in `defaults`

			var self = $(this);

			// assume form is invalid
			self.data('valid', false);
			self.data('submitIfValid', false);
			
			var fieldChanged = function (event) {
				// console.log('fieldChanged', self, arguments);
				self.data('submitIfValid', false);
				
				var el = event.target, val, lVal;
				if ($(el).get(0).type.toLowerCase() == 'radio') {
					val = self.find('[name="' + $(el).attr('name') + '"]:checked').val();
					if (typeof val == 'undefined' || !val.length) {
						 val = $(el).value;
					}
					// lVal = $(el).data('lValue');
				}
				else {
					val = el.value;
					lVal = $(el).data('lValue');
				}
				if (typeof lVal == 'undefined') {
					lVal = '';
					$(el).data('lValue', lVal);
				}
				if (String(val) !== String(lVal)) {
				// console.log(String(val), '@', String(lVal));
					if (self.data('jqxhrTimeout')) {
						clearTimeout(self.data('jqxhrTimeout'));
					}
					if (self.data('jqxhr')) {
						self.data('jqxhr').abort();
					}

					self.data('jqxhrTimeout', setTimeout($.proxy(function() { self.submit() }, self), 150)); // console.log('jqxhrTimeout: 150: starts now!'); 
					// console.log('jqxhrTimeout', self.data('jqxhrTimeout'));
				}
				$(el).data('lValue', val);
			}
			
			var fieldFocus = function() {
				// console.log('focus', $(this).attr('name'), self.find('[name="' + $(this).attr('name') + '"]'));
				var el = self.find('[name="' + $(this).attr('name') + '"]');
				if (typeof $(el).data('hadFocus') == 'undefined' || !$(el).data('hadFocus')) {
					$(el).data('hadFocus', true);
				}
			}

			$.each(self.find(':input'), function(key, field) {
				if ($(field).get(0).type.toLowerCase() == 'radio') {
					// console.log('XXX');
					$(field).bind('click', $.proxy(fieldChanged, self));
				}
				$(field).keyup($.proxy(fieldChanged, self));
				$(field).blur($.proxy(fieldChanged, self));
				$(field).focus($.proxy(fieldFocus, field));
			});

			// setup onsubmit
			self.submit(function() {
				if (!self.data('valid')) {
					
					self.data('firstField', false);

					self.data('jqxhr', $.ajax({
						type: "POST",
						url: self.action,
						data: self.serialize(),
						context: this,
						success: function(data){
							// console.log('response is back', arguments, this, $(this).find(options.ctrlHiddenSelector), $(this).find(options.ctrlHiddenSelector).val());
							if (data.nErrors == 0) {
								self.data('valid', true);
								// console.log('nErrors = 0', self, self.data('submitIfValid'));
								if (self.data('submitIfValid') == true) {
									self.find(options.ctrlHiddenSelector).val(2);
									// console.log('nErrors = 0', self, self.data('submitIfValid'), '@', self.find(options.ctrlHiddenSelector).val());
									// console.log('submit(): 102', self, self.data('submitIfValid'), '@', self.find(options.ctrlHiddenSelector).val());
									self.submit();
								}
							}
							else {
								self.data('valid', false);
							}
							// else 
							{

								$.each(data.fields, $.proxy(function(field, status) {
									var el = $(':input[name="' + field + '"]');
									if (typeof el.length != 'undefined' && el.length > 0) {
										//if (el[0].type == 'radio') {
											el = el[0];
										//}
									}

									if (!self.data('firstField') && (self.find(options.ctrlHiddenSelector).val() == -1 || !status.ok)) { 
										self.data('firstField', $(el));
									}

									if (($(el).data('hadFocus') || self.data('submitIfValid') == true)) { //  || $(el).attr('type') == 'radio'

										if (self.find(options.ctrlHiddenSelector).val() != -1) {
											$(el)[(!status.ok ? 'remove' : 'add') + 'Class']('ok-field');
											$(el)[( status.ok ? 'remove' : 'add') + 'Class']('failed-field');
										}

										var ct = $($(el).parents('tr')[0]).children('td.status')[0];

										var txt = '<ul>';
										$.each(status.v, $.proxy(function(key, validator) {
											txt = txt + '<li class="' + (self.find(options.ctrlHiddenSelector).val() == -1 ? 'not-checked' : (validator.ok ? 'ok' : 'failed')) + '">';
											// txt = txt + ((!validator.ok || $(this).find(options.ctrlHiddenSelector).val() == -1) ? validator.text : '&nbsp;') + '</li>';
											txt = txt + validator.text + '</li>';
										}, this));
										txt = txt + '</ul>';
										$(ct).html(txt);

									}

								}, this));

								// modal
								if (!self.data('valid') && self.find(options.ctrlHiddenSelector).val() != -1 && self.data('submitIfValid') == true) {
									if (!self.data('dialog')) {
										self.data('dialog', self.children( options.dialogSelector ).dialog({
											modal: true,
											autoOpen: false,
											resizable: false,
											buttons: {
												Ok: function() {
													$( this ).dialog( "close" );
													if ($(self).data('firstField')) {
														$($(self).data('firstField')).focus();
													}
												}
											}
										}));
									}
									self.data('dialog').dialog( "open" );
								}

							}

							if (self.find(options.ctrlHiddenSelector).val() == -1) {
								self.find(options.ctrlHiddenSelector).val(1);								
								if (self.data('firstField')) {
									$(self.data('firstField')).focus();
								}
							}

						 }
					}));
				}
				else {
					if (self.data('submitIfValid') == true) {
						self.find(options.ctrlHiddenSelector).val(2);
					}
				}

				var r = self.data('valid') && self.data('submitIfValid') && (self.find(options.ctrlHiddenSelector).val() == 2);
				if (r) {
					if (self.data('jqxhrTimeout')) {
						clearTimeout(self.data('jqxhrTimeout'));
					}
					if (self.data('jqxhr')) {
						self.data('jqxhr').abort();
					}
				}
				// console.log('return', r, self.data('valid'), self.data('submitIfValid'), self.find(options.ctrlHiddenSelector).val() == 2, self.find(options.ctrlHiddenSelector).val());
				return r;
			});

			var btn = this.find(options.submitBtnSelector);
			if (btn.length === 1) {
				$(btn[0]).click(function() {
					$(self).data('submitIfValid', true);
					self.submit();
					return false;
				});
			}

			$('#performAction').val(-1);
			$('#signupFrm').submit();
			// setTimeout(function() { $('#signupFrm').submit(); }, 5000);

		}
	});
})(jQuery);
