//------------------------------------
//
//	GIRAFFE.JS
//	Requires:	jquery 1.6.x
//
//------------------------------------

////////////////////////////
// BEGIN JQUERY

$(function(){

	//////////////////////////
	// MEDIA QUEROES
	
	function mediaQs(){
		
		if( $('html').hasClass('ie7') || $('html').hasClass('ie8') ){
		
			var $w = $(window);
			var $d = $('#page_decorations');
		
			$(document).ready(function(){
				checkWidth();
			});
		
			$w.resize(function(){

				checkWidth();
				
			});
			
			function checkWidth(){
			
				if( $w.width() < 1200 ){
					$d.removeClass('show');
				}else{
					$d.addClass('show');
				}
				
				if( $w.width() < 1260 ){
					$('.bubble').hide();
				}else{
					$('.bubble').show();
				}
			
			}
		
		}
		
	}
	
	mediaQs();

	//////////////////////////
	// BUBBLES
	// Use 'name': false to create a new bubble with dev mode
	
	if( $('#signup_form').length > 0 ){
		
		$.bubbles({
			'join_club':	[169,-596,120,120],
			'tweet':		[198,495.5,120,120],
			'facebook':		[630,469.5,120,120]
		});
		
	}

	
	//////////////////////////
	// LOCATION SEARCH
	
	$('header #search').location({
		'json':		$('header #search').attr('action'),
		'brand':	$('header #search').data('brand')
	});
	
	
	//////////////////////////
	// FRANCHISE GALLERY
	
	$('.gallery').slideThat({
		'arrows':	false
	});
	

	//////////////////////////
	// TINYBOX
	
	// FOOTER PRIVACY & LEGAL
	
	$('footer #legal, footer #privacy').click(function(e){
		
		href = $(this).attr('href');
		
		TINY.box.show({
			url: href+'/tiny',
			width:	800,
			height:	594,
			boxid:	'tandcs'
		});
		
		e.preventDefault();
		
	});
	
	
	// FOOTER FLICKR
	
	$('#flickr a').click(function(e){
		
		href = $(this).attr('href');
		
		TINY.box.show({
			image:	href,
			boxid:	'tgallery'
		});
		
		e.preventDefault();
		
	});
	
	
	$('#brighton').click(function(e){
		
		TINY.box.show({
			html:	$('#b_terms').html(),
			boxid:	'tandcs',
			width:	400
		});
		
		e.preventDefault();
		
	});
		
	
	// MOBILE SITE AD
	
	/*
$('#mobile_promo a').click(function(e){
		
		href = $(this).attr('href');
		
		TINY.box.show({
			url: href+'/tiny',
			width:	800,
			height:	620,
			openjs:	function(){
				
				$('#mobile .slider').slideThat({
					'arrows':	false,
					'nav':		false,
					'pause':	2
				});
				
			}
		});
		
		e.preventDefault();
		
	});
*/
	
	
	//////////////////////////
	// TERMS TOOLTIPS
	
	$('span.img[data-terms],div.menu_promotion[data-terms]').tooltip({
		'style':	'brand_accent',
		'fixed':	true,
		'before':	function($this,$t){
		
			$('<p/>',{
				'html':		$this.data().terms,
				'css':		{
					'width':	200,
					'padding':	'12px 15px 15px',
					'margin':	0
				}
			}).appendTo($t);
			
		}
	});
	
	
	//////////////////////////
	// SIGN UP VALIDATION
	
	$('#signup_form').validate();
	

	//////////////////////////
	// BRAND SWITCHER
	
	function brandSwitcher(){
	
		// Objects
		var $logo = $('#logo');	// The logo on the page
		var $current;			// The current brand div
		var $img;				// The image inside the current brand div, for easier access
		var $fake;				// A fake logo, for animating
		var $bs;				// The Brand Switcher
		
		// Don't go any further if we are in the corporate section
		if( !$logo.hasClass('corporate') && $logo.length > 0 ){

			// Variables
			var mooseBan = false;
			var open = false;
			var html = $('#brands').html();
			var t = $('#brands .brand').length;
			var fresh = true;
		
			// Add in the link next to the logo, plus the tooltip
			
			var halfLogo = Math.round( $logo.width() / 2 );
			
			var $btn = $('<span/>',{
				'id':	'brand_toggle',
				'css':	{
					'margin-left':	halfLogo + 20
				}
			}).insertAfter($logo).click(function(){
			
				showSwitcher();
			
			});
			
			// And look for #swtich
			$('a[href=#switch]').click(function(e){
			
				if( !open ) showSwitcher();
				
				e.preventDefault();
			
			}).scrollTo({
				'target':	'top'
			});;
			
			$.bubbles({
				'switch_brand':	[39,halfLogo + 50,173,86,true]
			});
			
			function showSwitcher(){
				
				if( !mooseBan ){
				
					// Ban the mouse
					mooseBan = true;
					open = true;
				
					// Only add another if it doesn't exist
					if( $('#brand_switcher').length < 1  ){
					
						// Add it to the page
						$bs = $('<div/>',{
							'id':		'brand_switcher',
							'class':	'beige shadow',
							'html':		html,
							'css':	{
								'top':	-144
							}
						}).prependTo('body').mouseleave(function(){
							
							hideSwitcher();
							
						});
						
						$current = $bs.find('.current');
						$img = $current.find('img');
						
						// Remove the current logo (we have to keep the next bit separate to get an accurate index)
						$current.css({
							'opacity':	0
						}).click(function(e){
						
							hideSwitcher();
						
							e.preventDefault();
							
						});
	
						
						// Clone a new, fake logo over the top of everything
						$fake = $('<img/>',{
							'src':	$('#logo img').attr('src'),
							'id':	'fake_logo',
							'css':	{
								'left':	$logo.offset().left
							}
						}).prependTo('body');
						
					}
					
					$fake.show();
					
					// Hide the existing logo
					$logo.css({
						'opacity':	0
					});
					
					// Slide it down
					$bs.show().animate({
						'top':	0
					},600,'easeInOutExpo');
					
					// Shrink it down to the new switcher logo size
					$fake.animate({
						'top':		$img.offset().top + 145,
						'left':		$img.offset().left + 1,
						'width':	$current.find('img').width(),
						'height':	97
					},600,'easeInOutExpo',function(){
					
						// Re-Show the current one
						$current.css({
							'opacity':	1
						});
						
						// Hide the fake
						$fake.hide();
						
						// Activate the tooltips
						if( fresh ){
						
							// No longer a fresh turkey!
							fresh = false;
							
							$bs.find('.brand').tooltip({
								'fixed':	true,
								'margin':	12,
								'before':	function($this,$t){
									
									// Get tooltip text
									$('<p/>',{
										'html':	$this.find('p').text()
									}).prependTo($t);
									
									$t.addClass('brand');
									
								}
							});
						
						}
						
						// Allow the moose back in da hoose!
						mooseBan = false;
						
					});
				
				}
				
			}
			
			function hideSwitcher(){
			
				if( !mooseBan ){
				
					mooseBan = true;
					
					$('#tooltip').remove();
				
					$current.css({
						'opacity':	0
					});
				
					$fake.show().animate({
						'top':		0,
						'left':		$logo.offset().left,
						'width':	$logo.width(),
						'height':	$logo.height()
					},600,'easeInOutExpo',function(){
						
						$fake.hide();
						
						$logo.css({
							'opacity':	1
						});
						
						mooseBan = false;
						
						open = false;
						
					});
					
					$bs.animate({
						'top':	-144
					},600,'easeInOutExpo',function(){
						$(this).hide();
					});
				
				}
				
			}
		
		}
	
	}
	
	brandSwitcher();
	
	
	//////////////////////////
	// FORMS
	
	// SELECT REPLACEMENT
	
	$('form .select').simpleSelect();
	
	
	// JOINED INPUT and BUTTONS
	
	$('form .join').children().bind({
		'focus':		function(){
			$(this).parent('.join').addClass('focus');
		},
		'blur':			function(){
			$(this).parent('.join').removeClass('focus');
		},
		'mouseenter':	function(){
			$(this).parent('.join').addClass('hover');
		},
		'mouseleave':	function(){
			$(this).parent('.join').removeClass('hover');
		}
	});
	
	
	// PLACEHOLDER

	if( 'placeholder' in document.createElement('input') === false ){
	 
		$('input').each(function(){
	 
			var $el = $(this);
	 
			// skip if we do not have the placeholder attribute
			if( !$el.is('[placeholder]') )
				return;
	 
			// we cannot do password fields, but supported browsers can
			if( $el.is(':password') )
				return;
	 
			$el.bind('focus.placeholder', function(){
				if( this.value == $el.attr('placeholder' ) )
					$el.val('');
			});
	 
			$el.bind('blur.placeholder', function(){
				if(this.value == '')
					$el.val( $el.attr('placeholder') )
			});
	 
			$el.triggerHandler('blur');
	 
			// Prevent incorrect form values being posted
			$el.parents('form').submit(function(){
				$el.triggerHandler('focus.placeholder');
			});
	 
		});
	 
	}
	
	
	//////////////////////////
	// TARGET BLANK
	
	$('a[href*="http://"]:not([href*="'+location.hostname+'"]):not([class*="internal"]), .external').live('click',function() {
	    window.open($(this).attr('href'));
	    return false;
	});
	
	
	//////////////////////////
	// FAQ
	
	$('.faq dt').hover(function(){
		$(this).addClass('hover').next('dd').addClass('hover');
	},function(){
		$('.hover').removeClass('hover');
	});
	
	$('.faq dd').hover(function(){
		$(this).addClass('hover').prev('dt').addClass('hover');
	},function(){
		$('.hover').removeClass('hover');
	});

});


//////////////////////////
// PLUGINS

(function($) {


	//////////////////////////
	// SELECT REPLACEMENT
	
	$.fn.simpleSelect = function(settings) {
		
		// Settings
		var defaults = {
			ready:			function(){},
			click:			function(){},
			change:			function(){}
		};
		
		var o = $.extend(defaults, settings);
		
		return this.each(function(){
		
			// The objects involved
			var $this = $(this);
			var $s = $this.find('select');
			
			// Fit the select to the container completely
			$s.css({
				'width':		$this.outerWidth(),
				'height':		$this.outerHeight(),
				'opacity':		0
			}).bind({
				change:		function(){
				
					$this.find('span').text($s.find('option:selected').text());
					
					o.change.apply($s);
					
				},
				click:		function(){
			
					o.click.apply($s);
				
				},
				focus:		function(){
				
					$this.addClass('focus');
				},
				blur:		function(){
					
					$this.removeClass('focus');
					
				},
				mouseenter:	function(){
	
					$this.addClass('hover');
	
				},
				mouseleave:	function(){
	
					$this.removeClass('hover');
	
				}
				
			});
			
			o.ready.apply($s);
	
		});
	
	};
	
	
	//////////////////////////
	// BUBBLES
	
	$.bubbles = function(bubbles,devmode){
	
		// The global document and body objects
		var $d = $(document);
		var $b = $('body');
		
		// For dev purposes
		var dev = false;

		// For each bubble in the array
		for( squeak in bubbles ){
		
			// If we have coordinates place it on the page
			if( bubbles[squeak] ){
			
				// If there is a 5th item in the array set to true the bubble needs to remain indepentant of screen size.
				var perm = bubbles[squeak][4] ? ' permenant' : '';
		
				$('<span/>',{
					'class':	'bubble ' + squeak + perm,
					'css':		{
						'top':				bubbles[squeak][0],
						'margin-left':		bubbles[squeak][1],
						'width':			bubbles[squeak][2],
						'height':			bubbles[squeak][3],
						'background-image':	'url(/assets/giraffe/images/generic/bubbles/' + squeak + '.png)'
					}
				}).appendTo($b);
			
			// If we don't, then do something more complicated
			}else{
				
				// Dev mode is now true
				dev = true;
				
				// Add it to the page, with the image inside so we can get the dimensions
				$('<span/>',{
					'html':		'<img src="/assets/giraffe/images/generic/bubbles/' + squeak + '.png">',
					'class':	'bubble dev ' + squeak,
					'css':		{
						'top':				10,
						'left':				10,
						'background-image':	'url(/assets/giraffe/images/generic/bubbles/' + squeak + '.png)'
					}
				}).appendTo($b);
				
			}
			
		}
		
		if( dev ){
		
			// Show max lines
			$('<div/>',{
				'css':	{
					'position':		'fixed',
					'top':			0,
					'left':			'50%',
					'right':		0,
					'bottom':		0,
					'z-index':		0,
					'width':		1260,
					'height':		'100%',
					'margin-left':	-630,
					'border-left':	'dotted 1px red',
					'border-right':	'dotted 1px red'
				}
			}).appendTo('body');
		
			// Once the image is loaded up, get the dimensions and remove the image
			$('.bubble img').load(function(){
				$(this).parent('.bubble').css({
					'width':	$(this).width(),
					'height':	$(this).height()
				}).find('img').remove();
			});
		
			// On mouse down, start drag
			$('.bubble.dev').bind('mousedown',function(e){
			
				// Get some stuff we need for positioning
				var $bubble = $(this);				// The bubble
				var cStartX = e.pageX;				// The start mouse x
				var cStartY = e.pageY;				// The start mouse y
				var bStart = $bubble.position();	// The start bubble x&y
				
				// Bind mouse move and up to the entire window
				$d.bind({
					mousemove: function(e){
						
						// Set the position
						$bubble.css({
							'top':	e.pageY - cStartY + bStart.top,
							'left':	e.pageX - cStartX + bStart.left
						});
						
						e.preventDefault();
						
					},
					mouseup: function(){
					
						// Unbind the mousemove
						$d.unbind('mousemove mouseup');
						
					}
				
				});
				
			}).click(function(e){
			
				e.preventDefault();
				
			}).dblclick(function(e){
			
				// On double click, show this alert for copying
				alert('Copy this (triple click):\n[' + $(this).position().top + ',' + ( 0 - ( ( $b.width() / 2 ) -  $(this).position().left ) ) + ',' + $(this).width() + ',' + $(this).height() + ']');
				
				e.preventDefault();
				
			});
		
		}
				
	};
	
	
	//////////////////////////
	// TOOLTIP
	// This is basic, to be filled with individual content/styling each time
	
	$.fn.tooltip = function(settings){

		// Settings
		var defaults = {
			margin:			20,
			fixed:			false,
			style:			false,
			html:			'',
			before:			function(){},
			ready:			function(){},
			click:			function(){}
		};
		
		// o variable for settings
		var o = $.extend(defaults, settings);
		
		// The global window object
		var $w = $(window);
		
		// To global tooltip and arrow objects - there is only ever one at a time
		var $t;
		var $a;
		
		// Margin offset for animations
		var m;

		// For each target
		return this.each(function(){
			
			var $this = $(this);	// The hovered object
			
			$this.mouseenter(function(e){

				// Build tooltip
				$t = $('<div/>',{
					'id':		'tooltip',
					'class':	o.style,
					'html':		o.html
				});
				
				// And the arrow
				$a = $('<span/>',{
					'class':	'arrow'
				}).appendTo($t);
				
				// Before callback
				o.before($this,$t);
				
				// Add it to page with coordinates
				$t.appendTo('body').css(coords(e));
				
				// Ready callback
				o.ready($this,$t);
				
				// Animate it a little
				$t.css({
					marginTop:		m,
					'opacity':			0
				}).animate({
					'margin-top':		0
				},{
					'queue':			false,
					'duration':			400,
					'specialEasing':	{
						marginTop:		'easeOutBounce'
					}
				});
				
				$t.animate({
					'opacity':			1
				},{
					'queue':			false,
					'duration':			200
				});
				
				// Bind actions to target
				$this.bind({
					'mousemove':	function(e){
						
						// Move with mouse
						if( !o.fixed ) $t.css(coords(e));
						
					},
					'mouseleave':	function(){
					
						// Remove tooltip and unbind events from target
						$t.remove();
						$this.unbind('mousemove mouseleave');
						
					},
					'click':		function(e){
						
						if( o.click == false ){
						
							return false;
							
						}else{
						
							o.click($this,$t);
						
						}
						
					}
				});
				
				// If page scrolls, remove tooltip
				$w.scroll(function(){
					$t.remove();
				});
				
			});
			
			// Get coordinates
			function coords(e){
				
				// Get window metrics
				var scrT = $w.scrollTop();
				var scrL = $w.scrollLeft()
				var win = $w.width();
				
				// Get tooltip metrics
				var w = $t.getHiddenDimensions().outerWidth;
				var h = $t.getHiddenDimensions().outerHeight;
				
				// Get X
				if( o.fixed ){
				
					var xp = $this.offset().left + Math.round( $this.outerWidth() / 2 );
					var yp = $this.offset().top;
				
				}else{
				
					var xp = e.pageX;
					var yp = e.pageY;
					
				}
				
				var x = xp < win + scrL - Math.round( w / 2 ) - o.margin ? xp - Math.round( w / 2 ) : win + scrL - ( w + o.margin );

				// Top or bottom
				if( yp < scrT + h + ( o.margin * 3 ) ){
				
					// Adjust the y point if fixed, as we need to account for the target height
					if( o.fixed ) yp += $this.outerHeight();
				
					// Set arrow to up
					$a.removeClass('down').addClass('up');
					
					// Figure out y
					var y = yp + o.margin;
					
					// Set margin offset
					m = o.margin;
					
				}else{
				
					// Set arrow to down
					$a.addClass('down').removeClass('up');
					
					// Figure out y
					var y = yp - h - o.margin;
					
					// Set margin offset
					m = 0 - o.margin / 2;
					
				}
				
				// Final off the screen check
				if( x < scrL + o.margin ){
					x = scrL + o.margin;
				}
				
				//console.log('x: ' + x + ' y: ' + y);
				
				// Send back the x and y for the css
				return {top:y,left:x};
				
			}
			
		});
		
	};
	
	
	//////////////////////////
	// HIDDEN DIMENSIONS

	$.fn.getHiddenDimensions = function(includeMargin){
	
		var $item = this;
		
		props = {
			position:		'absolute',
			visibility:		'hidden',
			display:		'block'
		};
		
		dim = {
			width:			0,
			height:			0,
			innerWidth:		0,
			innerHeight:	0,
			outerWidth:		0,
			outerHeight:	0
		};
		
		$hiddenParents = $item.parents().andSelf().not(':visible');
		
		includeMargin = ( includeMargin == null ) ? false : includeMargin;
		
		var oldProps = [];
		
		$hiddenParents.each(function(){
		
			var old = {};
		
			for ( var name in props ) {
			
				old[ name ] = this.style[ name ];
				this.style[ name ] = props[ name ];
				
			}
		
			oldProps.push(old);
			
		});
		
		dim.width = $item.width();
		dim.outerWidth = $item.outerWidth(includeMargin);
		dim.innerWidth = $item.innerWidth();
		dim.height = $item.height();
		dim.innerHeight = $item.innerHeight();
		dim.outerHeight = $item.outerHeight(includeMargin);
		
		$hiddenParents.each(function(i) {
		
			var old = oldProps[i];
			
			for ( var name in props ) {
			
				this.style[ name ] = old[ name ];
				
			}
		});
		
		return dim;
		
	}
	
	
	//////////////////////////
	// SCROLL TO
	
	$.fn.scrollTo = function (settings){

		return this.click(function(e){
		
			$.scrollTo(settings,$(this))
			
			e.preventDefault();
			
		});

	}

	$.scrollTo = function(settings,$this){

		// Settings
		var defaults = {
			target:		'href',				// If left, it will assume that the target is an href. If you set the target, it must be either: top, bottom, or an object
			speed:		600,				// Speed of scroll
			offset:		0,					// Add or subtract from the final position
			easing:		'easeInOutExpo',	// Easing to use
			before:		function(){},		// Callback before scrolling
			after:		function(){}		// Callback after scrolling
		};
		
		var o = $.extend(defaults, settings);
		
		// The scrolling element
		var $element = $('html').hasClass('webkit') ? $('body') : $('html');
		
		// Before callback
		o.before.apply($this);
		
		// Just creating it for now
		var y = 0;
		
		// The max scroll (to stop sudden stops)
		var max = $(document).height() - $(window).height();

		// Target detection
		if( o.target == 'href' ){
		
			y = $($this.attr('href')).offset().top;
		
		}else{
		
			if( o.target == 'top' ){
				
				y = 0;
				
			}else if( o.target == 'bottom' ){
			
				y = max;
			
			}else{
			
				y = o.target.offset().top;
			
			}
		
		}
		
		// Add the offset
		y = y + o.offset;
	
		// If the page isn't long enough just go as far as possible
		if( y > max ){
			y = max;
		}
		
		// If we're not going anywhere, don't bother with the animation
		if( y == $element.scrollTop() || y == max ){
		
			o.after.apply($this);
			
		}else{
		
			// Animate! - Put body back in if anything breaks, or do an if statement for the tag on certain browsers. I think it's just ie that has an issue.
			$element.animate({
				'scrollTop':	y
			},o.speed,o.easing,function(){
			
				o.after.apply($this);
				
			});
		
		}
		
	};
	
	
	//////////////////////////
	// SLIDE THAT PLUGIN
	
	$.fn.slideThat = function(settings){

		// Settings
		var defaults = {
			'arrows':	true,			// Show the arrows
			'nav':		true,			// Show the nav dots
			'infinite':	true,			// Will cycle through slides and then go back to zero automatically
			'auto':		true,			// Will automatically cycle through slides
			'pause':	5,				// The pause between slides in seconds - can be set using data-pause
			'setSize':	true,			// For customised sliders, this often breaks things, so can be set to false
			'ready':	function(){}	// Ready callback
		};
		
		// o variable for settings
		var o = $.extend(defaults, settings);

		// For each target
		return this.each(function(){
			
			// Objects
			var $this = $(this);										// The slider div
			var $swin = $this.find('.slider_window');					// The slider window
			var $nav;													// The nav
			var $next;													// Next arrow
			var $prev													// Previous arrow
			var $slide = new Array();									// An array of the slides
			
			// Variables
			var total = $swin.children('.slider_content').length + 1;	// How many slides are there? Add 1 for the initial slide that is outside the window to start!
			var c = 1;													// Current slide
			var timer;													// For the pause
			var mooseBan = false;										// Bad moose!
			var w;														// The width of the whole thing
			var h;														// The height of the whole thing
			var sw;														// The width of the slider window (for homepage mainly)
			var sh;														// The height of the slider window (for homepage mainly)
			
			// Don't go any further if there is only 1 slide (or none!)
			if( total > 1 ){
			
				// Set width and height for going forward
				w = $this.width();
				h = $this.height();
				
				if( o.setSize ){
				
					$swin.css({
						'width':	w,
						'height':	h
					});
				
				}
				
			
				// Build an array of each slide
				for( i = 0; i <= total; i++ ){
					
					// The first slide is not in the window, so treat that one differently
					if( i == 0 ){
					
						$slide[i] = $this.children('.slider_content');
					
					}else{
					
						// Find the slide in the window
						$slide[i] = $swin.children('.slider_content:eq(' + ( i - 1 ) + ')');
					
					}
					
				}
				
				// Now that's done, show the slider window
				sw = parseFloat( $swin.css('width') );
				sh = parseFloat( $swin.css('height') );
				
				$swin.empty().show();
				
				// and remove the contents and move the first slide into it!
				$slide[0].prependTo($swin);
				
				// Is there nav of any type?
				if( o.nav || o.arrows ){
				
					// Build nav container
					$nav = $('<div/>',{
						'class':	'slider_nav'
					});
				
					// If there are nav dots
					if( o.nav ){
					
						var navHTML = '';
						
						// Build the list
						for( i = 1; i <= total; i++ ){
							
							// For each slide, add a nav dot. If it's the first one, add class of on.
							navHTML += '<li><a href="#' + i + '" title="Go to slide ' + i + '"' + ( i == 1 ? ' class="on"' : '' ) + '>' + i + '</a></li>';
							
						}
						
						// Build them
						$('<ul/>',{
							'html':		navHTML
						}).appendTo( $nav ).find('a').click(function(e){
						
							// Go to the number
							goTo( parseFloat( $(this).text() ) );
	
							// Stop badness
							e.preventDefault();
	
						});
						
					}
					
					// If there are arrows
					if( o.arrows ){
						
						// Build next
						$next = $('<a/>',{
							'href':		'#next',
							'class':	'arrow next',
							'text':		'Show next slide',
							'click':	function(e){
								
								// Go to the next slide
								goTo('next');
								
								// Stop badness
								e.preventDefault();
								
							}
						}).appendTo( $nav );
						
						// Build prev
						$prev = $('<a/>',{
							'href':		'#prev',
							'class':	'arrow prev',
							'text':		'Show previous slide',
							'click':	function(e){
								
								// Go to the previous slide
								goTo('prev');
								
								// Stop badness
								e.preventDefault();
								
							}
						}).appendTo( $nav );
						
					}
					
					// Add it all to the slider
					$this.append( $nav );
					
					// Center the arrows vertically
					var $arr = $this.find('.arrow');
					
					$arr.css({
						'top':	Math.round( h / 2 ),
						'margin-top':	0 - Math.round( $arr.height() / 2 )
					});
					
				}
			
				// Ready callback
				o.ready($this);
				
				
				//////////////////////////
				// GO TO SLIDE
				
				function goTo(num,callback){
				
					if( !mooseBan && num != c ){
					
						// Ban that bad moose!
						mooseBan = true;
					
						// If we have string, it's next or previous
						if( typeof num === 'string' ){
						
							// Add class for spin
							num == 'next' ? $swin.addClass('flip_right') : $swin.addClass('flip_left');
						
							// Increase or decrease current
							num = num === 'next' ? c + 1 : c - 1;
							
							// Keep it within range
							if( num > total ){
								num = 1;
							}else if( num < 1 ){
								num = total;
							}
						
						}else{
						
							// Add class for spin
							num > c ? $swin.addClass('flip_right') : $swin.addClass('flip_left');
						
						}
						
						// Get new and old
						
						var $new = $slide[num-1];
						var $old = $slide[c-1];
						
						// Are we using 3d?
						if( $('html').hasClass('webkit') ){
						
							$old.addClass('old');
							
							$new.prependTo($swin).addClass('new').bind({
							
								'webkitAnimationEnd':	function(){
									
									$new.removeClass('new').unbind('webkitAnimationEnd');
									
									done();
									
								}
							});
							
						}else{
						
							// Out with the old! ( -1 on these because the $slide array index is 0 )
							var oldX = $swin.hasClass('flip_right') ? 0 - w : w;
							var newX = $swin.hasClass('flip_right') ? w : 0 - w;
							
							$old.animate({
								'margin-left':	oldX
							},600,'easeInOutExpo',function(){
							
								done();
								
							});
							
							// In with the new!
							$new.prependTo($swin).css({
								'margin-left':	newX
							}).animate({
								'margin-left':	0
							},600,'easeInOutExpo');
						
						}
						
						// We have a new current slide! Well done!
						c = num;
						
						// If there is a nav
						if( o.nav ){
						
							// Remove nav on state
							$nav.find('.on').removeClass('on');
							
							// Add on state
							$nav.find('a[href=#' + c + ']').addClass('on');
							
						}
						
						// Once animating is complete
						function done(){
						
							// Strip left or right classes
							$swin.removeClass('flip_right flip_left');
							
							// Remove the old slide
							$old.removeClass('old').remove();
						
							// Moose can come back in now
							mooseBan = false;
							
							// Callback
							if( callback ) callback.apply($this);
						
						}
					
					}
				
				}
				
				
				//////////////////////////
				// AUTO SLIDE
				
				if( o.auto ){
				
					// The repeating function
					function auto(){
						
						// Get the pause data from the side, if there is any
						var sp = $slide[c-1].data().pause;
						
						// If there is, set that as the pause period, else use the pause value from settings
						var p = sp == undefined ? o.pause : sp;
					
						// Set the timeout function
						pause = setTimeout(function(){
							
							// Go to the next slide
							goTo('next',function(){
							
								// Fire the auto function again on callback - we have to use this method as tabs save processing power by not performing animations off screen
								auto();
							
							});
							
						},p*1000);
					
					}
				
				
					// Detect hover
					$this.bind({
						'mouseenter':	function(){
							
							// Clear the pause timer
							clearTimeout(pause);
							
						},
						'mouseleave':	function(){
							
							// Start the timer again
							auto();
							
						}
					});
				
					// FIRE!
					auto();
				
				}
			
			}
			
		});
		
	};


	//////////////////////////
	// FORM VALIDATION	

	$.fn.validate = function(settings) {
	
		// Settings
		var defaults = {
			'errorMsg':		'<h5>Oops&hellip;</h5><p>It looks like we&rsquo;re missing a few details! Please fill in any marked fields and try again.</p>',
			'ajax':   		false
		};
		
		
		// o variable for settings
		var o = $.extend(defaults, settings);
		
		
		// For each form (not that there will ever be more than one...)
		return this.each(function(){
	
			// Objects
			var $form = $(this);
			var $error;
			var fresh = true;
			
			
			// Variables
			var error = false;
			
			
			// SIMPLE TEXT FIELD
			$form.find('input, textarea').blur(function(){
			
				var $t = $(this);
				
				// Is this a fresh form?			
				if( !fresh && $t.required() ){
				
					var val = $(this).val();
					var len = val.length;
					
					if( len < 3 || val == $(this).attr('placeholder') ){
						$t.error();
					}else{
						$t.valid();
					}
				
				}
				
			});
			
			
			// FULL NAME
			$form.find('#giraffe_name').unbind('blur').blur(function(){
			
				var $t = $(this);
				
				// Is this a fresh form?			
				if( !fresh && $t.required()  ){
	
					var val = $t.val();
					var name = val.search(/^([a-zA-Z'-]+\s+){1,4}[a-zA-z'-]+$/);
					
					if( name < 0 ){
						$t.error();
					}else{
						$t.valid();
					}
				
				}
				
			});
			

			// SIMPLE SELECTS - Making sure to still target ie6
			$form.find('.field > .select select, .field > select').live('change blur',function(){

				var $s = $(this);

				// Is this a fresh form?			
				if( !fresh && $(this).required() ){
				
					if( $s.checkSelect() ){
					
						$s.error();
						
					}else{
					
						$s.valid();
						
					}
				
				}
				
			});


			// JOINED SELECTS
			$form.find('.field > .join_select select[data-required]').live('change blur',function(){

				// Is this a fresh form?			
				if( !fresh ){
		
					var $s = $(this);
					var required = $s.required();
					
					if( $s.checkSelect() && required ){
					
						$s.error();

					}else{

						if( $s.closest('.join_select').find('select').checkSelect() && required ){
							
							$s.error();
							
						}else{
							
							$s.valid();
							
						}
						
					}
				
				}
				
			});

			
			// CHECK SELECT
			$.fn.checkSelect = function(){
			
				var error = 0;
				
				this.each(function(){
				
					var $this = $(this);
					var val = $this.val();
					
					error += val == $this.children('option:first').val() || val == $this.children('option[disabled]').val() ? 1 : 0;
					
				});
				
				error = error > 0;
				
				return error;
				
			}
			
			
			// EMAIL
			$form.find('input[type=email]').blur(function(){
			
				// Is this a fresh form?			
				if( !fresh ){
		
					var $i = $(this);
					var val = $i.val();
					var required = $i.required();
					var email = checkemail( $i.val() ) ? true : false;
					
					if( !email && required || ( val.length > 0 && !email ) ){
						$i.error();
					}else if( email || ( val.length == 0 && !required ) ){
						$i.valid();
					}
				
				}
				
			});
			
			
			// PHONE NUMBER
			$form.find('input[type=tel]').blur(function(){
		
				// Is this a fresh form?			
				if( !fresh ){
		
					var $i = $(this);
					var ph = $i.attr('placeholder');
					var val = $(this).val();
					var pn = checkphone( val );
					var mn = checkMphone( val );
					
					if( ( val != ph && val != '' ) && ( ( pn == false || pn == null ) && ( mn == false || mn == null ) ) ){
						$i.error();
					}else if( val != ph ){
						$i.valid();
					}else if( ( val == ph || val == '' ) && !$i.required() ){
						$i.parent('.field').removeClass('valid error').find('.error').remove();
					}
				
				}
				
			});
			
			
			// POST CODE
			$form.find('#giraffe_postcode').unbind('blur').blur(function(){
			
				// Is this a fresh form?			
				if( !fresh ){
		
					var $i = $(this);
					var r = $i.required();
					var ph = $i.attr('placeholder');
					var val = $(this).val();
					var emp = val == '' || val == ph;
					var pc = checkPost( val );
					
					if( ( r && emp ) || ( !r && !emp && !pc ) ){
						$i.error();
					}else if( ( !r && emp ) || pc ){
						$i.valid();
					}
				
				}
				
			});
			
			
			// CHECK REQUIRED
			$.fn.required = function(){

				return $(this).data('required') == '';

			}
			
			
			//////////////////////////
			// SUBMIT
			
			$form.submit(function(e){
				
				// No longer fresh as a daisy, so live error checking time!
				fresh = false;
				
				// Go through and validate the required fields
				$form.find('input:visible, textarea:visible, select:visible').blur();
				
				// Find visible errors (the ones hidden can be presumed uninteresting)
				if( $form.find('.error:visible').length != 0 ){
				
					if(!o.ajax){
												
						// Scroll to the top of the form
						$.scrollTo({
							'target':	$form,
							'offset':	-20,
							'after':	function(){

								// Only do this bit if there is no error currently
								if( !error ){

									// Error is now true
									error = true;

									// Error message
									$error = $('<div/>',{
										'class':	'error_message',
										'html':		o.errorMsg,
										'css':		{
											'display':	'none',
											'opacity':	0
										}
									}).insertAfter($form.find('.intro:first')).slideDown(600,'easeInOutExpo').animate({
										'opacity':	1
									});

								}else{

									var s = 50;
									var e = 'easeInOutExpo';

									$error.animate({
										'left':	-2
									},s,e).animate({
										'left':	2
									},s,e).animate({
										'left':	-2
									},s,e).animate({
										'left':	2
									},s,e).animate({
										'left':	-2
									},s,e).animate({
										'left':	2
									},s,e).animate({
										'left':	-2
									},s,e).animate({
										'left':	0
									},s,e);

								}

							}
						});
						
					}				
					
					// STOP RIGHT THERE!
					e.preventDefault();
					
				}else if(o.ajax){
					
					e.preventDefault();
					
					o.ajax.call();
					
				}
				
			});
		
		});
		
		//////////////////////////
		// REGEX'S
		
		function checkemail(email_address) {
			return email_address.length > 5 && email_address.match(/^((([A-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([A-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([A-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([A-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([A-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([A-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([A-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([A-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([A-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([A-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/);
		}
		
		function checkphone(phone_number) {
			return phone_number.length > 9 && phone_number.match(/^(\(?(0|\+44)[1-9]{1}\d{1,4}?\)?\s?\d{3,4}\s?\d{3,4})$/);
		}
		
		function checkMphone(phone_number) {
			return phone_number.length > 9 && phone_number.match(/^((0|\+44)7(5|6|7|8|9){1}\d{2}\s?\d{6})$/);
		}
		
		function checkPost(post_code) {
			var postcodeRegEx = /[A-Z]{1,2}[0-9]{1,2} ?[0-9][A-Z]{2}/i;
			return postcodeRegEx.test(post_code);
		}
		
	};
	
	
	//////////////////////////
	// ERROR AND VALID
	// Used on various forms
	
	$.fn.error = function() {
	
		var $this = $(this);
		
		var $f = $this.closest('.field');
		
		if( !$f.hasClass('error') ){
		
			var error = $f.data('error');
			
			if( error == undefined ) error = 'Please complete this field';
			
			$f.addClass('error').removeClass('valid');
			
			var $error = $('<p/>',{
				'class':	'error',
				'html':		error
			}).appendTo($f);
			
			$f.bind({
				'mouseenter':	function(){
				
					$f.addClass('hover');
					
					$error.css({
						'display':		'block',
						'margin-top':	18,
						'opacity':		0
					}).animate({
						'margin-top':		12
					},{
						'queue':			false,
						'duration':			400,
						'specialEasing':	{
							marginTop:		'easeOutBounce'
						}
					});
				
					$error.animate({
						'opacity':			1
					},{
						'queue':			false,
						'duration':			200
					});
					
				},
				'mouseleave':	function(){
				
					$f.removeClass('hover');
					
					$error.css({
						'margin-top':	18,
						'opacity':		0
					}).hide();
					
				}
			});
			
		}
	};
	
	$.fn.valid = function() {
		var $f = $(this).closest('.field');
		$f.addClass('valid').unbind('mouseenter mouseleave').removeClass('error').find('.error').remove();
	};

})(jQuery);


//////////////////////////
// EASING

jQuery.extend( jQuery.easing,{
	easeInOutExpo: function (x, t, b, c, d){
		if (t==0) return b;
		if (t==d) return b+c;
		if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
		return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
	},
	easeInExpo: function (x, t, b, c, d) {
		return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
	},
	easeOutExpo: function (x, t, b, c, d) {
		return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
	},
	easeInBack: function (x, t, b, c, d, s) {
		if (s == undefined) s = 1.70158;
		return c*(t/=d)*t*((s+1)*t - s) + b;
	},
	easeOutBack: function (x, t, b, c, d, s) {
		if (s == undefined) s = 1.70158;
		return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
	},
	easeOutBounce: function (x, t, b, c, d) {
		if ((t/=d) < (1/2.75)) {
			return c*(7.5625*t*t) + b;
		} else if (t < (2/2.75)) {
			return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
		} else if (t < (2.5/2.75)) {
			return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
		} else {
			return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
		}
	},	
	easeOutQuad: function (x, t, b, c, d) {
		return -c *(t/=d)*(t-2) + b;
	},
	easeInOutQuad: function (x, t, b, c, d) {
		if ((t/=d/2) < 1) return c/2*t*t + b;
		return -c/2 * ((--t)*(t-2) - 1) + b;
	}
});


//////////////////////////
// GOOGLE STUFF

var _gaq = _gaq || [];
	
_gaq.push(
	['analytics1._setAccount', 'UA-3530095-62'],
	['analytics1._trackPageview']
);

(function() {
	var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
	ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
	var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();


//////////////////////////
// TWITTER WEB INTENTS

(function(){

	if( window.__twitterIntentHandler ) return;

	var intentRegex = /twitter\.com(\:\d{2,4})?\/intent\/(\w+)/,
			windowOptions = 'scrollbars=yes,resizable=yes,toolbar=no,location=yes',
			width = 550,
			height = 420,
			winHeight = screen.height,
			winWidth = screen.width;
 
	function handleIntent(e) {
		e = e || window.event;
		var target = e.target || e.srcElement,
				m, left, top;
 
		while (target && target.nodeName.toLowerCase() !== 'a') {
			target = target.parentNode;
		}
 
		if (target && target.nodeName.toLowerCase() === 'a' && target.href) {
			m = target.href.match(intentRegex);
			if (m) {
				left = Math.round((winWidth / 2) - (width / 2));
				top = 0;
 
				if (winHeight > height) {
					top = Math.round((winHeight / 2) - (height / 2));
				}
 
				window.open(target.href, 'intent', windowOptions + ',width=' + width + ',height=' + height + ',left=' + left + ',top=' + top);
				e.returnValue = false;
				e.preventDefault && e.preventDefault();
			}
		}
	}
 
	if (document.addEventListener) {
		document.addEventListener('click', handleIntent, false);
	} else if (document.attachEvent) {
		document.attachEvent('onclick', handleIntent);
	}
	window.__twitterIntentHandler = true;
	
}());

