AuthJobs = {};

AuthJobs.Global = {
	
	isiOS: navigator.userAgent.match(/like Mac OS X/i),
		
	// Initialise, called on page load
	init: function() {
		
		$('li.dropdown>a,li.dropdown>span').click(function(e){
			e.stopPropagation();
			$(this).next('ul').toggle();
		});
		$('body').click(function(){
			$('li.dropdown ul').hide();
		});
		
		// Handle mobile Safari zoom bug (http://adactio.com/journal/4470/)
		if (navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i)) {
		  var viewportmeta = $("meta[name='viewport']");
		  if (viewportmeta) {
		    viewportmeta.attr("content", "width=device-width, minimum-scale=1.0, maximum-scale=1.0");
		    $("body").bind('gesturestart', function() {
		      viewportmeta.attr("content", "width=device-width, minimum-scale=0.25, maximum-scale=1.6");
		    });
		  }
		}
			
		// Add disappearing hint (value comes from title attrib on element itself)
		$('input[title!=""], textarea[title!=""]').hint();
		
		// Custom effect for modal display/hide
		$.tools.overlay.addEffect('panelSlide',
			function(done) {
				overlay = this.getOverlay();
				h = overlay.outerHeight();	
				var animateProps = {
					top: 0//'+=' + h
				};
				
				if (window.innerWidth < 1040) {
					
					$.scrollTo(0, {
						duration: 250,
						axis: 'y',
						easing: 'easeInOutQuad',
						onAfter: function() {
							overlay.css('position', 'fixed');
							overlay.css('top', '-' + h + 'px');
							overlay.show().animate(animateProps, 400, 'easeInQuint', done);
						}
					});
					
				}
				
				else {
					overlay.css('position', 'fixed');
					overlay.css('top', '-' + h + 'px');
					overlay.show().animate(animateProps, 400, 'easeInQuint', done);
				}
				

			},
			function(done) {
				overlay = this.getOverlay();
				h = overlay.outerHeight();
				var animateProps = {
					top: '-=' + h
				};
				overlay.animate(animateProps, 400, 'easeOutQuad', function() {
					$(this).hide();
					done.call();
				});
			}
		);
		
		AuthJobs.Global.enhanceAccessibility();
		
		// One touch to select input values
		$("input.touchselect").focus(function() {
			$(this).select();
		});
		
		// Toggle to reveal email subscribe form
		$("#channels .email a").click(function(e) {			
			$("#newsletter").slideToggle();
			e.preventDefault();
		});
		
		
		// Add toggle-closed for banner
		$('.banner .close').click(function(e){
			e.stopPropagation();
			e.preventDefault();
			$.cookie('hide-banner-ios-app', true, {
				expires: 2592000, 
				domain: '.' + document.domain
			});
			$('.banner').slideUp();
		});
	},
	
	// Accessibility enhancements (WAI-ARIA)
	enhanceAccessibility: function() {
		
		// Add roles to page areas		
		$("#main").attr("role", "main");
		$("aside").attr("role", "complementary");
		
		// Navigation
		$("#sitenav").attr("role", "navigation").find("ul, li").attr("role", "presentation");
		
		
	},
	
	// Handle positioning of error messages for form validation failures
	errorPlacement: function(error, element) {
		
		if (element.hasClass('adjacent')) {
			if (element.siblings('p.example').length != 0) {
				element.siblings('p.example:first').before(error);
			}
			else {
				error.appendTo(element.parent()); 
			}
		}
		
		else if (element.attr('type') == "checkbox") {
			element.siblings("label:last").after(error);
		}
		
		else if (element.attr('name') == 'job_type') {			
			$("#jobtype .options").after(error).addClass('error');
		}
		
		else if (element.attr('id') == 'description') {
			$('span#description_parent').after(error);
		}
		
		else if (element.attr('id') == 'twitter_username') {
			$("#companytwitter").append(error);
		}
		
		else if (element.hasClass("stylish")) {
			$(element).next('.newListSelected').after(error).addClass('error');
		} 
		
		else if (element.attr('id') == 'ccnumber') {
			$(".ccnumber-img").after(error);
		}
		
		else if (element.parents('li:first').attr("id") == 'cardinfo') {
			// Do nothing (labels not required and can't fit them in anyway)
		}
		
		else {
			element.after(error);
		}
		
	},
	
	// Add indication of invalid user input
	highlightFieldError: function(element, errorClass) {	
		var jq = $(element);
		if (element.id == 'description') {
			jq = jq.siblings('span');
		}
			
		jq.addClass(errorClass);
		jq.nextAll('.wordcount, .charactercount').children('strong').css('color', '#B30000');	
				
	},
	
	// Remove the indication of invalid user input
	unhighlightFieldError: function(element, errorClass) {
		$(element).removeClass(errorClass);
		$(element).nextAll('.wordcount, .charactercount').children('strong').css('color', '#222222');
		$(element).parent().find('label.error').remove();
	},
	
	// Count the number of words in a text field, and highlight if over the limit	
	countWords: function(element) {			
		words = (element.value.match(/([^\s\.\?]+)/g) || []).length;
		$(element).nextAll('.wordcount').children('strong').html(words);			
	},
	
	tinyMCEWordLimitUpdate: function(editor) {
		
		words = AuthJobs.Global.countWordsTinyMCE(editor);
		
		original = editor.getElement();
		
		$(original).parents('div:first').find('.wordcount').children('strong').html(words);
		
		// Validate
		if (words > $(original).rules().maxWordsTinyMCE) {
			AuthJobs.Global.highlightFieldError($(original), 'error');
			AuthJobs.Global.highlightFieldError($('span.mceEditor'), 'error');
		}
		else {
			AuthJobs.Global.unhighlightFieldError($(original), 'error');
			AuthJobs.Global.unhighlightFieldError($('span.mceEditor'), 'error');
		}
		
	},
	
	// Count the number of words in a TinyMCE field
	countWordsTinyMCE: function(editor) {				
		
		text = editor.getContent();
		text = text.replace(/<[^>]+>/ig,""); // strip markup
		text = text.replace(/&nbsp;/g,""); // collapse html whitespace
		text = text.replace(/\n/g," "); // remove newlines
		text = text.replace(/\s+/g," "); // collapse string whitespace
		text = $.trim(text);
		words = text.split(' ').length;
		if (text == "") words = 0;		
		return words;				
	},
	
	// Handle submission of an invalid form
	invalidHandler: function(event, validator) {
		
		var firstError = validator.errorList[0].element;
		
		// Fetch the stylish select custom HTML so we don't try to scroll to a hidden element
		if ($(firstError).hasClass('stylish')) {
			firstError = $(firstError).next('.newListSelected').get(0);
		}
		
		$.scrollTo(firstError, {
			duration: 250,
			axis: 'y',
			offset: { left: 0, top: -20 },
	 		easing: 'easeInOutQuad'
		});
				
	},
	
	supportsGeolocation: function() {
		return !!navigator.geolocation;
	},
	
	getLocation: function(callback) {
		navigator.geolocation.getCurrentPosition(callback, this.handleGeoError, { enableHighAccuracy: false, timeout: 10000, maximumAge: 60 * 60 * 1000 });
		
		// Display loader
		$("#geo_loader").show();
	},
	
	handleGeoError: function(err) {
		
		// Cancel loader
		$("#geo_loader").hide();
		
		alert(err);
		if (err.code == 1){
			// user said no!
		}
		else if (err.code == 2){
			// no response
		}
		else if (err.code == 3){
			// timeout
		}
		else{
			// whoa
		}
	},
	
	selectElementText: function(target) {
		var text = $(target).get(0);
		var range,selection;
		if ($.browser.msie) {
			range = document.body.createTextRange();
			range.moveToElementText(text);
			range.select();
		} else if ($.browser.mozilla || $.browser.opera) {
			selection = window.getSelection();
			range = document.createRange();
			range.selectNodeContents(text);
			selection.removeAllRanges();
			selection.addRange(range);
		} else if ($.browser.safari) {
			selection = window.getSelection();
			selection.setBaseAndExtent(text, 0, text, 1);
		}
	}
	
};

AuthJobs.Filter = {
	
	// Filter parameters
	search: "",
	location: "",
	onlyremote: "0", // default "false"
	category: "0", // default "all jobs"
	types: "1,2,3,4", // default all types
	
	type_lookup: {
		"1": "full-time",
		"2": "freelance",
		"3": "contract",
		"4": "internship"
	},
	
	// Number of listings to display per "page"
	page_size: 50,
	
	// Initial pagination values
	initial_page_count: 0,	
	initial_page: 0,
	initial_total_count: 0,	
	
	// Initial map marker position values
	map_marker_x: 0,
	map_marker_y: 0,
		
	// Resetting flag (don't update results on each criteria set reset programatically)
	resetting: false,
	
	// Initialising flag (used when loading page with a filtering parameters hash)
	initialising: true,
	
	// The limit at which we switch from showing job type exceptions in status display to just a listing of them
	exceptionLimit: 1,
	
	// Initalise, called on page load
	init: function() {
				
		// History support
		$.history.init(function(hash) {
			
			if (hash == "") {
				// try loading from cookie
				hash = $.cookie('filter_values') || "";
			}
			
			// restore past filtering settings
			if (hash != "") {
				// load filter from hash
				
				if (AuthJobs.Filter.initialising) {
				
					var parameters = hash.split("&");
					
					// reset missing parameters to prevent cookie overriding
					if (!parameters['types']) {
						parameters['types'] = '1,2,3,4';
					}
					
					$.each(['location','category','search','onlyremote'], function(i,e) {
						if (!parameters[e]) parameters[e] = '';
					});
					
					$.each(parameters, function(index, element) {
						var property = element.substring(0, element.indexOf("="));
						var value = urldecode(element.substring(element.indexOf("=") + 1));
					
						switch(property) {
							case "types":
								AuthJobs.Filter.updateTypes(value);
								AuthJobs.Filter.types = value;
								break;
							case "category":							
								AuthJobs.Filter.updateCategory(value);
								AuthJobs.Filter.category = value;
								break;
							case "location":
								AuthJobs.Filter.updateLocation(value);	
								AuthJobs.Filter.location = value;
								break;
							case "onlyremote":
								AuthJobs.Filter.updateOnlyRemote(value);
								AuthJobs.Filter.onlyremote = value;
								break;
							case "search":
								AuthJobs.Filter.updateSearch(value);
								AuthJobs.Filter.search = value;
								break;
						}
	
					});
					
					AuthJobs.Filter.execute();
					AuthJobs.Filter.initialising = false;
					
				}			
				
			}	
			
			else {
				
				AuthJobs.Filter.initialising = false;
			}		

		}, { unescape: ",/=&" });
		
		// Insert search input clear buttons
		$("input[name='search']").after("<a href='#' class='clear'>x</a>");
		
		// Make search input clear link visible if value present in search
		if (AuthJobs.Filter.search != "") {
			$("#search .clear, #mobile-search .clear").addClass("activated");
		}
		
		// Bind handler to search input clear buttons
		$('#search .clear, #mobile-search .clear').click(function() {
			$(this).removeClass("activated");
			AuthJobs.Filter.dismissPulldown("mobile-search");
			if (AuthJobs.Filter.search != "") {
				$("input[name='search']").val("");
				AuthJobs.Filter.search = "";
				AuthJobs.Filter.updateHistory();
				AuthJobs.Filter.execute();
			}
			return false;
		});
		
		// Remove submit button & pagination (JS functionality supercedes both)
		$("#filtering input[type='submit'], .pages").fadeOut(200);
		
		// Enhance pulldowns
		$("#upper > ul > li:not(:last) > a").click(function() {
			
			var $link = $(this);
			var id = $link.parent("li").attr("id");
			
			$link.parent("li").siblings("li:not(#search)").each(function() {
				AuthJobs.Filter.dismissPulldown($(this).attr("id"));
			});
			
			if (!$link.next(".pulldown").is(":visible")) {
				
				$link.parent("li").addClass("open");

				$link.next(".pulldown").fadeIn(200, function() {
					
					$(document).bind('click.pulldown', function() { 						
						AuthJobs.Filter.dismissPulldown(id); 
					});
					
					$(document).bind('keyup.pulldown', function(e) {
						if ((e.keyCode || e.which) == 27) {
							AuthJobs.Filter.dismissPulldown(id);
						}					
					});					
					
				});
				
			}
			
			else {
				AuthJobs.Filter.dismissPulldown(id);
			}						
			
			return false;
			
		});
		
		$("#upper .mobile .search > a").click(function() {
			
			AuthJobs.Filter.dismissPulldown("status"); 
			
			var $link = $(this);
			
			$link.parent(".search").addClass("open");
			
			$link.next(".pulldown").attr("droid", (new Date().getTime())).fadeIn(200, function() {
				
				$(document).bind('click.pulldown touchstart.pulldown', function() { 						
					AuthJobs.Filter.dismissPulldown("mobile-search"); 
				});
				
				$(document).bind('keyup.pulldown', function(e) {
					if ((e.keyCode || e.which) == 27) {
						AuthJobs.Filter.dismissPulldown("mobile-search");
					}					
				});				
				
			});
			
			return false;
			
		});
		
		$("#status .refine > a").click(function() {
			
			AuthJobs.Filter.dismissPulldown("mobile-search"); 
			
			var $link = $(this);
			
			$link.parent(".refine").addClass("open");
			
			$link.next(".pulldown").attr("droid", (new Date().getTime())).fadeIn(200, function() {
				
				$(document).bind('click.pulldown touchstart.pulldown', function() { 						
					AuthJobs.Filter.dismissPulldown("status"); 
				});
				
				$(document).bind('keyup.pulldown', function(e) {
					if ((e.keyCode || e.which) == 27) {
						AuthJobs.Filter.dismissPulldown("status");
					}					
				});				
				
			});						

			return false;
		});
		
		// Prevent touches on mobile flyout labels propagating
		$('.refine label').bind('click touchstart', function(e) { e.stopPropagation(); });
		
		// Prevent touches on pulldowns from doing anything
		$(".pulldown").bind('click touchstart', function(e) { e.stopPropagation(); });
		
		// Insert location clear button 
		$("#locations .wrap").append("<a href='#' class='clear'>x</a>");
		
		// Make location input clear link visible if value present in location
		if (AuthJobs.Filter.location != "") {
			$("#locations .clear").addClass("activated");
		}
		
		// Location clear button handler
		$("#location").keyup(function() {
			if ($(this).val() != "") {
				$(this).next('.clear').addClass("activated");
			}
			else {
				$(this).next('.clear').removeClass("activated");
			}
		});
		
		$("#locations .clear").click(function(e) {			
			$(this).removeClass("activated");			
			$("#location").val("");
			e.preventDefault();
		});
		
		// Replace location pulldown button 
		$("#locations .pulldown .controls").empty().append("<a href='#' class='save button'>Save</a> <a href='#' class='cancel button minor'>Cancel</a>");		
	
		// Bind cancel button in location pulldown
		$("#locations .pulldown .cancel").click(function(e) {
			AuthJobs.Filter.dismissPulldown("locations");
			e.preventDefault();
		});
		
		// Replace mobile refine pulldown button
		$("#status .refine .pulldown .controls").empty().append("<a href='#' class='save button'>Save</a> <a href='#' class='cancel button minor'>Cancel</a> <a href='#' class='resetAll button minor'>Reset</a>");		
		
		// Bind cancel and reset buttons in refine pulldown
		$("#status .refine .pulldown .minor").click(function(e) {
			AuthJobs.Filter.dismissPulldown("status");
			e.preventDefault();
		});
				
		// Search reset link
		$(".resetAll").click(function(e) {
			AuthJobs.Filter.resetting = true;
			$("#categories .pulldown a:first").click();
			$("#mobile-duration, #mobile-category").val(0);
			$("input[name='search']").val("").blur();
			AuthJobs.Filter.search = "";
			$("#search .clear, #mobile-search .clear").removeClass("activated");
			$("#types input[type='checkbox']").each(function() { 
				if (!this.checked) {
					$(this).click().trigger("change");
				}
			});
			$("#location").val("");
			$(".mobile .location").removeClass("set").unbind(".unlocate").unbind(".locate").bind("click.locate", function(e) {
				AuthJobs.Filter.locate();
				e.preventDefault();
			});
			AuthJobs.Filter.location = "";
			AuthJobs.Filter.onlyremote = "0";
			AuthJobs.Filter.updateOnlyRemote(AuthJobs.Filter.onlyremote);
			$("#status").removeClass('active');
			AuthJobs.Filter.resetting = false;			
			$.history.load("");
			$.cookie('filter_values', "", {
				expires: 90, 
				domain: '.' + document.domain
			});	
			AuthJobs.Filter.execute();			
			e.preventDefault();
		});
	
		
		
		// Prevent the HTML form from being submitted (everything handled on change by jquery)
		$("#filtering").submit(function() {
			return false;
		});		

		
		// Job type selection
		$("#types input[type='checkbox']").change(function() {	
			AuthJobs.Filter.types = "";
			$(".refine .duration input[type='checkbox']").each(function() { this.checked = false; });
			$("#types input[type='checkbox']").each(function() {
				if (this.checked) {
					AuthJobs.Filter.types += $(this).data("val") + ",";
					$(".refine .duration input[data-val='" + $(this).data("val") + "']").get(0).checked = true;
				}
			});
			AuthJobs.Filter.types = AuthJobs.Filter.types.substring(0, AuthJobs.Filter.types.length-1);
			AuthJobs.Filter.updateHistory();
			AuthJobs.Filter.execute();
		});
		
		// Job category selection
		$("#categories .pulldown a").click(function(e) {
			AuthJobs.Filter.category = $(this).data("val");
			AuthJobs.Filter.updateCategory(AuthJobs.Filter.category);
			AuthJobs.Filter.dismissPulldown("categories");
			AuthJobs.Filter.updateHistory();
			AuthJobs.Filter.execute();
			e.preventDefault();
		});
		
		// Mobile refine flyout save button
		$(".refine .controls .save").click(function(e) {			
			AuthJobs.Filter.types = "";
			$("#types input[type='checkbox']").each(function() { this.checked = false; });
			$(".refine .duration input[type='checkbox']").each(function() {
				if (this.checked) {
					AuthJobs.Filter.types += $(this).data("val") + ",";
					$("#types input[data-val='" + $(this).data("val") + "']").get(0).checked = true;
				}
			});
			AuthJobs.Filter.types = AuthJobs.Filter.types.substring(0, AuthJobs.Filter.types.length-1);			
			AuthJobs.Filter.category = $("#mobile-category").val();
			AuthJobs.Filter.updateCategory(AuthJobs.Filter.category);			
			if ($("#mobile-onlyremote").get(0).checked) {
				AuthJobs.Filter.onlyremote = "1";
				$("#onlyremote").get(0).checked = true;
				$("#locations .telecommute").css('display', 'inline');
			}
			else {
				AuthJobs.Filter.onlyremote = "0";
				$("#onlyremote").get(0).checked = false;				
				$("#locations .telecommute").hide('display', 'none');
			}
			$("#mobile-onlyremote").get(0).checked ? $("#locations .telecommute").show() : $("#locations .telecommute").hide();			
			AuthJobs.Filter.dismissPulldown("status");
			AuthJobs.Filter.updateHistory();
			AuthJobs.Filter.execute();
			e.preventDefault();
		});
				
		// Location selection from save button click
		$("#locations .pulldown .save.button").click(function(e) {			
			AuthJobs.Filter.location = $("#location").val();
			if ($("#onlyremote").get(0).checked) {
				AuthJobs.Filter.onlyremote = "1";
				$("#locations .telecommute").show();
				$("#mobile-onlyremote").get(0).checked = true;
			}
			else {
				AuthJobs.Filter.onlyremote = "0";		
				$("#locations .telecommute").hide();
				$("#mobile-onlyremote").get(0).checked = false;				
			} 
			AuthJobs.Filter.dismissPulldown("locations");
			AuthJobs.Filter.updateHistory();
			AuthJobs.Filter.execute();
			
			e.preventDefault();
		});
		
		// Location selection from location input enter keypress
		$("#location").keyup(function(e) {
			if ((e.keyCode || e.which) == 13) {
				$("#locations .pulldown .save.button").trigger('click');
			}
		});
		
		// Search field
		$("#search input[name='search']").keyup(function() {
			if ($(this).val() != "") {
				$("#search .clear, #mobile-search .clear").addClass("activated");
			}
			else {
				$("#search .clear, #mobile-search .clear").removeClass("activated");
			}
		}).delayedObserver(function() {
			AuthJobs.Filter.search = this.val();
			AuthJobs.Filter.updateHistory();
			AuthJobs.Filter.execute();
		}, 0.2);	
		
		// Search submit from mobile search input enter keypress
		$(".mobile input[name='search']").keyup(function(e) {
			if ($(this).val() != "") {
				$("#search .clear, #mobile-search .clear").addClass("activated");
			}
			else {
				$("#search .clear, #mobile-search .clear").removeClass("activated");
			}
			if ((e.keyCode || e.which) == 13) {
				$(this).blur();
				AuthJobs.Filter.dismissPulldown("mobile-search"); 
				AuthJobs.Filter.search = $(this).val();
				AuthJobs.Filter.updateHistory();
				AuthJobs.Filter.execute();
			}	
		});
		
		// Highlight selected items in pulldown menus
		$(".pulldown ul li a").click(function(e) {
			$(this).parents(".pulldown").find("li").removeClass("selected");
			$(this).parent("li").addClass("selected");
			e.preventDefault();
		});		
		
		// Use current location button (shown at low res for mobile devices)
		$(".mobile .location").bind("click.locate", function(e) {					
			AuthJobs.Filter.locate();
			e.preventDefault();
		});
		
		// Fetch initial pagination values
		var $listings = $("ul#listings");
		AuthJobs.Filter.initial_page_count = $listings.data('page-count');
		AuthJobs.Filter.initial_page = $listings.data('page');
		AuthJobs.Filter.initial_total_count = $listings.data('total-count');
						
		// Load JS pagination
		AuthJobs.Filter.updateMoreLink(AuthJobs.Filter.initial_page_count, 
																	 AuthJobs.Filter.initial_page, 
																	 AuthJobs.Filter.initial_total_count);
		
	},
	
	// Locate the visitor using HTML5 geolocation
	locate: function() {
		
		var $button = $(".mobile .location");
		$button.unbind(".unlocate");
		
		if (navigator.geolocation) {				

			$button.addClass("loading");
			navigator.geolocation.getCurrentPosition(function(position) {
				
				AuthJobs.Filter.location = "ll_" + position.coords.latitude + "," + position.coords.longitude;
				AuthJobs.Filter.updateHistory();
				AuthJobs.Filter.execute();
				
				$button.toggleClass("loading set").unbind(".locate").bind("click.unlocate", function(e) {
					AuthJobs.Filter.unlocate();
					e.preventDefault();
				});
				
			}, function(error) {
				
				$button.removeClass("loading");
				alert("Sorry, we couldn't get your location.");
				
			});
			
		}
		
		else {
			alert("Sorry, your browser doesn't support geolocation.");
		}
		
	},
	
	// Forget the location setting
	unlocate: function() {				
		$(".mobile .location").unbind(".locate").bind("click.locate", function(e) {
			AuthJobs.Filter.locate();
			e.preventDefault();
		}).removeClass("set");
		AuthJobs.Filter.location = "";
		AuthJobs.Filter.updateHistory();
		AuthJobs.Filter.execute();
	},
	
	// Update the selected job category in the UI
	updateCategory: function(value) {		
		
		var cat;
		
		if (value == "0" || value == "") {
			cat = $("#categories .pulldown a[data-val='0']");
			$("#categories > a").addClass("default").html(cat.html() + " <span>(choose a category&hellip;)</span>");
		}
		else {
			cat = $("#categories .pulldown a[data-val='" + value + "']");
			$("#categories > a").removeClass("default").html($.trim(cat.html().substring(0, cat.html().indexOf("<span>"))));
		}
		
		$("#categories .pulldown li").removeClass("selected");
		cat.parent("li").addClass("selected");
		
	},
	

	// Update the selected location in the UI
	updateLocation: function() {	
		
		var locationTip = $("#locations .unknown").tooltip({
			tip: "#locations .tip",
			effect: "slide",
			relative: true,
			offset: [10, 0]
		});
		
		if (AuthJobs.Filter.location == "")	{
			$("#locations .unknown").fadeOut(175);
			locationTip.hide();
			$("#locations .marker").removeClass("set").fadeOut(175);
		}
		
		else {
			
			$("#location").val(unescape(AuthJobs.Filter.location));
			
			$(".mobile .location").addClass("set").unbind(".locate").bind("click.unlocate", function(e) {
				AuthJobs.Filter.unlocate();
				e.preventDefault();
			});

			if (AuthJobs.Filter.map_marker_x != 0 && AuthJobs.Filter.map_marker_y != 0) {

				$("#locations .marker").css({
					left: AuthJobs.Filter.map_marker_x,
					top: AuthJobs.Filter.map_marker_y
				}).fadeIn(200, function() {
					$(this).addClass("set");
				});		

				$("#locations .unknown").hide();
				locationTip.hide();

			}

			else {

				$("#locations .marker").fadeOut(175, function() {
					$(this).removeClass("set");				

					if (AuthJobs.Filter.location != "") {

						$("#locations .unknown").fadeIn(175, function() {
							locationTip.show();
							setTimeout(function() {	locationTip.hide(); }, 3000);
						});				

					}
				});
			}		
			
		}		

	},
	
	// Update the only remote working jobs option in the UI
	updateOnlyRemote: function(value) {
		
		if (value == "1") {
			$("input[name='onlyremote']").each(function() {
				$(this).get(0).checked = true;			
			});
			$("#locations .telecommute").css('display', 'inline');
		}
		
		else {
			$("input[name='onlyremote']").each(function() {
				$(this).get(0).checked = false;			
			});
			$("#locations .telecommute").css('display', 'none');
		}
		
	},
	
	// Update the selected job types in the UI
	updateTypes: function(values) {		
		
		$("#types input[type='checkbox'], .refine .duration input[type='checkbox']").each(function(index, checkbox) {
			checkbox.checked = false;
			$(checkbox).removeAttr("checked");
		});

		$.each(values.split(","), function(index, value) {			
			
			// Full size layout checkboxes
			var type = $("#types input[data-val='" + value + "']");
			if (type.length) {
				type.attr("checked", "checked").get(0).checked = true;
			}
			
			// Responsive layout checkboxes
			type = $(".refine .duration input[data-val='" + value + "']");
			if (type.length) {
				type.attr("checked", "checked").get(0).checked = true;
			}			
			
		});
		
	},
	
	// Update the search string in the UI
	updateSearch: function(value) {
		$("input[name='search']").val(unescape(value)).removeClass("blur");
		$("#search .clear, #mobile-search .clear").addClass("activated");
	},
	
	// Hide the pulldown menus
	dismissPulldown: function(id) {		
		var pulldown = $("#" + id + " .pulldown");		
		if(pulldown.is(':visible')) {
			$("#" + id).removeClass("open");
			pulldown.fadeOut(200);
			$(document).unbind('.pulldown');
		}
	},
	
	// Push to query string for history support
	updateHistory: function() {		
		
		// Bail out if we're performing a criteria reset (history will be updated ONCE manually in that case)
		if (AuthJobs.Filter.resetting) return;
		
		var hash = "";

		if (!AuthJobs.Filter.defaultTypes()) { hash += "types=" + AuthJobs.Filter.types + "&"; }		
		if (!AuthJobs.Filter.defaultCategory()) { hash += "category=" + AuthJobs.Filter.category + "&"; }							 
		if (!AuthJobs.Filter.defaultLocation()) {	hash += "location=" + AuthJobs.Filter.location + "&";	}
		if (!AuthJobs.Filter.defaultOnlyRemote()) { hash += "onlyremote=" + AuthJobs.Filter.onlyremote + "&";	}		
		if (!AuthJobs.Filter.defaultSearch()) { hash += "search=" + AuthJobs.Filter.search + "&";	}
		
		// Trim trailing "&"
		hash = hash.substring(0, hash.length - 1);							 
				 
		$.history.load(hash);
		$.cookie('filter_values', hash, {
			expires: 90,
			domain: '.' + document.domain
		});	
	},	
	
	// Trigger update of job listings from the server
	execute: function(updated, page, callback) {
				
		// Bail out if we're performing a criteria reset (results will be updated ONCE manually in that case)
		if (AuthJobs.Filter.resetting) return;
		
		// The page number to request
		page = (page == undefined) ? 1 : page;
		
		// Have filtering settings been updated (assume we're paging/reloading browser if not)
		updated = (updated == undefined) ? true : updated;
		
		// Filter GET request params
		var data = {
			page: page,
			page_size: AuthJobs.Filter.page_size,
			search: AuthJobs.Filter.search,
			category: AuthJobs.Filter.category,
			location: AuthJobs.Filter.location,
			onlyremote: AuthJobs.Filter.onlyremote,
			types: AuthJobs.Filter.types
		};
		
		if (updated) {
			// Fade out and remove current listings	
			$("#more").remove();
			$("#noresults").hide();
			$("#listings, #more").fadeTo(200, 0.3, function() {
				if ($("#loading").length == 0) {
					$("#listings").before("<div id='loading'><span>Loading results ...</span></div>");
					$("#loading").fadeTo(200, 1);
				}
				
				AuthJobs.Filter.updateStatus();
				
				AuthJobs.Filter.requestListings(data, updated, callback);
				
			});
		}
		
		else {			
			AuthJobs.Filter.requestListings(data, updated, callback);
		}
		
	},
	
	requestListings: function(data, updated, callback) {		
		
		$.get("/filter.php", data, function(result, status, xhr) {
			
			if (updated) {
				$("#listings").empty();
			}			
			else {
				// Mark the "fold" (the last listing from the previous "page")
				$("#listings li").removeClass("fold").filter(":last").addClass("fold");
			}
			
			// Store map marker location co-ordinates and update marker pin location
			AuthJobs.Filter.map_marker_x = result.location.x;
			AuthJobs.Filter.map_marker_y = result.location.y;			
			AuthJobs.Filter.updateLocation();
			
			// Update location co-ordinates with neater title if available 
			if (result.location.name != undefined) {
				$("#status .location").html("near <strong>" + result.location.name + "</strong>");
			}
			
			if (result.pagination.total_count == 0) {
				$("#listings").empty();
				$("#noresults").fadeTo(300, 1);
			}
			
			else {
				
				$("#noresults").fadeTo(200, 0);
				
				$.each(result.listings, function(index, listing) {

					// Build listing markup
					var markup = "<li class='" + listing.employment.toLowerCase() + "'>";
							markup += "<a href='" + listing.url_relative + "'>";
							markup += "<span>";
							
							markup += "<img src='" + listing.company_logo + "' width='32px' height='32px' alt='' />";
							
							markup += "<div class='role'>";
							markup += "<h3>" + listing.title + "</h3>";							
							markup += "<h4>" + listing.company + "</h4>";
							if (listing.company_tagline != "") {
								markup += "<span>" + listing.company_tagline + "</span>";
							}
							markup += "</div>"; // end .role
							
							markup += "<span class='location'>" + listing.loc + "</span>";
							
							markup += "<div class='meta'>";
							markup += "<strong class='type'>" + listing.employment + "</strong>";							
							if (listing.is_new) {
								markup += "<span class='new'>New</span>";
							}
							else {
								markup += "<span class='posted'>" + listing.post_date_relative + "</span>";
							}
							markup += "</div>"; // end .meta							
							
							markup += "</span></a></li>";

					// Insert listing
					$("#listings").append(markup);

				});
				
				// Fade listings back in if we faded out and emptied previously for a filter setting update
				if (updated) {				
					$("#listings").fadeTo(500, 1, function() {
						if (callback != undefined) {
							callback();
						}	
					});				
				}
				
				// If loading next "page"
				else {					
					if (callback != undefined) {
						callback();
					}					
				}							
				
			}
			
			// Update the load more listings link
			AuthJobs.Filter.updateMoreLink(result.pagination.page_count, result.pagination.page, result.pagination.total_count);				
						
			$("#loading").fadeTo(200, 0, function() {
				$(this).remove();	
			});
			
		});
		
	},

	
	// Conditionally insert/update next "page" link
	updateMoreLink: function(page_count, page, total_count) {
			
		// If we have more pages
		if ((page_count - page) > 0) {			
			
			var next_page = page + 1;
			
			// Calculate the number of listings on the next page
			var next_page_size = AuthJobs.Filter.page_size;
			var remaining = total_count - (page * AuthJobs.Filter.page_size);
			if (remaining < AuthJobs.Filter.page_size) {
				next_page_size = remaining;
			}
			
			// Build load more link markup
			var more = "<a href='#' data-page='" + next_page + "'>";
					more += "Load the next <span class='next_size'>" + next_page_size + "</span> listings ";
					more += "<span class='remaining'>(" + remaining + " more in total)</span></a>";			
			
			// Insert load more link if not already present
			if ($("#more").size() == 0) {						
				
				$("#listings").after("<div id='more'>" + more + "</div>");
								
				// Android hack			
				$("#more").attr("droid", (new Date().getTime()));
			}
			
			// Update more link if it's there already
			else {
				$("#more").html(more);
			}
			
			$("#more a").unbind('click').click(function() {
				
				// Display loading message in more link
				$("#more").html("<span class='loading'>Loading results ...</span>");
				
				AuthJobs.Filter.execute(false, next_page, function() {
					//Scroll to top of next "page"
					$.scrollTo("#listings .fold", {
						duration: 500,
						axis: 'y',
				 		easing: 'easeInOutQuad'
					});
				});
				$(this).blur();
				return false;
			});
			
		}
		
		// If no more pages
		else {			
			$("#more").remove();			
		}
		
	},
	
	
	/*
	 * Status area functionality */	
	
	// Update the status bar
	updateStatus: function() {
		
		if (AuthJobs.Filter.defaults()) {
			//$("#status").slideUp(250, updateCriteria);
			$("#status").removeClass("active");
			updateCriteria();
		}
		
		else {
			updateCriteria();
			//$("#status").slideDown(250);
			$("#status").addClass("active");
		}
		
		function updateCriteria() {
			AuthJobs.Filter.updateCategoryStatus();
			AuthJobs.Filter.updateTypesStatus();
			AuthJobs.Filter.updateLocationStatus();
			AuthJobs.Filter.updateSearchStatus();
		}
		
	},
	
	updateCategoryStatus: function() {
		var category = $.trim($("#categories .selected a").clone().children().remove().end().text().toLowerCase());
		var onlyremote = AuthJobs.Filter.onlyremote != "0" ? true : false;
		var remote = "";
		
		if (!$("#categories .selected").hasClass("reset")) {
			if (onlyremote) {
				remote = "<strong>telecommute</strong> ";
			}
			$("#status .category").html(remote + "jobs in <strong>" + category + "</strong>");
		}
		
		else {
			if (onlyremote) {
				$("#status .category").html("<strong>telecommute</strong> jobs");
			}
			else {
				$("#status .category").html("<strong>" + category + "</strong>");
			}
		}
		
	},
	
	updateTypesStatus: function() {
		
		var selected = AuthJobs.Filter.types.split(",");

		var unselected = [];		
		$.each(AuthJobs.Filter.type_lookup, function(id, title) {
			if ($.inArray(id, selected) == -1) {
				unselected.push(id);
			}			
		});
		
		var selectedCount = selected.length;
		var unselectedCount = unselected.length;

		var types = "";
		
		if (unselectedCount <= AuthJobs.Filter.exceptionLimit) {
			$.each(unselected, function(index, element) {

				var label = AuthJobs.Filter.type_lookup[element];
				if (label == "internship") { label += "s"; } // pluralise internship
				
				if (index == unselectedCount - 1) {
					if (index != 0) { types += " </strong> &amp; <strong> "; }
					types += label;
				} 
				
				else {
					types += label;
					
					if (index != unselectedCount - 2) {
						types += ", ";
					}
				}				

			});
		} 
		
		else {	
			$.each(selected, function(index, element) {
				
				var label = AuthJobs.Filter.type_lookup[element];
				if (label == "internship") { label += "s"; } // pluralise internship
				
				if (index == selectedCount - 1) {
					if (index != 0) { types += "</strong> &amp; <strong>"; }
					types += label;
				} else {
					types += label;
					if (index != selectedCount - 2) {
						types += ", ";
					}
				}
			});
		}
		
		if (types.length != 0) {
			if (unselectedCount <= AuthJobs.Filter.exceptionLimit) {
				$("#status .types").html('(except <strong>' + types + '</strong>)');
			} 
			else {
				$("#status .types").html('(<strong>' + types + '</strong>)');
			}
		} 
		else {
			$("#status .types").empty("");
		}
		
	},
	
	updateLocationStatus: function() {
		var location = $.trim(AuthJobs.Filter.location);
		if (location != "") {
			
			if (location.substring(0,2) == "ll") {
				$("#status .location").html("<strong>nearby</strong>");
			}
			
			else {
				$("#status .location").html("near <strong>" + location + "</strong>");
			}
	
		}
		
		else {
			$('#status .location').empty();
		}
	},
	
	updateSearchStatus: function() {
		var search = $.trim(AuthJobs.Filter.search);
		if (search != "") {
			$("#status .search").html("matching <strong>&ldquo;" + search + "&rdquo;</strong>");
		}
		
		else {
			$('#status .search').empty();
		}
	},
	
	defaults: function() {		
		var defaults = true;		
		if (!AuthJobs.Filter.defaultCategory()) return false;
		if (!AuthJobs.Filter.defaultLocation()) return false;	
		if (!AuthJobs.Filter.defaultOnlyRemote()) return false;
		if (!AuthJobs.Filter.defaultSearch()) return false;
		if (!AuthJobs.Filter.defaultTypes()) return false;			
		return defaults;
	},
	
	defaultCategory: function() {		
		if (AuthJobs.Filter.category != "0") return false;
		else return true;		
	},
	
	defaultLocation: function() {
		if (AuthJobs.Filter.location != "") return false; 
		else return true;
	},
	
	defaultOnlyRemote: function() {
		if (AuthJobs.Filter.onlyremote != "0") return false;
		else return true;
	},
	
	defaultSearch: function() {
		if (AuthJobs.Filter.search != "") return false;
		else return true;
	},
	
	defaultTypes: function() {
		
		if (AuthJobs.Filter.types == "0") return true;
		
		var sum = 0;
		var target = 10;
				
		$.each(AuthJobs.Filter.types.split(","), function(index, element) {			
			sum += parseInt(element, 10);			
		});
		
		if (sum < target) return false;
		else return true;		
		
	}
	
};


AuthJobs.Home = {
		
	// Initialise, called on page load
	init: function() {		
		
		// Hide alert when clicking close button
		$('#alert a.dismiss').bind('click', function() {
			$('#alert').slideUp();
			$.post('/ajax/dismiss_alert.php','alert_dismissed');
			return false;
		});
		
		AuthJobs.Subscribe.init();
				
	}
	
};

AuthJobs.Subscribe = {
	
	init: function() {
		
		// Subscribe modal overlay
		
		$(".subscribe").overlay({
			top: 0,
			effect: 'panelSlide',
			expose: {
				color: '#000',
				loadSpeed: 200,
				opacity: 0.75			
			},
			speed: 'fast',
			closeOnClick: false,
			onBeforeLoad: function(e) {
				
				$("#subscribe header p").html("Your criteria: <strong class='criteria'>" + $.trim($("#status .criteria").text()) + "</strong>");
				
				$.get("/ajax/subs.php", {}, function(a) {
            $("#customrss").attr("href", a.feed);
            $("#rssurl").val(a.feed);
        }, "json");
			
			},
			onClose: function(e) {
				AuthJobs.Subscribe.modalReset();
			}
		});
		
		// Subscribe modal tabs
		$("#subscribe .methods").tabs("#subscribe .process > div", {
			effect: 'fade',
			initialIndex: 0,
			onBeforeClick: function(e, index) {
				
				var tab = $('#subscribe .methods li').eq(index),
						newPos;
				
				if ($('#subscribe:visible').length == 1) {
				
					newPos = tab.position().top + (tab.height() / 2) - ($('#subscribe .notch').height() / 2);		
				
					$('#subscribe .notch').stop().animate({ 
						top: newPos + 'px' 
					}, 500, 'easeOutExpo');
					
				} else {
					$('#subscribe').show();
					
					newPos = tab.position().top + (tab.height() / 2) - ($('#subscribe .notch').height() / 2);		
				
					$('#subscribe .notch').stop().css({top: newPos});
					
					$('#subscribe').hide();
				}
				
				$("#subscribe .methods li").removeClass('active');
				tab.addClass('active');
				
			}
		});
		
		// Subscribe form validation
		$("#subscribe form").validate({
	    rules: {
      	subscribeemail: {
        	required: true,
          email: true
       	}
			},
			messages: {
				subscribeemail: {
					email: "Please enter a valid email address."
				}
			},
			errorClass: "error",
			errorElement: "label",
			highlight: function(b, a) {
				AuthJobs.Global.highlightFieldError(b, a);
			},
			unhighlight: function(b, a) {
				AuthJobs.Global.unhighlightFieldError(b, a);
			},
			submitHandler: function(a) {
				$.ajax({
					type: 'POST',
					url: "/ajax/subscribe.php",
					data: {
						subscribeemail: $("#subscribeemail").val(),
						mailfrequency: $("#subscribe-email > :radio:checked").val()
					},
					success: function(b) {
						$("#subscribe .body").slideUp(500, function() {
							$("#subscribe h2").html("Subscribed");
							$("#subscribe header p").html("We&#146;ll be sending you matching jobs as they come in. Good luck!");
						});
					},
					error: function(b, s, e) {
						$("#subscribe .body").slideUp(500, function() {
							if (e == "Bad Request"){
								$("#subscribe header p").html("You already have an active subscription for this criteria.");
							}
							else{
								$("#subscribe header p").html("An error occurred! Whoa!");
							}
						
							$("#subscribe h2").html("Oops!");
						});
					},
					dataType: 'text'
				});
				return false;
			}
    });
		
	},
	
	modalReset: function() {
		$("#subscribe .body").css("display", "block");
    $("#subscribe h2").html("Subscribe to Personalized Notifications");	
	}
	
};


AuthJobs.Post = {
	
	// Max assignable categories to a job listing
	category_limit: 2,
	
	// Initialise, called on page load
	init: function() {	
		
		// Custom styling treatment for selects
		// REMOVED [BBODIEN] - SSELECT BUGGY IN IE<9
		// $("body:not(.payment) select").sSelect().addClass('stylish');
		
		// Job type selection (clicking radio)
		$("#jobtype .options input[type='radio']").click(function() {
			
			// set li.selected
			$("#jobtype .options li").removeClass("selected");
			$(this).parent('li').addClass("selected");
			
		});
		
		// Job type selection (clicking link)
		$("#jobtype .options a").click(function() {
			
			// select radio
			$("#jobtype .options input[type='radio']").removeAttr("checked");
			$(this).siblings("input[type='radio']").attr("checked", "checked").trigger('click');			
			
			return false;
		});
		
		// Set selected class on list item if browser has recalled input checked status
		$("#jobtype .options input[type='radio']").each(function(index, element) {
			
			if ($(this).get(0).checked) {
				$(this).parent('li').addClass("selected");
			}
			
		});
		
		// Make the back link act like a post
		$("#post_back").click(function(){
			$("#post").prepend('<input type="hidden" name="goto_part" value="1" />');
			$("#post").submit();

			return false;
		});

		
		
		// Special treatment of freelance job type
		$("input[name='job_type']").click(function() {			
			if ($(this).parent('li').hasClass("freelance")) {
				//$('#relocationassist').attr('disabled','disabled');
				//$("#remoteworking").get(0).checked = true;
			}
			else {				
				//$('#relocationassist').removeAttr('disabled');
				//$("#remoteworking").get(0).checked = false;
			}			
		});
		
		// Category handling
		
		// Build category options 
		var cat_master = "";
		$("#cat_master li").each(function(index, element) {
			cat_master += "<option value='" + $(element).find(".cat_id").text() + "'>" + $(element).find(".cat_name").text() + "</option>";
		});
		
		$(".category_add").click(function(e) {
			
			var cat_count = $("#categories > li").size();
						
			if (cat_count < AuthJobs.Post.category_limit) {
				
				var next_cat = cat_count + 1;				
				var new_select = "<select name='category_" + next_cat + "'><option value=''>Choose a category ...</option>" + cat_master + "</select>";				
				
				$("#categories").append("<li>" + new_select + "</li>");
				
				//$("#categories li > select:not(.stylish)").sSelect().addClass('stylish');
				
				// TODO: Remove previously selected categories from the new options list
				
				if (cat_count == (AuthJobs.Post.category_limit - 1)) {
          $(this).hide(); // Hide the add new category link if we're at the category limit
				}
				
				$('#categories .category_delete').show().appendTo('#categories > li:last');
			}
			
			e.preventDefault();
		});
		
		$(".category_delete").click(function(e){
			var el = $(this),
					 l = $('#categories > li').length;
			
			if (l > 2) {
				el.appendTo('#categories > li:eq(' + (l - 2) + ')');
			} else {
				el.hide().appendTo('#categories > li:first');
			}
			$('#categories > li:last').remove();
			
      $(".category_add").show();
			
			e.preventDefault();
		});	
		
		// Toggle job perks
		$('#jobperks-included').live('click', function(e) {
			$('#perks-wrapper').slideDown(250);	
			$('#jobperks').removeAttr('disabled');
			$(this).replaceWith("<label for='jobperks'>Add job perks</label>");
			$("#perks .close").removeClass('hidden');
			$('#jobperks').val('');
			e.preventDefault();
		});
		
		$("#perks .close").click(function(e) {
			$("#perks-wrapper").slideUp(250, function() {
				$("#jobperks").attr("disabled", "disabled");
				$("#perks label[for='jobperks']").replaceWith("<a href='#' id='jobperks-included'>Add job perks</a>");
				$("#perks .close").addClass('hidden');
			});
			e.preventDefault();
		});
		
		// How to apply detail expansion
		$("select[name='howapply']").change(function() {
			
			var val = $(this).get(0).value;			
			var detail = $("#apply .detail");
				
			detail.find('input').hide().attr('disabled','disabled');				

			if (val == "crew") {
				// do nothing
			}

			else if (val == "email") {
				$("input[name='apply_email']").show().attr('disabled',false);
			}

			else if (val == "url") {
				$("input[name='apply_url']").show().attr('disabled',false);
			}
			
		});				
		
		// How to apply instructions
		$("#add-instructions").live('click', function(e) {
			$("#instructions-wrapper").slideDown(250).find("textarea").removeAttr("disabled");
			$(this).replaceWith("<label for='instructions'>Add instructions</label>");
			$("#apply .close").removeClass('hidden');
			$('#instructions').val('');
			e.preventDefault();
		});
		
		$("#apply .close").click(function(e) {
			$("#instructions-wrapper").slideUp(250, function() {
				$(this).find("textarea").attr("disabled", "disabled");
				$("#apply label[for='instructions']").replaceWith("<a href='#' id='add-instructions'>Add instructions</a>");
				$("#apply .close").addClass('hidden');
			});
			e.preventDefault();
		});		
		
		
		// Custom validation method for TinyMCE
		$.validator.addMethod("maxWordsTinyMCE", function(value, element, params) {
			return AuthJobs.Global.countWordsTinyMCE(tinyMCE.getInstanceById('description')) <= params;
		}, "Please enter 500 words or fewer"); // hardcoded omg
		
		// override built in maxWords wordcount method with our own for consistency
		jQuery.validator.addMethod("maxWords",function(b,a,c){
			return this.optional(a)||b.match(/([^\s\.\?]+)/g).length<=c;
		},jQuery.validator.format("Please enter {0} words or fewer."));
				
		// Set up inline form validation (handles both steps)
		$(".listing #main form").validate({		
			rules: {
				job_type: {
					required: true
				},
				compname: {
					required: "#confidential:unchecked"
				},
				compurl: {
					required: "#confidential:unchecked",
					url: true
				},
				'complogo-file': {
					required: function() { 
						return ($("#complogo").val() == 'upload' && !$("#companylogo").hasClass("existing")); 
					},
					accept: "png|jpe?g|gif"
				},
				twitter_username: {
					required: function() { return $('#complogo').val() == 'twitter'; }
				},
				comptagline: {
					required: "#confidential:unchecked",
					maxlength: 40
				},
				compadminname: {
					required: true
				},
				compemail: {
					required: true,
					email: true
				},
				category_1: {
					required: true
				},
				category_2: {
					required: function() { return $('#categories select').length >= 2; }
				},
				category_3: {
					required: function() { return $('#categories select').length >= 3; }
				},
				complocale: {
					required: true
				},
				position: {
					required: true
				},
				description: {
					required: true,
					maxWordsTinyMCE: 500					
				},
				jobperks: {
					maxWords: 50
				},
				howapply: {
					required: true,
					maxWords: 50
				},
				apply_url: {
					required: 'input[name=apply_url]:visible'
				},
				apply_email: {
					required: 'input[name=apply_email]:visible'
				},
				agree: {
					required: true
				}			
			},			
			messages: {
				job_type: 'Please select a job type.',
				compname: 'Please enter your company name.',
				compurl: {
					required: 'Please enter your company URL.',
					url: 'Please enter a valid URL.'
				},
				compadminname: {
					required: 'Please enter your admin contact name.'
				},
				compemail: {
					required: 'Please enter your admin contact email address.',
					email: 'Please enter a valid email address.'
				},
				'complogo-file': {
					accept: 'Please provide either a PNG, GIF or JPEG file.',
					required: 'Please choose an image to upload.'
				},
				twitter_username: 'Please enter your Twitter username.',
				comptagline: 'Please provide a brief description of your company.',
				category_1: 'Please select at least one job category.',
				category_2: 'Please select a valid job category.',
				category_3: 'Please select a valid job category.',
				complocale: "Please specify the job's location.",
				position: "Please specify the job's title.",
				description: {
					required: 'Please provide a job description.'
				},
				howapply: {
					required: 'Please provide instructions on how to apply for the job.'
				},
				apply_url: {
					required: 'Please provide a URL.'
				},
				apply_email: {
					required: 'Please provide an email address.'
				},
				agree: {
					required: 'Please agree to the listing terms.'
				},
				category: 'Please select at least one job category.',
				category_2: 'Please select a job category, or remove the extra category.',	
				category_3: 'Please select a job category, or remove the extra category.'				
			},		
			errorClass: 'error',
			errorElement: 'label',
			focusInvalid: false,
			errorPlacement: function(error, element) { AuthJobs.Global.errorPlacement(error, element); },
			highlight: function(element, errorClass) { AuthJobs.Global.highlightFieldError(element, errorClass); },
			unhighlight: function(element, errorClass) { AuthJobs.Global.unhighlightFieldError(element, errorClass); },
			invalidHandler: function(event, validator) { AuthJobs.Global.invalidHandler(event, validator); }
		});
		
		// TinyMCE on description field
		if(!AuthJobs.Global.isiOS){
			$('body:not(.preview) #description').tinymce({
				script_url: '/js/tiny_mce/tiny_mce.js',
				theme: 'advanced',
				skin: 'authenticjobs',
				theme_advanced_toolbar_location: "top",
				theme_advanced_toolbar_align: "left",
				theme_advanced_buttons1: "bold,italic,bullist,link,unlink",
				theme_advanced_buttons2: "",
				theme_advanced_buttons3: "",
				plugins: "paste",
				valid_elements: "p,a[href|target=_blank],strong/b,em/i,ul,li",
				setup: function(ed) {				
					ed.onInit.add(function(ed){
						AuthJobs.Global.tinyMCEWordLimitUpdate(ed);
						// get language package for link dialogue
						var script = document.createElement("script");
						script.type = "text/javascript";
						script.src = ed.theme.url + '/langs/' + ed.settings.language + '_dlg.js';
						document.getElementsByTagName("head")[0].appendChild(script);
						ed.theme._mceLink = function (ui, val) {
							var ed = this.editor,
							link = ed.dom.getParent(ed.selection.getNode(), 'A'),
							url = ed.dom.getAttrib(link, 'href'),
							send = function (url) { ed.execCommand('mceInsertLink', false, { href : url }); };
							if (!url) { url = "http://"; }
							url = prompt(ed.getLang("advanced_dlg.link_url", "link url"), url);
							if (!url) { return false; }
							send(url);
							return false;
						};	
						tinymce.dom.Event.add(ed.settings.content_editable ? ed.getBody() : (tinymce.isGecko ? ed.getDoc() : ed.getWin()), 'focus', function(e) {
							$('#description_ifr').contents().find('body').addClass('focused');
						});
						tinymce.dom.Event.add(ed.settings.content_editable ? ed.getBody() : (tinymce.isGecko ? ed.getDoc() : ed.getWin()), 'blur', function(e) {
							$('#description_ifr').contents().find('body').removeClass('focused');
						});
					});
					ed.onKeyUp.add(function(ed, e) { 
						AuthJobs.Global.tinyMCEWordLimitUpdate(ed); 
						tinyMCE.getInstanceById('description').save();
					});
				}
			});
			$('.mce_wrap').append(
				$('<a class="toggle_mce" data-mce-id="description" href="#">Switch to plain text</a>')
				.toggle(
					function(){
						tinyMCE.execCommand('mceRemoveControl', false, $(this).data('mce-id'));
						$(this).html('Switch to basic HTML');
						$('#'+$(this).data('mce-id')).focus();
					},
					function(){
						tinyMCE.execCommand('mceAddControl', false, $(this).data('mce-id'));
						tinyMCE.execCommand('mceFocus', false, $(this).data('mce-id'));
						$(this).html('Switch to plain text');
					}
				)
			);
		}

		
		// Disable company name, URL & logo if company name marked confidential
		$('input#confidential').bind('click', function() {
			if (this.checked) { 
				$('#compurl').removeClass('error');
				$('#companyurl label.error').remove();
				$("label[for='compname'], #compname, #companyurl, #companylogo, #tagline, #example").animate({ opacity: 0.5 }, 100);
				$("#compname, #compurl, #twitter_username, #complogo, #comptagline").attr("disabled", "disabled")
					// remove any errors as not relevant now
					.removeClass('error')
					.parents('fieldset').find('label.error').remove();
				$("#tagline .charactercount strong").removeAttr("style");
			}
			else {
				$("label[for='compname'], #compname, #companyurl, #companylogo, #tagline, #example").animate({ opacity: 1 }, 100);
				$("#compname, #compurl, #twitter_username, #complogo, #comptagline").removeAttr("disabled");
			}			
			
		});
		
		if ($('input#confidential').attr('checked')) {
			$('#compurl').removeClass('error');
			$('#companyurl label.error').remove();
			$("label[for='compname'], #compname, #companyurl, #companylogo, #tagline, #example").animate({ opacity: 0.5 }, 100);
			$("#compname, #compurl, #complogo, #comptagline").attr("disabled", "disabled");
			$("#tagline .charactercount strong").removeAttr("style");
		}
		
		// Company logo source options
		$("select[name='complogo']").change(function() {	
			var val = $(this).get(0).value;
			var detail = $("#companylogo .detail");
			
			detail.slideUp(250, function() {
				
				$("#companylogo .loading").hide();
				
				$(this).find('div').hide();
				$("#complogo-file, #twitter_username").attr("disabled", "disabled");
				
				if (val == "twitter")	{
					
					$("#companytwitter").show();
					$("#twitter_username").removeAttr("disabled");
					detail.slideDown(250);					

				}
				
				else if (val == "upload") {
					$("#logo-upload").show();
					$("#complogo-file").removeAttr("disabled");
					detail.slideDown(250);
					$("#companylogo .preview").attr('src','/img/employer_default.png');
				}
				
				else {
					$("#companylogo .preview").attr('src','/img/employer_default.png');
				}				
				
			});			
		
		});		
		
		// Twitter profile image fetch button
		$("#companytwitter .update").click(function(e) {
			
			var username = $("#twitter_username").val();
			
			$("#companylogo .loading").css("display", "inline-block").fadeTo(400, 1);
			
			$("#companylogo .preview").attr("src", "http://img.tweetimag.es/i/" + username + '_o')
																.css({opacity: 0})
																.load(function() {
																	$("#companylogo .preview").fadeTo(400, 1).unbind('load');
																	$("#companylogo .loading").fadeTo(400, 0);
																});		
				
			e.preventDefault();
		});
		
		// Tag line character count
		$("#comptagline").keyup(function() {
			$(this).nextAll(".charactercount").find("strong").text($(this).val().length);
		});
		
		// Recipient selection
		$("#recipient input[type='radio']").click(function() {
			$("#recipient .options label").removeClass('selected');
			$(this).next("label").addClass('selected');
			
			if ($(this).val() == "other") {
				$("#other").slideDown(250);
			}
			
			else {
				$("#other").slideUp(250);
			}
			
		});
		
		// Textarea word counting
		$(".countwords").each(function() {					
			AuthJobs.Global.countWords(this);
			$(this).bind('keyup', function() { AuthJobs.Global.countWords(this); });
		});
		
		// Apply button disabled on preview page
		$("#listing.preview .button.apply").click(function(e) {
			return false;
		});		
		
		
		/* Cart Page */
		
		// More info area for sponsored listings
		$("#sponsored .more").click(function() {
			$(this).toggleClass("open").nextAll(".extra").slideToggle(250);
			return false;
		});
		
		$("#sponsored .extra .close").click(function() {
			$("#sponsored .extra").slideUp(250);
			return false;
		});
				
		// Set up inline form validation on payment page
		$('.payment #payment').validate({					
			rules: {
				ccnumber: {
					required: "#payCC:checked",
					creditcard: true
				},
				ccexpireMonth: {
					required: "#payCC:checked",
					min: 1,
					max: 12,
					number: true
				},
				ccexpireYear: {
					required: "#payCC:checked",
					min: 2011,
					number: true
				},
				ccverify: {
					required: "#payCC:checked"
				},
				ccnameoncard: {
					required: "#payCC:checked"
				},
				ccbilladdress1: {
					required: "#payCC:checked"
				},
				cccity: {
					required: "#payCC:checked"
				},
				receipt_recipients: {
					required: true,
					email: false
				}				
			},
			messages: {
				ccnumber: {
					required: 'Please enter your credit card number.'
				},
				ccexpireMonth: {
					required: ''
				},
				ccexpireYear: {
					required: ''
				},
				ccverify: {
					required: ''
				},
				ccnameoncard: {
					required: "Please enter the name as it appears on your card."
				},
				ccbilladdress1: {
					required: 'Please enter your card billing address.'
				},
				cccity: {
					required: 'Please enter your card billing city.'
				},
				receipt_recipients: {
					required: 'Please tell us where to send your receipt.',
					email: 'Please enter a valid email address.'
				}					
			},		
			errorClass: 'error',
			errorElement: 'label',
			errorPlacement: function(error, element) { AuthJobs.Global.errorPlacement(error, element); },
			highlight: function(element, errorClass) { AuthJobs.Global.highlightFieldError(element, errorClass); },
			unhighlight: function(element, errorClass) { AuthJobs.Global.unhighlightFieldError(element, errorClass); },
			
			submitHandler: function(form) {
				form.submit();
				$('#pay_button').attr('disabled', true);
				$('#pay_button').html('Please wait...');
			}		
		});
		
		
		
	}	
	
};


AuthJobs.Listing = {
	
	// Initialise, called on page load
	init: function() {		
		
		// Flag modal	
		flag = $("#flag-trigger[rel]").overlay({
			top: 0,
			effect: 'panelSlide',
			api: true,
			expose: {
				color: '#000',
				loadSpeed: 200,
				opacity: 0.75			
			},
			speed: 'fast',
			closeOnClick: false
		});
		
		// Set up inline form validation
		$('#flag_modal form').validate({
			rules: {
				conemail: {
					required: true,
					email: true
				},
				conname: "required",
				captcha_answer: 'required'
			},			
			messages: {
				conemail: {
					email: 'Please enter a valid email address.'
				},
				conname: "Please enter your name.",
				captcha_answer: 'Please answer the question.'
			},		
			errorClass: 'error',
			errorElement: 'label',			
			highlight: function(element, errorClass) { AuthJobs.Global.highlightFieldError(element, errorClass); },
			unhighlight: function(element, errorClass) { AuthJobs.Global.unhighlightFieldError(element, errorClass); },
			submitHandler: function(form) {
				$('#captcha_error').remove();
				$.post($('#flag_modal form').attr('action'), { 
						conemail: $('#conemail').val(), 
						conname: $('#conname').val(), 
						context: $('#context').val(),
						captcha_id: $('#captcha_id').val(),
						captcha_answer: $('#captcha_answer').val(),
						ajax: 1
					},
				  function(data) {
					if (data == 'Incorrect captcha'){
						$('#flag_modal form #captcha_answer').after('<label for="captcha_answer" generated="true" class="error id="captcha_error">Sorry, wrong answer.</label>');
					}
					else{
						$('#flag_modal .body').slideUp(500, function(){
							$('#flag_modal h2').html("Thanks for your vigilance! We'll look into it.");
							$('#flag_modal header').append("<p>You help us keep Authentic Jobs relevant and valuable to job seekers and employers, and we appreciate that.</p>");
							$('#flag_modal header').append("<a class='close button minor'>Close</a>");						
							$("#flag_modal .close").click(function() {
								flag.close();
							});
						});
					}
				}, "text");
				return false;
			}			
		});
		
		// Map
		$("#location").click(function(e) {
			$("#map").stop(true).fadeTo(250, 1, function() {
				
				// Prevent clicks on map from closing map
				$('#map, #location').click(function(e){
					e.stopPropagation();
				});
			
				// Hide map on any click
				$(document).bind('click touchstart', function() {
					hideMap();
				});
				
				// Hide map on pressing Escape
				$(document).bind('keyup.map', function(e) {
					if ((e.keyCode || e.which) == 27) {
						hideMap();
					}					
				});
			});
			e.preventDefault();			
		});
		function hideMap() {
			$("#map").stop(true).fadeTo(200, 0, function() {
				$(this).hide();
				$(document).unbind('.map');
			});
		}
		hideMap();
		
		var w = $(window),
			wrap = $('.aside-wrap'),
			footer = $('footer'),
			offset = wrap.offset().top;
		w.scroll(moveSidebar);
		w.resize(moveSidebar);
		function moveSidebar(){
			if (window.innerWidth > 1040){
				aside_foot_pos = w.scrollTop()+wrap.height();
				foot_top = footer.offset().top;
				if(w.scrollTop() >= offset){
					if(aside_foot_pos >= foot_top){
						wrap.css({"position":"absolute","top":(foot_top - wrap.height()-60)+"px" });
					} else {
						wrap.css({"position":"fixed","top":0,"margin-top":0});
					}
				} else {
					wrap.attr('style', '');
				}
			} else {
				wrap.attr('style', '');
			}
		}

		// Share listing link (using addthis.com)
		var addthis_config = {
			ui_click: true			
		};		
		
		addthis.button(".addthis", addthis_config);
		
	},
	
	load_map: function(location){
		// set map
		var latlng = new google.maps.LatLng(-34.397, 150.644);
		var myOptions = {
			zoom: 11,
			center: latlng,
			mapTypeId: google.maps.MapTypeId.ROADMAP,
			panControl: false,
			zoomControl: true,
			mapTypeControl: false,
			scaleControl: false,
			streetViewControl: false,
			overviewMapControl: false
		};
		var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
		geocoder = new google.maps.Geocoder();
		geocoder.geocode( { 'address': location}, function(results, status) {
			if (status == google.maps.GeocoderStatus.OK){
				map.setCenter(results[0].geometry.location);
				var marker = new google.maps.Marker({
						map: map,
						position: results[0].geometry.location
				});
			} else {
				//?
			}
		});
	}
	
};


AuthJobs.Payment = {
	
	// Initialise, called on page load
	init: function() {
				
		// Switch between Credit Card and PayPal payment methods
		$("#payment-method input[type='radio']").bind('click', function() {
			if($("#payCC")[0].checked) {
				$("#payWithPayPal").hide();
				$("#payWithCC").slideDown(200);				
			}
			else {
				$("#payWithCC").slideUp(200, function() {
					$("#payWithPayPal").show();
				});				
			}
		});
		
		// Detect card type and display relevant logo
		$("#ccnumber").bind('keyup', function() {
			
			number = $("#ccnumber").val();
			img = "";
			
			// type detection
			if (number.match(/^4\d{3}-?\d{4}-?\d{4}-?\d{4}$/) !== null) {
				img = "cc-visa.gif";
			}
			else if(number.match(/^5[1-5]\d{2}-?\d{4}-?\d{4}-?\d{4}$/) !== null) {
				img = "cc-mc.gif";
			}
			else if(number.match(/^3[4,7]\d{13}$/) !== null) {
				img = "cc-amex.gif";				
			}
			else if(number.match(/^6011-?\d{4}-?\d{4}-?\d{4}$/) !== null) {
				img = "cc-discover.gif";
			}
			else {
				img = "cc-blank.gif";
			}
			
			// update card logo
			$(".ccnumber-img").attr('src', "/img/" + img);
			
			// if amex, switch verification image to front version
			if (img == 'cc-amex.gif') {
				$(".ccverify-img").attr('src', "/img/cc-verify-front.gif");
			}
			else {
				$(".ccverify-img").attr('src', "/img/cc-verify-back.gif");
			}
		});
		
		$('#payment_form').submit(function(){
		    $('input[type=submit]', this).attr('disabled', 'disabled');
		});
		
	}
	
};


AuthJobs.Contact = {

	// Initialise, called on page load
	init: function() {
			
		// Set up inline form validation
		$('form.contact').validate({
			rules: {
				conname: 'required',
				conemail: {
					required: true,
					email: true
				},
				consub: 'required',
				context: 'required'
			},			
			messages: {
				conname: 'Please tell us your name.',
				conemail: {
					required: 'Please give us your email address so we can get back to you.',
					email: 'Please enter a valid email address.'
				},
				consub: "Please tell us what you're writing to us about.",
				context: 'Please enter your message.'
			},		
			errorClass: 'error',
			errorElement: 'label',			
			errorPlacement: function(error, element) { AuthJobs.Global.errorPlacement(error, element); },
			highlight: function(element, errorClass) { AuthJobs.Global.highlightFieldError(element, errorClass); },
			unhighlight: function(element, errorClass) { AuthJobs.Global.unhighlightFieldError(element, errorClass); }			
		});		
		
	}	
	
};


AuthJobs.Contest = {
	
	// Initialise, called on page load
	init: function() {		
		
		var query = {
			q: "#tussle",
			rpp: "100",
			since_id: "73433681074733056"
		};
		
		$.get("http://search.twitter.com/search.json", query, function(data) {
			
			if (data.results.length > 0) {
			
				var markup = "";
			
				$.each(data.results, function(index, tweet) {
					// TODO: check for t.co links to try and drop non-relevant tweets
					markup += "<li><blockquote><cite>@" + tweet.from_user + "</cite> <p>" + tweet.text + "</p></blockquote></li>";				
				});
			
				$("#tweets").append(markup).find(".loading").remove();
				
				$("#tweets").cycle({
					fx: 'scrollUp'
				});
				
			}
			
			else {
				$("#tweets").append("<li>No tweets found</li>").find(".loading").remove();
			}
			
		}, 'jsonp');
		
	}
	
};



AuthJobs.App = {
	
	// Initialise, called on page load
	init: function() {
				
		// Screenshot carousel
		$(".iphone nav").tabs(".iphone .display > img", {
			effect: 'fade',
			rotate: true			
		}).slideshow({
			autoplay: true,
			interval: 5000
		});
		
	}
	
};

function urldecode(str) {
   return decodeURIComponent((str+'').replace(/\+/g, '%20'));
}
