(function($) {

	var 	CLASS_LABELEDVALUES_LABELED	= 'labeled',
			CLASS_LABELEDVALUES_TARGET	= 'labeled_value',
			CLASS_REPLACED_BUTTONS		= 'custom',
			HTML_REPLACED_BUTTON_OPEN	= '<a href="#"><span>',
			HTML_REPLACED_BUTTON_CLOSE	= '</span></a>';

	var FormSupport = {
		init: function() {
			window.isIE6 = /msie 6/i.test(navigator.userAgent)? true:false;
			this.forms = $('form');
			this.LabeledValues.init(this.forms);
			this.CustomButtons.init(this.forms);
			this.HelpPopups.init(this.forms);
			//this.CalendarPopups.init(this.forms);
			this.PasswordStrengthMeters.init(this.forms);
		}
	}
	
	// labeled values
	// values in form text fields that function as their label (and will disappear when focus is received)
	FormSupport.LabeledValues = {
		init: function(root) {
			if(!root) root = $(document);
			$('.' + CLASS_LABELEDVALUES_TARGET, root).each(function() {
				var t = this.nodeName.toUpperCase();
				if(t == 'TEXTAREA' || (t == "INPUT" && $(this).attr('type') == 'text')) {
					// target form fields labeled 
					FormSupport.LabeledValues.prepareField($(this));
				} else {
					// target form fields within a parent labeled
					$('textarea, input[type=text]', $(this)).each(function() {
						var label = $('label[for=' + $(this).attr('id') + ']', root);
						$(this).attr({ title: label.text() });
						FormSupport.LabeledValues.prepareField($(this));
					});
				}
			});
		},
		prepareField: function(element) {
			FormSupport.LabeledValues.setLabel(element);
			element.bind('focus', function() { FormSupport.LabeledValues.resetLabel(element); });
			element.bind('blur', function() { FormSupport.LabeledValues.setLabel(element); });
		},
		setLabel: function(element) {			
			var title = element.attr('title');
			if(element.val() == '' || element.val() == element.attr('title')) {
				element.val(title);
				element.addClass(CLASS_LABELEDVALUES_LABELED);
			}
		},
		resetLabel: function(element) {
			var title = element.attr('title');
			if(element.val() == title) {
				element.val('');
				element.removeClass(CLASS_LABELEDVALUES_LABELED);
			}
		}
	}
	
	// custom buttons
	// submit buttons that get 'replaced' into custom HTML without disturbing a form's default (and added) functionality
	FormSupport.CustomButtons = {
		init: function (root) {
			if(!root) root = $(document);
			$('input.' + CLASS_REPLACED_BUTTONS + '[type=submit], input.' + CLASS_REPLACED_BUTTONS + '[type=reset]', root).each(function () {
				FormSupport.CustomButtons.replace($(this));
			});
		},
		replace: function (origin) {
			var replacement = jQuery(HTML_REPLACED_BUTTON_OPEN + origin.val() + HTML_REPLACED_BUTTON_CLOSE);
			replacement.attr({
				title: origin.attr('title'),
				className: origin.attr('class')
			});
			if (origin.attr('name') != undefined) {// Add submit name/value pair to rel attribute
				replacement.attr('rel', origin.attr('name') + '|' + origin.attr('value'));
			}
			origin.css({ display: 'none' });
			origin.after(replacement);
			if(origin.attr('type') == 'submit') {
				if (origin.attr('onclick') != undefined) {// Add submit name/value pair to rel attribute
					replacement.attr('onclick', origin.attr('onclick'));
				}
				else {
					replacement.click(function(e) {
						/*
						if ($(this).attr('rel') != undefined) {
							var pair = $(this).attr('rel').toString().split('|');
							$(this).parents('form').append('<input type="hidden" name="' + pair[0] + '" value="' + pair[1] + '"></input>');
						}
						*/
						FormSupport.CustomButtons.submitClick(this);
						$(this).parents('form').submit();
						e.preventDefault();
					});
				}
				origin.remove();
			} else {
				replacement.click(function(e) {
					$(this).parents('form').reset();
					e.preventDefault();
				});
			}
			return true;
		},
		submitClick: function (el) {
			el = $(el);
			if (el.attr('rel') != undefined) {
				var pair = el.attr('rel').toString().split('|');
				el.parents('form').append('<input type="hidden" name="' + pair[0] + '" value="' + pair[1] + '"></input>');
			}
		}
	};
	
	// help popups
	// small, unobtrisive tooltips that contain additional info and appear when an icon is clicked or hooked form fields receive focus
	FormSupport.HelpPopups = {
		init: function(root) {
			if(!root) root = $(document);
			this.targetPopup = null;
			this.popupLayer = $('<div id="help_popuplayer"><div id="help_popuplayer_content"></div></div>');
			$('body').append(this.popupLayer);
			$('a.help', root).bind('focus', function(e) {
				FormSupport.HelpPopups.close();
				FormSupport.HelpPopups.open($(this));
			}).bind('blur', function() { 
				FormSupport.HelpPopups.close(); 
			}).each(function() {
				$('select, input, textarea', $(this).parent()).bind('focus', function() {
					FormSupport.HelpPopups.open($('a.help', $(this).parent()));
				}).bind('blur', function() { 
					FormSupport.HelpPopups.close();
				});
			}).bind('click', function(e) { 
				$(this).focus(); 
				e.preventDefault(); 
			});
		},
		open: function(sourceLink) {
			this.targetPopup = $('#' + sourceLink.attr('href').split('#')[1]);
			$('#help_popuplayer_content', this.popupLayer).html(this.targetPopup.html());
			this.popupLayer.css({ top: sourceLink.offset().top + 'px', left: sourceLink.offset().left + 'px' });
		},
		close: function() {
			if(!this.targetPopup) return;
			this.popupLayer.css({ left: '-3000em' }); 
			this.targetPopup = null;	
		}
	}
	
	// calendar popups
	// a small calendar to make date selection easier for a user
	/*FormSupport.CalendarPopups = {
		init: function(root) {
			if(!root) root = $(document);
			this.popupLayer = $('<div id="calendar_popuplayer"><div id="calendar_popuplayer_content"></div></div>');		
			this.sourceLink = null;
			$('body').append(this.popupLayer);
			$('a.calendar', root).bind('click', function(e) {
				FormSupport.CalendarPopups.close();
				FormSupport.CalendarPopups.open($(this));
				e.preventDefault(); 
			});
		},
		open: function(sourceLink) {	
			this.sourceLink = sourceLink;	
			FormSupport.CalendarPopups.update();
			this.popupLayer.css({ top: this.sourceLink.offset().top + 'px', left: this.sourceLink.offset().left + 'px' });	
		},
		close: function() {
			this.popupLayer.css({ left: '-3000em' }); 
		},
		getDate: function() {
			var parent = this.sourceLink.parent();
			var dateObject = {
				day: $('.calendar_day', parent).eq(0).val(),
				month: $('.calendar_month', parent).eq(0).val(),
				year: $('.calendar_year', parent).eq(0).val()
			};
			return dateObject;
		},
		setDate: function() {
			return;
		},
		convertDate: function(dateObject) {
			// TODO: what id dateObject contains an invalid date?
			var date = new Date();
			date.setDate(dateObject.day);
			date.setMonth(dateObject.month);
			date.setFullYear(dateObject.year);
		},
		update: function() {
			return;
		}
	}*/
	
	// password strength meters
	FormSupport.PasswordStrengthMeters = {
		init: function(root) {
			if(!root) root = $(document);
			this.labels = ['insufficient', 'very weak', 'weak', 'okay', 'good', 'excellent'];
			var template = $('<span class="pw_strength_meter" title="This bar displays the strength of the password you have chosen"><span></span><em></em></span>');
			$('.pw_measure', root).each(function() {
				$(this).after(template.clone().css('display', 'none'));
				$(this).bind('keyup', function() { 
					FormSupport.PasswordStrengthMeters.measure($(this)); 
				});
				FormSupport.PasswordStrengthMeters.measure($(this));
			});
		},
		measure: function(field) {
			var meter = $('.pw_strength_meter', field.parent());
			var password = field.val();
			var strength = FormSupport.PasswordStrengthMeters.getStrength(password);
			var labelIndex = Math.floor((strength / 100) * (FormSupport.PasswordStrengthMeters.labels.length - 1));
			if(password.length > 0 ) meter.fadeIn(); else meter.fadeOut();
			$('span', meter).css({ width: strength + '%' });
			$('em', meter).text(FormSupport.PasswordStrengthMeters.labels[labelIndex]);
		},
		getStrength: function(password) {
			if(!password) return 0;
			var score = 0;
			var maxScore = 65;
			var len = password.length;
					
			// password length matters, below 4 is instant fail, +4 reward for each additional character above 3
			if(len < 4) return 0; else score = len * 4;
			// password contains mixed-case characters, +10 reward
			if(password.match(/[a-z]/) && password.match(/[A-Z]/)) score += 10;
			// password contains characters and special characters, +15 reward
			if(password.match(/[a-z]/i) && password.match(/[^A-Za-z0-9_]/)) score += 15;
			// password is only characters, -10 penalty
			if(!password.match(/[0-9_]/) && !password.match(/[^A-Za-z0-9_]/)) score -= 10;
			// password contains numbers and lower-/uppercase characters, +15 reward
			if(password.match(/[0-9_]/) && password.match(/[a-z]/i)) score += 15;
			// password contains numbers and special characters, +15 reward	
			if(password.match(/[0-9_]/i) && password.match(/[^A-Za-z0-9_]/)) score += 15;
			// password is only numbers, -10 penalty
			if(!password.match(/[a-z]/i) && !password.match(/[^A-Za-z0-9_]/)) score -= 10;
			
			
			// TODO: there should be an entropy/pattern check, but I cannot do it
			// TODO: there should be a check on the values of other fields with the password (a no-go)
			
			
			if(score < 0) score = 0;
			if(score > maxScore) score = maxScore;
			var percentage = Math.round(100 * (score / maxScore));
			return percentage;
		}
	}
	
	
	

	$(function() {
		FormSupport.init();
	});	
	
})(jQuery);


