(function($){
	
	// CSS styling for javascript enabled before domready
	$(document.body).addClass('javascript');

	$.fn.makeOffsetParent = function() {
		this.each(function(){
			var self = $(this); var position = self.css('position');
			if (position != 'relative' && position != 'absolute') self.css('position', 'relative');
		});
	}

	$(document).ready(function(){ 
		// Make login button pop up form
		$('#login-link a.loginButton').bind('click', function(e){
			e.preventDefault();
			
			var visible = $('#login-form').css('display') == 'block';
			$('#login-form').css('display', visible ? 'none' : 'block');
		})
	
		// Display flash on load
		$('#Flash').slideDown('slow');
		setTimeout(function(){$('#Flash').slideUp('slow');}, 7000);
	
		$('input.clearing-input').clearingInput();
		
		// Add site-wide overlay-from-ajax handler
		$('*[rel$="-overlay"]').overlay({
			speed: 'fast',
			onBeforeLoad: function(){
				var trigger = this.getTrigger();
				var src = trigger.attr('href')  + ( trigger.attr('ref') ? trigger.attr('ref') : '' );
				this.getContent().find(".wrap").css({opacity: 0}).empty().load(src);
			},
			onLoad: function() {
				this.getContent().find(".wrap").animate({opacity: 1});
			}
		});
		$('*[rel$="inline-info"]').overlay({
			speed: 'fast',
			onBeforeLoad: function(){
				var trigger = this.getTrigger();
				var src = trigger.attr('href')  + ( trigger.attr('ref') ? trigger.attr('ref') : '' );
				var bits = src.match(/\#.*/);
				this.sel = null;
				if(bits && typeof bits[0] != 'undefined'){
					this.sel = bits[0];
					var el = $(this.sel);
					if(el){
						var info = el.clone(true).css('display', 'block');
						this.getContent().find(".wrap").html(info);
					}else{
						return false;
					}
				}
			},
			onBeforeClose: function(){
				if(this.sel){
					var el = $(this.sel);
					if(el){
						var info = this.getContent().find(".wrap").find(this.sel);
						if (info && info.length > 0) {
							$(info).css('display', 'none');
							el.replaceWith($(info));
						}
					}
				}
			}
		});

		$('*[rel$="-slideshow-tour"]').overlay({
			speed: 'fast',
			onBeforeLoad: function(){
				var trigger = this.getTrigger();
				var src = trigger.attr('href')  + ( trigger.attr('ref') ? trigger.attr('ref') : '' );
				this.getContent().find(".wrap").css({opacity: 0}).empty().load(src);
			},
			onLoad: function() {
				var self = this;
				this.getContent().find(".wrap").animate({opacity: 1}, {complete:  function(){
					new SlideShowTour($('#slideShowTour'), self.getContent());
				}});
			}
		});
		
		if(window.location.pathname.match(/^\/learn-more/)){
			// Don't show popbox if a 4QSurvey already exists.
			if ($('#ipeL').length) {
				return;
			}
			var a = $(document.createElement('a')).attr({'href': '#', 'rel' : '#learn-more-popbox'}).text('pop');	
			var overlayDiv = $('#salehoo-overlay');
			var div = overlayDiv.clone();
			div.attr('id', 'learn-more-popbox')
			div.insertAfter(overlayDiv);
			var api = a.overlay({
				speed: 'fast',
				onBeforeLoad: function(){
					this.getContent().find(".wrap").css({opacity: 0}).empty().load('/learn-more/index_files/popbox.html');
				},
				onLoad: function() {
					this.getContent().find(".wrap").animate({opacity: 1});
				}
			});
			var call = function(){
				if ($.cookie("learn-more-popbox")) return;
				$.cookie("learn-more-popbox", true, {expires: 1});
				a.trigger('click.overlay');
			}
			setTimeout(call, 30000);
		}

		var bind_events = function() {
			$('select.ajax-onchange').bind('change', submit_via_ajax);
			$('select.ajax-onchange ~ .ajax-action').css({display: 'none'});
		}

		var replace_selector = function(ctxel, selector, message) {
			var replace, match, targetheight;
			message = message.match(/</) ? $(message) : $('<span class="message" style="padding-left:5px;"> '+message+'</span>');
			
			if (match = selector.match(/^(\w+)::(.+)/)) {
				switch (match[1]) {
					case 'parent':
						replace = ctxel.parent(match[2]);
						break;
					case 'ancestor':
						replace = ctxel.parents(match[2]).eq(0);
						break;
					case 'descendant':
						replace = ctxel.find(match[2]).eq(0);
						break;
				}
			}
			else replace = $(selector);
			
			// If we're replacing something that isn't on the page, just ignore it
			if (!replace.length) return;
			
			var parent = replace.parent();
			var originalParentHeight = parent.css('height');
			
			/* Find the target height - kinda ugly, maybe should use parent.height() - replace.height() + message.height()? */ 
			message.insertBefore(replace);
			message.css({ opacity: 0 });
			
			var olddisplay = replace.css('display'); 
			replace.css('display', 'none');
			
			targetheight = parent.height();
			replace.css('display', olddisplay);

			/* We need to remember the original css to restore it after the fade in */
			var original = {
				position: message.css('position'),
				top: message.css('top'),
				left: message.css('left'),
				width: message.css('width'),
				'z-index': message.css('z-index')
			};
			
			/* Then hide the message and put it over top of the replaced */

			var needToReposition = false;			
			// Easy way first - if message is absolutely positioned, it's already in the right place. Just make it z-indexed right */
			if (original.position == 'absolute') {
				message.css({
					'z-index': 10000
				});
			}
			
			/* Otherwise, try sticking it as an absolutely positioned child of the thing to replace (now relatively positioned). 
				This will fail on IE if replace can't have children (inputs, etc) */
			else {
				replace.makeOffsetParent();
				message.prependTo(replace);
				
				message.css({
					position: 'absolute',
					top: 0,
					left: 0,
					width: replace.width(),
					'z-index': 10000
				});
				
				needToReposition = true;
			}
			
			/* Then do the replace */
			parent.animate({height: targetheight}, 'slow');
			replace.children().not(message).fadeOut();

			message.css(original);
			if (needToReposition) message.insertBefore(replace); 
			replace.remove();
			message.css({opacity: 1});
		}

		var submit_via_ajax = function(e, override_href) {
			var el = $(this);
			el.blur();
			
			if (el.is('a')) {
				var url = override_href || el.attr('href');
				var method = 'get';
				var dat = null;
			}
			else {
				var form = el.parents('form').eq(0);
				var url = el.attr('rel') || form.attr('action');
				var method = form.attr('method') || 'get';
				
				var dat = form.serialize();
				if (el.is('input[type=button], button, input[type=submit]')) dat = dat + '&' + el.attr('name') + '=' + el.attr('value');
				dat += '&ajax=1';
		
				el.attr('disabled', 'disabled');
			}

			el.next('.message').remove();
			
			/* Two options for displaying a waiting state. The submission element gets the 'waiting' class added to it, and a new div is positioned at the top left of the element
			 * named waiting-for-$class for each class on the submission element */
			
			var waitingdiv = $('<div></div>');
			$.each(el.attr('class').split(/\s+/), function(i, str){ if (str != 'ajax-action' && str != 'ajax-action-static') waitingdiv.addClass('waiting-for-'+str); });
			
			waitingdiv
				.css({
					opacity: 0,
					position: 'absolute',
					top: el.offset().top,
					left: el.offset().left
				})
				.appendTo('body')
				.animate({opacity: 1});

			el.addClass('waiting');
			if (form) form.addClass('waiting');
			
			var done = function(data){
				var remove, remmethod, message, insertAfter, replace, match;
				waitingdiv.fadeOut('slow', function(){ waitingdiv.remove(); });
				el.removeClass('waiting');
				if (form) form.removeClass('waiting');
				
				if (data.replace) {
					for (var selector in data.replace) replace_selector(el, selector, data.replace[selector]);
				}
				
				if (data.message) {
					message = data.message.match(/</) ? $(data.message) : $('<span class="message" style="padding-left:5px;"> '+data.message+'</span>');
					message.css('display', 'none');
				}
				
				if (data.remove === true) {
					remove = el; 
					remmethod = 'fadeOut';
				}
				else {
					el.removeAttr('disabled');
					
					if (data.remove) {
						remove = insertAfter = el.parents(data.remove).eq(0);
						remmethod = 'slideUp'; 
					}
					else if (data.empty) {
						remove = el.parents(data.empty).eq(0).children();
						insertAfter = remove.eq(remove.length-1);
						remmethod = 'fadeOut'; 
					}
				}
				
				if (remove) {
					if (message) message.insertAfter(remove);
					remove[remmethod]('slow', function(){
						remove.remove();
						if (message) message.fadeIn('slow');
					})
					
				}
				else if (message) {
					message.insertAfter(el).fadeIn('slow');
					setTimeout(function(){message.fadeOut('slow');}, 7000);
				}

				bind_events();

				if (data.callback) {
					window[data.callback](data.params);
				}
			}

			$.ajax({
				dataType: 'json',
				data: dat,
				url: url,
				type: method,
				success: function(data){ done(data); },
				error: function(){ done({message: 'Error submitting request'}); }
			});
		}

		
		var ajaxAction = function(el, e){
			var self = $(el); 
			var parent = self.parent();
			
			e.preventDefault();
			
			// If we confirm first, pop up the box
			if (self.is('.ajax-confirm-first')) {
				parent.makeOffsetParent()
				var form = $('<div class="ajax-confirm-form"><span>Are you sure?</span> <a class="yes">Yes</a> <a class="no">No</a>');
				form
					.css({position: 'absolute', top: 0, right: 0, height: '100%'})
					.insertAfter(self);

				form
					.css({right: -form.width()})
					.animate({right: 0})
					.find('a')
						.bind('click', function(){
							var a = $(this);
							form.animate({right: -form.width()}, function(){ 
								if (a.is('.yes')) submit_via_ajax.call(self, e); 
								form.remove(); 
							});
						});
			}
			
			else submit_via_ajax.call(self, e);
		}
		
		// Add site-wide submission-via-ajax
		$('.ajax-action-static').click(function(e){
			ajaxAction(this, e);
		});
		$('.ajax-action').live('click', function(e){
			ajaxAction(this, e);
		});
		
		bind_events();
		
		$('.ajax-load, .ajax-load-once').live('click', function(e){
			var self = $(this);
			
			e.preventDefault();
			
			var target = $(self.attr('rel'));
//			target.load(self.attr('href') + (self.attr('ref') ? ' '+self.attr('ref') : ''));
			if (!self.is('.ajax-change-label') || !self.is('.review-expand'))
				target.load(self.attr('href'));

			if( self.is('.ajax-change-label')) {
				var oldText = self.find("strong").html();
				self.find("strong").html(self.find("span.hidden").html());
				self.find("span").html(oldText);
				
				// change to collapse icon
				if(self.is('.review-expand')) {
					self.removeClass('review-expand').addClass('review-contract');
					$(self.attr('ref')).hide();
				}
				else if(self.is('.review-contract')) {
					self.addClass('review-expand').removeClass('review-contract');
				}

			}
			else if (self.is('.ajax-load-once')) self.remove();
			return false;
		})
		
		// Add favorite accordian handling
		$.tools.addTabEffect("fullheight", function(i, done) {
			var active = this.getPanes().eq(i); 
			this.getPanes().not(active).animate({height: 0});
			active.animate({height: 162}, done);
		});
		
		// For the Favourites on the MemberHomepage, we want an accordian effect
		$("#UpperSection .DrillDown").tabs(".DrillDown > li > ul", {tabs: '.DrillDown > li > h3', effect: 'fullheight'});
		
		// For the other Favourites, we want an expand / collapse effect
		$('#Sidebar .DrillDown h3').bind('click', function(){
			var title = $(this);
			var list = title.next();
			
			if (title.hasClass('collapsed')) {
				list.hide().slideDown().show(function(){
					$(this).show();
				});

				title.removeClass('collapsed');
			}
			else {
				list.slideUp();
				title.addClass('collapsed');
			}
			return false;
		});

		$('.favouritelink').live('click', function(e) {
			window.location = e.target.href;
		});

		$(".DrillDown ul li")
			.live('mouseenter', function(){ 
				$(this).addClass('hover'); 
			})
			.live('mouseleave', function(){ 
				$(this).removeClass('hover'); 
				form = $(this).find('.ajax-confirm-form');
				if (form.length) form.animate({right: -form.width()}, function(){ $(this).remove(); });
			});
			
		$('.email-frequency').live('click', function(e){
			var self = $(this); 
			var parent = self.parent();
			
			e.preventDefault();
			
			var formstr = '<div class="ajax-confirm-form"><span>Updates:</span>';
			
			days = {0: 'never', 1: 'daily', 3: '3 days', 7: 'weekly'};
			for (var k in days) {
				if (self.text() == k) formstr += '<span>'+days[k]+'</span>'; 
				else formstr += '<a href="'+self.attr('href')+'?frequency='+k+'">'+days[k]+'</a>';
			}
			
			formstr += '</div>';
			
			var form = $(formstr);
			form
				.css({position: 'absolute', top: 0, right: 0, height: '100%'})
				.insertAfter(self);

			form
				.css({right: -form.width()})
				.animate({right: 0})
				.find('a')
					.bind('click', function(e){
						e.preventDefault();
						var a = $(this);
						form.animate({right: -form.width()}, function(){ 
							submit_via_ajax.call(self, e, a.attr('href')); 
							form.remove(); 
						});
					});
					
		});
		
		/**
		 * @todo
		 * !todo - this should be removed to a separate jquery library
		 *
		 * map_canvas
		 * Requires: http://maps.google.com/maps/api/js?sensor=false
		 * Automatically put a map into any div with clas map_canvas based on
		 * either of the following content syntaxes:
		 *
		 * Latitude, Longitude[, Zoom]
		 * e.g. <div class="map_canvas">-43.531637, 172.636645</div>
		 * e.g. <div class="map_canvas">-43.531637, 172.636645, 10</div>
		 *
		 * Location Search String[, Zoom]
		 * e.g. <div class="map_canvas">Christchurch, NZ</div>
		 * e.g. <div class="map_canvas">Christchurch, New Zealand, 6</div>
		 */
		$('div.map_canvas').each(function(i,el){
			// Don't attempt it if there's no google maps js api loaded
			if (window.google == undefined || window.google.maps == undefined) {
				return;
			}
			
			// If there's already a map in this element:
			if (el.map) {
				return;
			}
			
			// These are the elements we store in case someone else
			el.map = null;
			el.marker = null;
			el.positionString = null;
			
			// Remove the lat/lng/address as quick as possible so the user doesn't see them.
			el.positionString = el.innerHTML.replace(/^\s*|\s*$/g, '');
			el.innerHTML = '';
			
			
		    var myOptions = {
		      zoom: 7,
			  // Default to Christchurch - our base of operations.
		      center: new google.maps.LatLng(-43.531637, 172.636645),
		      mapTypeId: google.maps.MapTypeId.ROADMAP
		    };
			
			// Does this look like a latitude/longitude pair [with zoom]?
			var pattern = /^([\d\.-]+),\s*([\d\.-]+?)(?:,\s*(\d+?))?$/g;
			var matches = pattern.exec(el.positionString);
			if (matches) {
		    	myOptions.latlng = new google.maps.LatLng(parseFloat(matches[1]), parseFloat(matches[2]));
				if (matches[3]) {
					myOptions.zoom = parseInt(matches[3]);
				}
				el.map = new google.maps.Map(el, myOptions);
				el.map.setCenter(myOptions.latlng);
				el.marker = new google.maps.Marker({
					position: myOptions.latlng, 
					map: el.map
				});
			}
			else {
				var address = el.positionString;
				pattern = /^(.*?)(?:,\s*(\d+?))?$/g;
				matches = pattern.exec(el.positionString);
				if (matches) {
					address = matches[1];
					if (matches[2]) {
						myOptions.zoom = parseInt(matches[2]);
					}
				}
				var geocoder = new google.maps.Geocoder();
				if (geocoder) {
					geocoder.geocode( { 'address': address}, function(results, status) {
						if (status == google.maps.GeocoderStatus.OK) {
							myOptions.latlng = results[0].geometry.location;
							el.map = new google.maps.Map(el, myOptions);
							el.map.setCenter(myOptions.latlng);
							el.marker = new google.maps.Marker({
								map: el.map, 
								position: myOptions.latlng
							});
						} else {
							// If the lookup fails, we can't provide a map, so remove it.
							el.parentNode.removeChild(el);
						}
					});
				}

			}
			
			// Trigger a change event on this element, so someone can hook into it
			// if they want.
			$(el).trigger('change.map_canvas');
		});
	});

	/**
	 * Success Stories quick view
	 */
	$.fn.rotateSuccessStories = function() {
		$(this).click(function() {
			$("p."+  $(".active.justFace").removeClass("active").attr("rel")).hide();
			$("p."+ $(this).addClass("active").attr("rel")).show();
		});
	}
	// feature overview page
	$(".justFace").rotateSuccessStories();
		
	$('#NVForm_SearchForm').live('change', function(){
		$('#Q').animate({'marginLeft': 0});
		$('#action_favorite').fadeOut();
	});
	$('#NVForm_SearchForm #Q').live('keypress', function(){
		$('#Q').animate({'marginLeft': 0});
		$('#action_favorite').fadeOut();
	});
	$('.menu-search #NVForm_SearchForm_Q').clearingInput({blurClass: 'default', text: 'Directory search'});
	
	// Suppliers reviews
	$(".reviews .submit-review").addClass("hidden");
	$(".addReviewRating").click(function() {
		if($(".reviews .submit-review").hasClass("hidden")) {
			$(".reviews .submit-review").removeClass("hidden");
			$(".addReviewRating").hide();
		}
		if(!($(this).hasClass("ignoreReturn") === false)) return false;
	});
	// You can't select values, and "none" at the same time. (must use 'click'. 'change' fails in IE).
	$('#NVForm_RatingForm #Contacted input').live('click', function() {
		if (this.value != "none") {
			$(this).parents('#Contacted').find('input[value="none"]').attr('checked', false);
		}
		else {
			$(this).parents('#Contacted').find('input:not(input[value="none"])').attr('checked', false);
		}
	});
	
	// Blog JS
	$(".enterEmail").click(function() {
		if($(this).val() == "Enter your email") $(this).val("");
	});

	/**
	 * Simple slide show for elements
	 * @author websta*
	 */
	window.ElementSlideShow = function (el, periodical){
		this.isFirst = true;
		this.isLast = false;
		/**
		 * Constructor
		 */
		function init(el, periodical){
			if(show.init(el) && typeof periodical == 'number'){
				this.run(periodical);
			}
		}
		/**
		 * Core, does all the hard yards
		 * @private
		 */
		var show = {
			container: null,
			timer: null,
			screens: [],
			currIndex: 0,
			nextIndex: 1,
			init: function(el){
				this.container = $(el);
				if(!$(this.container)){
					throw "SimpleShow could not be intitialised: " + el; 
				}
				this.screens = this.container.children('div.screen');
				this.length = this.screens.length;
				if(this.length > 1){
					$(this.screens).css({
						opacity:0,
						display:'none'
					});
					this.change(0, 1);
					return this;
				}
				return false;
			},
			change: function(index, immediate){
				if(typeof index == 'number' && index >= 0 && index < this.length){
					var next = index;
				}else{
					var next = this.nextIndex;
				}
				var prev = this.screens[this.currIndex];
				var curr = this.screens[next];
				if(typeof immediate != 'undefined' && immediate){
					$(prev).css({display: 'none', opacity: 0});
					$(curr).css({display: 'block', opacity: 1});
				}else{
					$(prev).animate({opacity: 0}, {complete: function(){
						 $(this).css({display: 'none'});
					}});
					$(curr).css({display: 'block', opacity: 0});
					$(curr).animate({opacity: 1});
				}
				this.currIndex = next;
				next++;
				this.nextIndex = (next < this.length) ? next : 0;
			},
			first: function(){
				this.change(0);
			},
			last: function(){
				this.change(this.length - 1);
			},
			prev: function(){
				if(this.currIndex > 0){
					this.change(this.currIndex - 1);
				}
			},
			next: function(){
				if(this.currIndex < this.length - 1){
					this.change(this.currIndex + 1);
				}
			}
		}
		
		this.run = function(delay){
			var self = this;
			var call = function(){
				return self.change.apply(self);
			};
			show.timer = setInterval(call, parseInt(delay));
		},
		
		this.stop = function(){
			clearInterval(show.timer);
		}
		
		this.container = function(){
			return show.container;
		}

		/**
		 * Cycle screen
		 * @public
		 */
		this.change =  function(){
			show.change();
			if(show.currIndex == 0){
				this.isFirst = true;
				this.isLast = false;
			}else if(show.currIndex == show.length - 1){
				this.isLast = true;
				this.isFirst = false;
			}else{
				this.isFirst = false;
				this.isLast = false;
			}
		}			
		
		/**
		 * Previous screen
		 * @public
		 */
		this.first = function(){
			show.first();
			this.isFirst = true;
			this.isLast = false;
		}
		
		/**
		 * Next screen
		 * @public
		 */
		this.last = function(){
			show.last();
			this.isLast = true;
			this.isFirst = false;
		}
		
		/**
		 * Previous screen
		 * @public
		 */
		this.prev = function(){
			show.prev();
			if(show.currIndex == 0){
				this.isFirst = true;
				this.isLast = false;
			}else{
				this.isFirst = false;
			}
		}
		
		/**
		 * Next screen
		 * @public
		 */
		this.next = function(){
			show.next();
			if(show.currIndex == show.length - 1){
				this.isLast = true;
				this.isFirst = false;
			}else{
				this.isLast = false;
			}
		}
		
		init.apply(this, arguments);
	};

	/**
	 * Controllable Slide Show in a lightbox(jquery tools.overlay)
	 * @author websta*
	 */
	window.SlideShowTour =  function(slideShowContainer, overlayElement){
		var slideShow = new ElementSlideShow(slideShowContainer);
		var container = slideShow.container();
		if(!overlayElement){
			container.addClass('inpage');
		}
		var nextLinks = container.find('a.tourNext');
		var prevLinks = container.find('a.tourPrev');
		var endLinks = container.find('.tourEnd');
		if(nextLinks) nextLinks.click(function(e){
			e.preventDefault();
			slideShow.next();
			if(slideShow.isLast){
				nextLinks.hide();	
			}
			prevLinks.show();
		});
		if(prevLinks) prevLinks.click(function(e){
			e.preventDefault();
			slideShow.prev();
			if(slideShow.isFirst){
				prevLinks.hide();
			}
			nextLinks.show();
		});
		if(overlayElement && endLinks) endLinks.click(function(e){
			e.preventDefault();
			overlayElement.find('.close:first').trigger('click');
		});
	}
})(jQuery)
