//////////////////////////
// Add methods to GOOD
//////////////////////////

$.extend(GOOD, {

	form: {

		// Validate a form input or a string (work in progress)
		validate: function (field, type) {
			var regex = {
					email: /^([a-z0-9!#$%&'*+\/=?\^_`{|}~\-]+(?:\.[a-z0-9!#$%&'*+\/=?\^_`{|}~\-]+)*)@(?:[a-z0-9](?:[a-z0-9\-]*[a-z0-9])?\.)+(?:[a-z]{2,4}|museum|travel)$/i
				},
				value, required, message;

			if (typeof field === 'string') {
				value = field;
			} else if (field.jquery) {
				value = field.val();
				required = field.hasClass('required');
			} else if (field.value) {
				value = field.value;
				required = /\brequired\b/.test(field.className);
			}

			if (regex[type].test(value)) {
				message = 'valid';
			} else if (value === '') {
				message = 'You forgot to enter a' + ((/[aeiou]/.test(type)) ? 'n ' : ' ') + type;
			} else {
				message = 'Please enter a valid ' + type;
			}

			return message;
		},

		// Replaces a form with its confirmation message
		confirm: function (selector, message, callback) {
			var $form = $(selector);
			GOOD.form.animateAndReplace($form, '<h4>' + message + '</h4>', callback);
		},

/**
 * error
 * Injects an error message into a standard HTML element
 *
 * @param mixed selector Any valid jQuery selector representing the present form
 */
		error: function (selector, messages, callback) {
			var $form = $(selector),
				$error = $form.find('.form_error'),
				$list = $('<ul/>'),
				message;

			if (!$error.length) {
				$error = $('<div class="form_error"/>')
					.prependTo($form)
					.append('<span/>');
			}

			if (typeof messages === 'object') {
				for (var field in messages) {
					if (messages.hasOwnProperty(field)) {
						message = messages[field];
						$list.append('<li class="error-message ' + field +'">' + message + '</li>');
					}
				}
			} else {
				$list.append('<li class="error-message">' + messages + '</li>');
			}

			GOOD.form.animateAndReplace($error.children(), $list, {
				show: ['slide', { direction:'up' }, 300]
			});
		},

/**
 * disable
 * Adds a 'disabled' class to a form and then disables and blurs all fields within
 *
 * @param mixed selector Any valid jQuery selector representing the form to be disabled
 */
		disable: function (selector) {
			$(selector)
				.addClass('disabled')
				.find(':input').attr('disabled', 'disabled').blur();
		},

/**
 * enable
 * Removes a 'disabled' class from a form and then unsets any disabled attributes from all fields within
 *
 * @param mixed selector Any valid jQuery selector representing the form to be disabled
 */
		enable: function ($form) {
			$form
				.removeClass('disabled')
				.find(':input').removeAttr('disabled').not(':hidden').filter(':first').focus();
		},

/**
 * ajaxSubmit
 *
 * @param mixed selector Any valid jQuery selector representing the form to be disabled
 */
		ajaxSubmit: function (form, options) {
			var $form = $(form),
				config = {
					type: form.method,
					url: form.action,
					data: $(form).serialize(),
					dataType: 'json'
				};

			GOOD.form.disable($form);

			if ($.isFunction(options.error)) {
				options.error = function (XMLHttpRequest, textStatus, errorThrown) {
					options.error.call(config, XMLHttpRequest, textStatus, errorThrown);
					GOOD.form.enable($form);
				};
			} else {
				options.error = function () {
					GOOD.form.enable($form);
				};
			}

			$.extend(config, options);
			$.ajax(config);
		},

		getAncestor: function (selector, expr) {
			var $parents = $(selector).parents();
			for (var i=0; i<$parents.length; i++) {
				if ($parents.eq(i).is(expr)) {
					return $parents.eq(i);
				}
			}
			return false;
		},

		isChildOf: function (selector, expr) {
			var $parents = $(selector).parents();
			for (var i=0; i<$parents.length; i++) {
				if ($parents.eq(i).is(expr)) {
					return true;
				}
			}
			return false;
        },

		getDialog: function (selector) {
			return GOOD.form.getAncestor(selector, '.ui-dialog-content');
		},

		isInDialog: function (selector) {
			return GOOD.form.isChildOf(selector, '.ui-dialog-content');
		},

/**
 * animateAndReplace
 *
 * @param selector (mixed) A valid jQuery selector (of maybe any element?)
 * @param options (object) A list of configuration options:
 *		- setup (function) A callback invoked prior to replacement.
 *		- complete (function) A callback invoked after replacement has been made and revealed
 * @return void
 * @access public
 */
		animateAndReplace: function (oldSelector, newSelector, options) {
			var $old = $(oldSelector),
				$new = $(newSelector),
				$container = $old.wrapAll('<div/>').parent(),
				$placeholder = $container.wrapAll('<div/>').parent();

			function afterReveal() {
				$placeholder.replaceWith($new);
				options.after.call(this, $old, $new);
			}

			function afterHide() {
				options.before.call(this, $old, $new);
				$container.empty().append($new);
				$container.show.apply($container, options.show);
				$placeholder.animate({ height:$container.height() }, 200, afterReveal);
			}

			options = $.extend({
				before: function () {},
				after: function () {},
				hide: ['slide', { direction:'left' }, 200 ],
				show: ['slide', { direction:'right' }, 200 ]
			}, options);

			options.hide.push(afterHide);

			$placeholder.css({ height:$placeholder.height(), overflow:'hidden' });
			$container.hide.apply($container, options.hide);
		},

/**
 * initForm
 * Initializes a GOOD form
 *
 * @param mixed selector A valid jQuery selector of the form
 * @return void
 * @access public
 */
		initForm: function (selector, options) {
			var $form = $(selector);

			options = options || {};

			options.formSuccess = options.formSuccess || function (json) {
				GOOD.form.confirm($form, json.message, options.success);
			};

			options.formError = options.formError || function (json) {
				GOOD.form.enable($form);
				GOOD.form.error($form, (json.errors) ? json.errors : json.message, options.error);
			};

			$form.submit(function (e) {

				e.preventDefault();

				$form.addClass('submitting');

				GOOD.form.ajaxSubmit(this, {
					success: function (json, status) {
						if (json.success) {
							options.formSuccess.call($form, json);
						} else {
							options.formError.call($form, json);
						}
					},
					complete: function () {
						$form.removeClass('submitting');
					}
				});
			});

			// Timeout needed to select input element in a form being animated into page
			setTimeout(function () {
				$form.find(':text').eq(0).focus();
			}, 300);
		},

/**
 * initReminder
 * Initializes the "reminder" link within a registration/login form,
 * which essentially just toggles b/w the two respective views
 *
 * @param mixed selector A valid jQuery selector of the form reminder (must be
 *		a descendant of a .registration element -- which is what gets replaced)
 */
		initReminder: function initReminder(selector, reminder) {
			var $container = GOOD.form.getAncestor(selector, '.registration'),
				$reminder = $container.find('a[href=/login],a[href=/users/signup]');

			$reminder.unbind().click(function (e) {

				e.preventDefault();

				$.get(this.href, function (html) {
					var $html = $(html),
						$existing = $container.children().not('.facebook'),
						$replacement = $html.children().not('.facebook');

					GOOD.form.animateAndReplace($existing, $replacement, {
						before: function ($old, $new) {
							$container.attr('class', $html.attr('class'));
							$new.find('#UserUserEmail').val($old.find('#UserUserEmail').val());
						},
						after: function ($old, $new) {
							var $dialog = GOOD.form.getDialog($new);
							if ($dialog) {
								$dialog.dialog('option', { title:$reminder.attr('title') });
							}
							$new.find('#UserUserEmail').focus();
						}
					});
				});
			});
		},

/**
 * initForgetLink
 * Initializes the forgot password "link" on login and facebook associate forms
 */
		initForgetLink: function (selector) {
			var $form = $(selector),
				$forgot = $form.find('[href=/forgot_password]');

			$forgot.unbind().click(function (e) {
				var $this = $(this),
					$email = $form.find('[id=UserUserEmail]'),
					emailData = {};

				function update(text, timeOut, timeIn) {
					timeOut = timeOut || 100;
					timeIn = timeIn || 500;
					$this.animate({ opacity:0 }, timeOut, function () {
						$this.html(text).animate({ opacity:1 }, timeIn);
					});
				}

				function reset() {
					$email.focus();
					update('Click here to reset your password', 1000, 500);
				}

				e.preventDefault();

				if ($email[0].value) {

					emailData[$email[0].name] = $email[0].value;

					$this.addClass('submitting');

					$.ajax({
						type: 'POST',
						url: this.href,
						dataType: 'json',
						data: emailData,
						success: function (json) {

							if (json.success) {
								$this
									.removeAttr('href')
									.unbind('click')
									.addClass('searched');

								$form.find('[id=UserUserPass]').focus();
							}

							$this.removeClass('submitting');
							update(json.message);

							if (!json.success) {
								$email.one('click', reset);
							}
						}
					});

				} else {
					update('Please provide an email address or username above.');
					$email.one('click', reset);
				}
			});
		},

/**
 * initLogin
 * Initializes a login process
 *
 */
		login: function login(selector) {
			var $login = $(selector);

			GOOD.form.initForm($login, {
				formSuccess:function () {
					GOOD.refresh(!GOOD.form.isInDialog($login));
				}
			});

			GOOD.form.initForgetLink($login);
			GOOD.form.initReminder($login);
		},

/**
 * initSignup
 * Initializes a signup process
 *
 */
		signup: function (selector) {
			var $signup = $(selector);

			GOOD.form.initForm($signup, {
				formSuccess: function () {
					GOOD.refresh(!GOOD.form.isInDialog($signup));
				},
				formError: function (json) {
					var $reminder = GOOD.form.getAncestor($signup, '.registration').find('.reminder');

					GOOD.form.enable($signup);

					if (json.errors && /account already exists/.test(json.errors.user_email)) {

						$.get('/login', function (html) {
							var $html = $(html);

							GOOD.form.animateAndReplace($signup, $html.find('form'), {
								before: function ($old, $new) {
									$new.find('#UserUserEmail').val($old.find('#UserUserEmail').val());
									$reminder.html($html.find('.reminder').html());
									$new.find('a[href=/login]').click(function () {
										$new.find('#UserUserEmail').val('');
									});
								},
								after: function ($old, $new) {
									GOOD.form.error($new, json.errors.user_email);
									GOOD.form.login($new);
									$new.find('#UserUserPass').focus();
								}
							});
						});

					} else {
						GOOD.form.error($signup, json.errors);
					}
				}
			});

			GOOD.form.initReminder($signup);
		},

/**
 * initForgotPassword
 * Initializes a reset password process
 */
		forgotPassword: function (selector) {
			var $forgot = $(selector);

			GOOD.form.initForm($forgot);
		},

/**
 * initFacebookAccount
 * Initializes a facebook connect confirmation process
 */
		facebookAccount: function (selector) {
			var $associate = $(selector),
				$container = $('.facebookAccount'),
				$quickClick = $container.find('.tell-friends'),
				$tellFriends = $quickClick.find('a'),
				$done = $container.find('.button');

			$tellFriends.click(function (e) {
				var url = this.href;

				e.preventDefault();

				FB.Connect.showPermissionDialog('publish_stream', function () {
					$.ajax({
						url: url,
						dataType: 'json',
						success: function (json) {
							$quickClick.animate({ opacity:0 }, function () {
								$quickClick
									.html(json.message)
									.animate({ opacity:1 })
									.removeAttr('href')
									.unbind();
							});
						}
					});
				});
			});

			$done.click(function () {
				GOOD.refresh(!GOOD.form.isInDialog($associate));
			});

			// TODO Create json views for associate or make it login_form w/o the other stuff
			GOOD.form.initForm($associate, {
				success: function () {
					GOOD.refresh(!GOOD.form.isInDialog($associate));
				}
			});
			GOOD.form.initForgetLink($associate);

			// TODO this is pretty redundant with the login submit handler
			// Break out any common elements into new funtions
			$associate.submit(function (e) {

				e.preventDefault();

				GOOD.form.ajaxSubmit(this, {
					success: function (success, status) {
						if (success === 1) {
							GOOD.form.confirm($associate, 'Your accounts have now been successfully connected.', function () {
								GOOD.refresh(!GOOD.form.isInDialog($associate));
							});
						} else {
							GOOD.form.enable($associate);
							GOOD.form.error($associate, 'We had trouble connecting your accounts. Please try again');
						}
					}
				});
			});
		}
	},

	refresh: function (referrer) {
		var url;

		if (referrer === true) {
			if (document.referrer) {
				url = document.referrer;
			} else {
				url = '/';
			}
		} else {
			url = location.href;
		}

		location.replace(url);
		location.href = url;
	},

	// TODO should select text instead of clearing it -- we try not to label fields from within anymore
	// Attach input clearing for focus & blur states
	clearInputOnFocus: function (selector) {
		$(selector)
			.bind(
				'focus.clearInput',
				function() {
					this.select();
					if (this.value.toLowerCase() === this.defaultValue.toLowerCase()) {
						this.value = '';
					}
				}
			)
			.bind(
				'blur.clearInput',
				function() {
					if (this.value === '' && !this.hasChanged) {
						this.value = this.defaultValue;
					}
				}
			)
			.bind(
				'keydown.clearInput',
				function(e) {
					if (e.keyCode !== 9) {
						this.hasChanged = true;
						$(this).unbind('keydown.clearInput');
					}
				}
			);
	},

	tooltip: function() {
		$("[title]").mbTooltip({  //also $([domElement]).mbTooltip  >>  in this case only children element are involved
			opacity: 0.97,        //opacity
			wait: 600,            //before show
			cssClass: "default",  //default = default
			timePerWord: 90,      //time to show in milliseconds per word
			hasArrow: false,      //if you whant a little arrow on the corner
			hasShadow: true,
			imgPath: "images/",
			ancor: "mouse",       //"parent"  you can ancor the tooltip to the mouse position or at the bottom of the element
			shadowColor: "black", //the color of the shadow
			mb_fade: 200          //the time to fade-in
		});
	}

});


//////////////////////////
// Site/DOM initialization
//////////////////////////

// Load the nav dropdown
$("ul.sf-menu").supersubs({}).superfish();

// TODO look for/clean up instances of .opener
// TODO add to $scripts for layout
// Attach jQuery UI dialogs with GOOD helper method
GOOD.dialog('a[href=/login]');
GOOD.dialog('a[href=/users/signup]');
GOOD.dialog('a[href=/forgot_password]');
GOOD.dialog('a[href=/posts/add]');
GOOD.dialog('a[href^=/posts/email_post_form]');
GOOD.dialog('#makeGood, a[href=/make_good_better]', {
	url: '/make_good_better',
	html: '<div id="goodBox" />',
	title: 'Make GOOD Better',
	width: 520
});

GOOD.dialog('#inviteFriends', {
	url: '/invitations/invite',
	html: '<div id="goodBox" />',
	height: 350,
	width: 480,
	title: 'Invite Your Friends'
});

GOOD.dialog('#howTo', {
	url: '/goodmarklet_howto',
	height: 510,
	width: 580
});


// TODO should this get added to $scripts_for_layout within newsletter form element
GOOD.clearInputOnFocus('#NewsletterSubscriberSignupForm :text');

// Submit only valid newsletter forms via AJAX
$('#NewsletterSubscriberSignupForm').submit(function (e) {
	var $form = $(this),
		$email = this['data[NewsletterSubscriber][email]'],
		$error = $('#newsletterError'),
		message = GOOD.form.validate($email, 'email');

	e.preventDefault();

	if (message !== 'valid') {
		$error.html(message);
	} else {
		$.ajax({
			type: this.method,
			url: this.action,
			data: $form.serialize(),
			dataType: 'html',
			success: function (confirmation) {

				$form
					.add($error)
					.animate({ opacity:0 }, function () {
						$form
							.html('<div class="confirmation">' + confirmation + '</div>')
							.animate({ opacity:1 });
					});
			}
		});
	}
});