jQuery(document).ready(function($) {

	// general modal-related utils, used in many places
		window.ModalUtils = {

			// constructor
			init : function() {
				window.ModalUtils = this;

				ModalUtils.attachGlobalHandlers();

				return this;
			},

			// properties/constants
			currentModalObject : null, // currently shown modal - to be able to
			// pass events to it
			defaultName : "Unknown Person",
			maxNameLength : 60,
			defaultEmail : "Enter email",
			maxEmailLength : 60,
			errorMessageContainerTemplate : "<ul></ul>",
			errorMessageItemTemplatePrefix : "<li class='error'>",
			errorMessageItemTemplateSuffix : "</li>",
			emptyNameErrorMessage : "Name cannot be empty.",
			nameTooLongErrorMessage : "Name is too long. Max 60 characters are allowed.",
			emptyEmailErrorMessage : "E-mail address cannot be empty.",
			emailTooLongErrorMessage : "E-mail address is too long. Max 60 characters are allowed.",
			invalidEmailErrorMessage : "Please provide a valid e-mail address.",
			defaultErrorFunction : function(httpRequest, textStatus, errorThrown) {
				if (httpRequest && httpRequest.status)
					return ModalUtils.handleErrors( {
						"error" : httpRequest.status
					});
				if (errorThrown)
					return ModalUtils.handleErrors( {
						"error" : errorThrown
					});
				if (textStatus)
					return ModalUtils.handleErrors( {
						"error" : textStatus
					});
			},

			// general modal window related
			retrieveHtmlTemplateById : function(templateId) {
				// checks if html template with given id is already in html
			// if not - retrieves it from server and stores in .templates div
			var template = $(".templates [_id=" + templateId + "]");
			if (template.length == 0) {
				$.ajax( {
					type : 'GET',
					url : "/template/" + templateId,
					dataType : 'html',
					async : false,
					timeout : 5000,
					success : function(result) {
						$(".templates [_id=" + templateId + "]").remove(); // just
					// to
					// be
					// sure
					$(".templates").append(result);
					template = $(".templates [_id=" + templateId + "]");
				}
				});
			}
			return template.clone(true);
		},

		createModalForAjaxUrlAndData : function(ajaxUrl, ajaxData) {
			$.ajax( {
				type : 'POST',
				url : ajaxUrl,
				dataType : 'html',
				data : ajaxData,
				success : function(result) {
					ModalUtils.createAndResizeModal(result);
				}
			});
		},

		createModalWithContent : function(modalContent, hidePrevious, showImmediately) {
			modalContent = $(modalContent);
			if (hidePrevious) {
				$('#modal-data').find(".modal").hide();
			} else {
				$('#modal-data').empty();
			}
			$('#overlay').stop().css( {
				display : 'block',
				height : document.documentElement.scrollHeight
			}).fadeTo('fast', 0.7);
			$('#modal-data').append(modalContent);
			if (showImmediately) {
				modalContent.show();
			} else {
				modalContent.fadeIn('fast');
			}

			ModalUtils.attachGeneralModalHandlers(modalContent);
		},

		resizeModal : function() {
			$('#modal-data .modal').each(function() {
				var modHeight = $(this).height();
				var modWidth = $(this).width();
				var offset = 47;
				if ($(this).hasClass('name-face')) {
					offset = 34;
				}
				var cssObj = {
					marginTop : '-' + (modHeight / 2 + offset) + 'px',
					marginLeft : '-' + (modWidth / 2 + 22) + 'px'
				};
				$(this).css(cssObj);
			});
		},

		createAndResizeModal : function(modalContent, hidePrevious, showImmediately) {

			ModalUtils.createModalWithContent(modalContent, hidePrevious, showImmediately);
			ModalUtils.resizeModal();
		},

		deleteModal : function() {
			$('#overlay').stop().fadeOut('fast');
			$('#modal-data .modal').stop().fadeOut('fast', function() {
				$(this).remove();
			});
			ModalUtils.currentModalObject = null;
		},

		showModalLoadingProgress : function() {
			// first - checking if the loading modal was already shown
			$("#modal-data #loading").remove();
			var loadingModal = ModalUtils.retrieveHtmlTemplateById("loading");
			ModalUtils.replaceIdAttributes(loadingModal);
			ModalUtils.createAndResizeModal(loadingModal, true, false);
		},
		removeModalLoadingProgress : function() {
			// first - checking if the loading modal was already shown

			$('#loading').remove();
		},
		hideCurrentModalAndShowLoadingProgress : function() {
			// first - checking if the loading modal was already shown
			$("#modal-data #loading").hide();
			var loadingModal = ModalUtils.retrieveHtmlTemplateById("loading");
			ModalUtils.replaceIdAttributes(loadingModal);
			ModalUtils.createAndResizeModal(loadingModal, true, false);
		},
		showModalPleaseWait : function() {
			// first - checking if the loading modal was already shown
			$("#modal-data #loading").remove();
			var loadingModal = ModalUtils.retrieveHtmlTemplateById("modal-please-wait");
			ModalUtils.replaceIdAttributes(loadingModal);
			ModalUtils.createAndResizeModal(loadingModal, true, false);
		},
		showSignupLoadingProgress : function() {
			// first - checking if the loading modal was already shown
			$("#modal-data #loading").remove();
			var loadingModal = ModalUtils.retrieveHtmlTemplateById("loading-signup");
			ModalUtils.replaceIdAttributes(loadingModal);
			ModalUtils.createAndResizeModal(loadingModal, true, false);
		},

		viewInsufficientPrivsModal : function() {
			// first - checking if the loading modal was already shown
			var loadingModal = ModalUtils.retrieveHtmlTemplateById("modal-insufficient-privileges");
			ModalUtils.replaceIdAttributes(loadingModal);
			ModalUtils.createAndResizeModal(loadingModal, true, true);
		},

		submitModalForm : function(modalForm, onSuccessFunction) {
			ModalUtils.submitModalFormWithAdditionalData(modalForm, onSuccessFunction, {});
		},

		submitModalFormWithAdditionalData : function(modalForm, onSuccessFunction, additionalAjaxDataHash) {

			var ajaxUrl = modalForm.attr('action');

			var ajaxData = ModalUtils.mergeHashes(ModalUtils.getFormDataAsHash(modalForm), additionalAjaxDataHash);

			$.ajax( {
				url : ajaxUrl,
				type : "POST",
				data : ajaxData,
				dataType : "json",
				success : onSuccessFunction,
				error : ModalUtils.defaultErrorFunction
			});
		},

		handleErrors : function(receivedData) {
			if (receivedData && receivedData.error) {
				if (receivedData.error == 403) {
					/* access denied - showing signin modal */
					SignIn.showSignInModal();
					return true;
				}

				if (receivedData.error == 404) {
					/* show server error modal */
					ErrorModals.showNotFoundModal();
					return true;
				}

				if (receivedData.error == 503) {
					/* show service timeout modal */
					ErrorModals.showTimeoutModal();
					return true;
				}
				if (receivedData.error == 500) {
					/* show server error modal */
					ErrorModals.showServerErrorModal();
					return true;
				}

				/* default behaviour - just close modal */
				ModalUtils.deleteModal();
			}
			return false;
		},

		focusOnInputWithDefaultValue : function(input, defaultValue) {
			input = $(input);
			input.addClass("focused");
			input.addClass("named");
			$('.reset').show();
			if(GeneralUtils.autocomplete!= null){
				GeneralUtils.autocomplete.removeNameAlert();
			}

			var value = $.trim(input.val());
			if (value == defaultValue) {
				input.attr('value', '');
				input.removeClass("default-value");
			}

		},

		blurFromInputWithDefaultValue : function(input, defaultValue) {
			input = $(input);
			// input.removeClass("focused");
			var value = $.trim(input.val());
			if (value == "" || value == defaultValue) {
				input.val(defaultValue);
				input.addClass("default-value");
			}
		},

		/* validation related */
		validateNameForInput : function(input, requiredField) {
			if (requiredField == null)
				requiredField = true; // required by default

		ModalUtils.removePreviousErrorsForInput(input);
		/* name validation only checks if name is empty */
		var name = $.trim(input.val());

		/* if not required and is empty - return positive validation */
		var emptyValue = (name == "" || name == ModalUtils.defaultName);
		if (!requiredField && emptyValue)
			return true;

		/* value required - performing thorough validation */
		return true; /* validation successful */
	},

	validateEmailForInput : function(input, requiredField) {
		if (requiredField == null)
			requiredField = true; /* required by default */

		ModalUtils.removePreviousErrorsForInput(input);
		/*
		 * email validation checks if email is empty or if it matches the email
		 * regular expression
		 */
		var email = input.val();

		// if not required and is empty - return positive validation
			var emptyValue = ($.trim(email) == "" || $.trim(email) == ModalUtils.defaultEmail);
			if (!requiredField && emptyValue)
				return true;

			/* value required - performing thorough validation */
			if (emptyValue) {
				ModalUtils.addErrorForInput(input, ModalUtils.emptyEmailErrorMessage);
				return false;
			}
			if (email.length > ModalUtils.maxEmailLength) {
				ModalUtils.addErrorForInput(input, ModalUtils.emailTooLongErrorMessage);
				return false;
			}
			if (!email.match(/^[a-zA-Z0-9][a-zA-Z0-9\-\+\._]*@([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,4}$/)) {
				ModalUtils.addErrorForInput(input, ModalUtils.invalidEmailErrorMessage);
				return false;
			}
			return true; // validation successful
		},

		isEmailValid : function(email) {
			if (email == null || email == '')
				return true;
			if (email.length > ModalUtils.maxEmailLength) {
				return false;
			}
			if (!email.match(/^[a-zA-Z0-9][a-zA-Z0-9\-\+\._]*@([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,4}$/)) {
				return false;
			}
			return true; // validation successful
		},
		isNameValid : function(name) {
			if (name.match(/[\#\%\?\*\&\=\+\\\/\<\>]/gi)) {
				return false;
			}
			return true;
		},
		removePreviousErrorsForInput : function(input) {
			var inputElementName = input.attr("name");
			input.siblings("ul[_name=" + inputElementName + "]").remove();
		},

		addErrorForInput : function(input, errorMessage) {
			var errorMessages = [];
			errorMessages.push(errorMessage);
			return ModalUtils.addErrorsForInput(input, errorMessages);
		},

		addErrorsForInput : function(input, errorMessages) {
			// creating errors container
			var inputElementName = input.attr("name");
			var errorsContainer = $(ModalUtils.errorMessageContainerTemplate);
			errorsContainer.attr("_name", inputElementName);
			$.each(errorMessages, function() {
				var message = this;
				var errorElement = ModalUtils.errorMessageItemTemplatePrefix + message + ModalUtils.errorMessageItemTemplateSuffix;
				errorsContainer.append(errorElement);
			});
			/* appending errors after input element */
			input.after(errorsContainer);
		},

		/* global handlers - attached only once */
		attachGlobalHandlers : function() {
			$(document).bind("keypress", function(e) {
				if (ModalUtils.currentModalObject && ModalUtils.currentModalObject.handleKeyPressed) {
					return ModalUtils.currentModalObject.handleKeyPressed(e.keyCode);
				} else {
					if (e.keyCode == 27) {
						ModalUtils.deleteModal();
					}
				}
			});
		},

		attachGeneralModalHandlers : function(modalContent) {
			modalContent.find("a.close_modal, .control a.close, .control a.cancel").click(function() {
				ModalUtils.deleteModal();
				return false;
			});
		},

		getAjaxJson : function(ajaxUrl, onSuccessFunction, ajaxData, onErrorFunction) {
			if (ajaxData == null)
				ajaxData = {};
			if (onErrorFunction == null)
				onErrorFunction = ModalUtils.defaultErrorFunction;
			$.ajax( {
				url : ajaxUrl,
				type : "POST",
				data : ajaxData,
				dataType : "json",
				success : onSuccessFunction,
				error : onErrorFunction
			});
		},

		/* helper methods */

		replaceIdAttributes : function(modalContainer) {
			if (modalContainer.is("[_id]")) {
				modalContainer.attr("id", modalContainer.attr("_id"));
			}
			modalContainer.find("[_id]").each(function() {
				var elem = $(this);
				elem.attr("id", elem.attr("_id"));
			});
		},

		getFormDataAsHash : function(modalContainer) {
			var ajaxData = {};
			$(modalContainer).find('input[name]').each(function() {
				ajaxData[$(this).attr('name')] = $(this).val();
			});
			return ajaxData;
		},

		isModalForm : function(form) {
			return ($(form).parents("#modal-data").length > 0);
		},

		mergeHashes : function(baseHash, additionalHash) {
			$.each(additionalHash, function(key, value) {
				baseHash[key] = value;
			});
			return baseHash;
		}
		}.init();

		/* actual modal objects */
		/* =============== TERMS & PRIVACY ============== */
		window.TermsAndPrivacy = {
			// constructor
			init : function() {
				this.attachTermsAndPrivacyHandlers();
				return this;
			},

			attachTermsAndPrivacyHandlers : function() {
				$('a.terms').click(function() {
					ModalUtils.showModalLoadingProgress();
					ModalUtils.createModalForAjaxUrlAndData("/terms/terms-of-use", {});
					return false;
				});
				$('a.privacy').click(function() {
					ModalUtils.showModalLoadingProgress();
					ModalUtils.createModalForAjaxUrlAndData("/terms/privacy", {});
					return false;
				});
			}

		}.init();

		/* =============== SIGN IN ============== */
		window.SignIn = {
			// constructor
			init : function() {
				this.attachGeneralSignInHandlers();
				return this;
			},

			showSignInModal : function() {
				var modalForm = ModalUtils.retrieveHtmlTemplateById("modal-sign_in");
				ModalUtils.replaceIdAttributes(modalForm);
				SignIn.attachModalHandlers(modalForm);
				ModalUtils.createAndResizeModal(modalForm);
			},

			showConnectModal : function() {
				var modalForm = ModalUtils.retrieveHtmlTemplateById("modal-connect");
				ModalUtils.replaceIdAttributes(modalForm);
				SignIn.attachModalHandlers(modalForm);
				ModalUtils.createAndResizeModal(modalForm);
			},
			showConnectFacebookAppModal : function() {
				var modalForm = ModalUtils.retrieveHtmlTemplateById("modal-connect-facebook");
				ModalUtils.replaceIdAttributes(modalForm);
				SignIn.attachJoinFacebookModalHandlers(modalForm);
				ModalUtils.createAndResizeModal(modalForm);
			},

			attachModalHandlers : function(modalForm) {
				modalForm.find(".facebook_connect_button").click(function() {
					ModalUtils.deleteModal();
					ModalUtils.showSignupLoadingProgress();
					FacebookUtils.checkFacebookSession();
					return false;
				});
			},
			attachJoinFacebookModalHandlers : function(modalForm) {
				modalForm.find("#facebook_join").click(function() {
					window.location.href = '/connect/facebook/';
					return false;
				});
			},

			attachGeneralSignInHandlers : function() {
				$('a.button.connect').live('click', function() {
					SignIn.showConnectModal();
					return false;
				});
				$('a.button.connect_facebook').live('click', function() {
					SignIn.showConnectFacebookAppModal();
					return false;
				});
				$('a.sign_in').live('click', function() {
					SignIn.showSignInModal();
					return false;
				});
				$('#modal-insufficient-privileges .allow_permissions').live('click', function() {
					ModalUtils.deleteModal();
					ModalUtils.showSignupLoadingProgress();
					FacebookUtils.checkFacebookSession();
					return false;
				});

			}

		}.init();

		/* =============== ERROR MODALS ============== */
		window.ErrorModals = {
			// constructor
			init : function() {
				this.attachModalHandlers();
				return this;
			},

			showTimeoutModal : function() {
				var modalForm = ModalUtils.retrieveHtmlTemplateById("modal-error-timeout");
				ModalUtils.replaceIdAttributes(modalForm);
				ErrorModals.attachModalHandlers(modalForm);
				ModalUtils.createAndResizeModal(modalForm);
			},

			showServerErrorModal : function() {
				var modalForm = ModalUtils.retrieveHtmlTemplateById("modal-error-internal");
				ModalUtils.replaceIdAttributes(modalForm);
				ErrorModals.attachModalHandlers(modalForm);
				ModalUtils.createAndResizeModal(modalForm);
			},

			showNotFoundModal : function() {
				var modalForm = ModalUtils.retrieveHtmlTemplateById("modal-error-not-found");
				ModalUtils.replaceIdAttributes(modalForm);
				ErrorModals.attachModalHandlers(modalForm);
				ModalUtils.createAndResizeModal(modalForm);
			},

			attachModalHandlers : function() {
			}

		}.init();



		/* =============== FOLLOW / UNFOLLOW ============== */
		window.FollowUnfollow = {
			/* constructor */
			init : function() {
				this.attachGeneralFollowUnfollowHandlers();
				return this;
			},

			/* constants returned from action bean that tell us what to do next */
			nextStepConstants : {
				FOLLOW_MODAL : "FOLLOW_MODAL",
				UNFOLLOW_MODAL : "UNFOLLOW_MODAL",
				REQUEST_SENT : "REQUEST_SENT",
				CLOSE_MODAL : "CLOSE_MODAL"
			},
			confirmationActionPrefixes : {
				FOLLOW_MODAL : '/follow/follow/',
				/*
				 * action to be called for following confirmation
				 */
				UNFOLLOW_MODAL : '/follow/unfollow/'
			/*
			 * action to be called for unfollowing confirmation
			 */
			},
			modalTemplateIds : {
				FOLLOW_MODAL : "modal-follow",
				UNFOLLOW_MODAL : "modal-unfollow"
			},

			handleFollowUnfollowRequestUrl : function(url) {

				ModalUtils.showModalLoadingProgress();
				ModalUtils.getAjaxJson(url, function(data) {
					if (ModalUtils.handleErrors(data))
						return false;

					var nextStep = data.nextStep;
					var modalForm = null;
					switch (nextStep) {
					case FollowUnfollow.nextStepConstants.FOLLOW_MODAL:
					case FollowUnfollow.nextStepConstants.UNFOLLOW_MODAL:
						modalForm = ModalUtils.retrieveHtmlTemplateById(FollowUnfollow.modalTemplateIds[nextStep]);
						FollowUnfollow.fillFormWithData(modalForm, data);
						ModalUtils.replaceIdAttributes(modalForm);
						FollowUnfollow.attachModalHandlers(modalForm);
						ModalUtils.createAndResizeModal(modalForm);
						break;
					case FollowUnfollow.nextStepConstants.REQUEST_SENT:
						modalForm = ModalUtils.retrieveHtmlTemplateById("request-sent");
						ModalUtils.replaceIdAttributes(modalForm);
						ModalUtils.createAndResizeModal(modalForm);
						break;
					case FollowUnfollow.nextStepConstants.CLOSE_MODAL:
						ModalUtils.deleteModal();
						window.location.reload();
						break;
					}
				});
			},

			fillFormWithData : function(modalForm, data) {
				var nextStep = data.nextStep;
				var actionUrl = FollowUnfollow.confirmationActionPrefixes[nextStep] + data.userToFollow.id;
				modalForm.attr("action", actionUrl);
				modalForm.find(".control a.save").attr("href", actionUrl);
				var header = modalForm.find("h1");
				/*
				 * only first name should be shown on follow/unfollow header -
				 * dividing screen name into tokens and showing only first of
				 * them
				 */

				var screenName = "";
				if (data.userToFollow.namePrivacy == "Private" && (data.userToFollow.creatorId == null || data.userToFollow.creatorId != data.signedInUserId)) {
					screenName = "this person";
				} else {
					screenName = $.trim(data.viewName);
					if (screenName) {
						screenName = screenName.split(" ")[0];
					}
				}

				if (screenName.length > 25) {
					screenName = screenName.substring(0, 25) + '...';
				}

				header.text(header.text().replace("__SCREEN_NAME__", screenName));
				modalForm.find(".photo img").attr("src", data.bigMugshotUrl);
			},

			attachModalHandlers : function(modalForm) {
				/* submitting request */
				modalForm.filter("#modal-follow, #modal-unfollow").find(".control a.save").click(function() {
					FollowUnfollow.handleFollowUnfollowRequestUrl($(this).attr("href"));
					return false;
				});
			},

			attachGeneralFollowUnfollowHandlers : function() {
				$('.follow a, .unfollow a').click(function() {
					FollowUnfollow.handleFollowUnfollowRequestUrl($(this).attr("_href"));
					return false;
				});
			}

		}.init();

	});
