//------------------------------------
//	LOCATION_PICKER.JS
//	Author: 	Engage Interactive
//	Requires:	jquery 1.5
//				jquery.mousewheel
//				engage.findmynearest
//	Version:	0.1
//------------------------------------

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

(function($){

	//////////////////////////
	// GLOBAL VARIABLES
	
	var pActive = false;
	var mooseBan = false;
	var $html = $('html');
	var $this = null;

	jQuery.fn.location = function (settings){	
		return this.live('click',function(){
		
			// Is click allowed
			if( mooseBan == false ){
				
				// Ban click
				mooseBan = true;
				
				// Do it!
				$.location(settings,$(this));
			
			}
			
			return false;
			
		});
	}

	jQuery.location = function(settings,$this){
	
		// Default options
		
		var defaults = {
			locationsUrl:		'/locations/json',			// Url to the Json feed for locations data
			url:				'/location/[location]',		// Url for the list and search result links to go to. Use [location] for placeholder.
			scrollList:			true,						// Replace the standard overflow auto box with a custom javascript scroll bar 
			scrollInertia:		true,						// Use inertia for the scroll
			scrollSpeed:		30,							// Scrolling speed
			magicScrollSpeed:	1,							// Scrolling speed for the magic mouse (or other inertia based mice)
			overlayClose:		true,						// Clicking the overlay will close the location picker
			overlayOpacity:		.5,							// Overlay opacity
			cufon:				'#lp_title, .lp_title',		// Which elements are to be styled by cufon? Set to false if cufon is not used
			searchTerm:			false,						// Are we opening with a search?
			no3D:				false,						// Stop webkit 3d effects
			disabledOptions: 	[],							// Array of location slugs to show as disabled
			
			// Callbacks
			beforeShow:			function(){},				// Before it is shown
			afterHide:			function(){},				// After it is hidden

			// HTML Structure and naming conventions
			id:					'location_picker',			// The id for the main container
			prefix:				'lp_',						// The prefix to all unique id's and classes used
			
			// Wording used throughout the location picker
			mainTitle:			'Please choose a restaurant', // The title for the location picker
			intro:				false,						// Underneath the title
			listTitle:			'All our locations',		// The title for the list column
			searchTitle:		'Find your nearest',		// The title for the search column
			searchIntro:		'Find your nearest restaurant by entering a postcode, place name or a landmark.', // The label above the search box
			searchEg:			'e.g. The London Eye',		// The placeholder text for the search box
			searchBtn:			'Go',						// Text for the search button
			searchResults:		'Search results',			// Search results title
			searchDist:			'm',						// The word affixed to the number of miles
			closeText:			'&times;',					// The text for the close button
			closeTitle:			'Cancel',					// The title for the close button
			formWrapperClass: 	'form_wrapper'				// The class to add to the search form 

		};


		// Variables
		var o = $.extend(defaults, settings);
		
		//////////////////////////
		// CREATE PICKER
		
		// TODO: Create the root container and overlay, show those and a loading spinner, then do the rest so that something happens for IE to look at
		// IE6 Doesn't support fixed, so need to do an alternative
		
		jQuery.location.create = function(){
		
			// Callback
			o.beforeShow.apply(this);
		
			// If we already have a picker we just need to change wording
			
			var intro = o.intro === false ? '' : '<p id="' + o.prefix + 'intro">' + o.intro + '</p>';
			
			if( $('#' + o.id ).length == 0 ){
			
				var html = '<div id="' + o.id + '">\
					<div id="' + o.prefix + 'body">\
						<a href="#" title="' + o.closeTitle + '" id="' + o.prefix + 'close">' + o.closeText + '</a>\
						<span id="' + o.prefix + 'title">' + o.mainTitle + '</span>' + intro + '<div id="' + o.prefix + 'search">\
							<form id="' + o.prefix + 'form" class="' + o.formWrapperClass + '"><fieldset>\
								<span class="' + o.prefix + 'title">' + o.searchTitle + '</span>\
								<label for="' + o.prefix + 'search_term">' + o.searchIntro + '</label>\
								<input id="' + o.prefix + 'search_term" name="' + o.prefix + 'search_term" placeholder="' + o.searchEg + '">\
								<button type="submit"><span>' + o.searchBtn + '</span></button>\
							</fieldset></form>\
							<div id="' + o.prefix + 'results">\
								<span class="' + o.prefix + 'title">' + o.searchResults + '</span>\
								<ul></ul>\
							</div>\
							<span id="' + o.prefix + 'loading"></span>\
						</div>\
						<div id="' + o.prefix + 'list">\
							<span class="' + o.prefix + 'title">' + o.listTitle + '</span>\
							<div>\
								<span class="' + o.prefix + 'track"><span></span></span>\
								<ul class="' + o.prefix + 'list_root"></ul>\
							</div>\
						</div>\
					</div>\
					<span id="' + o.prefix + 'overlay"></span>\
				</div>';
				
				// Add the html to the DOM
				$('body').append(html);
				
				// Set up some objects for use later
				$lp = $('#' + o.id );
				$lp_b = $('#' + o.prefix + 'body');
				$lp_o = $('#' + o.prefix + 'overlay');
				$lp_l = $('#' + o.prefix + 'list ul');
				$lp_f = $('#' + o.prefix + 'form');
				$lp_r = $('#' + o.prefix + 'results');
				
				// Some wording that might change
				$lp_mt = $('#' + o.prefix + 'title');
				$lp_lt = $('#' + o.prefix + 'list .' + o.prefix + 'title');
				$lp_st = $('#' + o.prefix + 'search form .' + o.prefix + 'title');
				$lp_si = $('#' + o.prefix + 'search label');
				$lp_sp = $('#' + o.prefix + 'search input');
				
			}else{
			
				// Do we need to change any wording?
				if( o.intro === false ){
					$('#' + o.prefix + 'intro').remove();
				}else{
					$('#' + o.prefix + 'intro').remove();
					$('<p id="' + o.prefix + 'intro">' + o.intro + '</p>').insertAfter($lp_mt);
				}
				
				// Titles
				if( $lp_mt.text() != o.mainTitle ) $lp_mt.html( o.mainTitle );
				if( $lp_lt.text() != o.listTitle ) $lp_lt.html( o.listTitle );
				if( $lp_st.text() != o.searchTitle ) $lp_st.html( o.searchTitle );
				if( $lp_st.text() != o.searchTitle ) $lp_st.html( o.searchTitle );
				
				// Other bits
				if( $lp_si.text() != o.searchIntro ) $lp_si.html( o.searchIntro );
				if( $lp_sp.attr('placeholder') != o.searchEg ) $lp_sp.attr('placeholder', o.searchEg );
			
			}
			
			// Add in the locations
			$.getJSON(o.locationsUrl, function(locations) {

				var list = '';
				var fresh = true;
				var disabled = '';
				
				for( var i in locations ) {
					
					// London or not London
				    if( locations[i].name == undefined ){
						for( var l in locations[i] ){
							if( fresh == true ){
								list = list + '<li class="' + o.prefix + 'group_title">London</li>';
								fresh = false;
							}
							
							// Disabled?
							disabled = '';
							if(o.disabledOptions.length) {
								if($.inArray(locations[i][l].slug, o.disabledOptions) >= 0) {
									disabled = 'disabled';
								}
							}
							
							list = list + '<li class="' + o.prefix + 'group ' + disabled + '"><a href="' + o.url.replace('[location]',locations[i][l].slug) + '" title="View the ' + locations[i][l].name + ' location page">' + locations[i][l].name + '</a></li>';
						}
					}else{
						
						// Disabled?
						disabled = '';
						if(o.disabledOptions.length) {
							if($.inArray(locations[i].slug, o.disabledOptions) >= 0) {
								disabled = 'disabled';
							}
						}
						
						list = list + '<li class="' + disabled + '"><a href="' + o.url.replace('[location]',locations[i].slug) + '" title="View the ' + locations[i].name + ' location page">' + locations[i].name + '</a></li>';
					
					}

				}
				
				$lp_l.html(list).find('li.' + o.prefix + 'group:last').addClass('last');
				
				// Disable clicks on disabled links
				if(o.disabledOptions.length) {
					$lp_l.find('.disabled a').css({opacity: '0.4'}).live('click', function(e) {
						e.preventDefault();
					});
				}
		
			});
			
			// Are we using cufon?
			if( o.cufon != false ) Cufon.replace(o.cufon);
			
			// Add close clicks
			$('#' + o.prefix + 'close, #' + o.prefix + 'overlay').bind('click',function(e){
				if( o.overlayClose || $(this).attr('id') != o.prefix + 'overlay' ){
					jQuery.location.hide();
				}
				e.preventDefault();
			});
						
			$.location.show();
		}


		//////////////////////////
		// SHOW

		jQuery.location.show = function(){
		
			$lp.show();
			
			// Hide flash
			var $live = $('#LivebookingsDirect');
			if( $live.length != 0 ){
				$live.data('style',$live.attr('style')).css({
					'height':	0,
					'overflow':	'hidden'
				});
			}
			
			// Hide selects if ie6
			if( $('html').hasClass('ie6') ){
				$('select').css({
					'margin-left':	'-9999px'
				});
			}
			
			// Once it's shown, do this
			var activate = function(){

				// Setup the search
				activateSearch();
				
				// If we are using the scroller, activate that
				if( o.scrollList == true ) activateList();
				
				// If we have a search term, use it
				if( o.searchTerm !== false ){
					$lp_sp.val(o.searchTerm);
					$lp_f.submit();
				}else{
					$lp_sp.focus();
				}
			
				// Unban the mouse
				mooseBan = false;
			}
		
			var showListener = function(event){
			
				$lp_b.unbind('webkitAnimationEnd');
				
				activate();
				
			}
			
			if( $html.hasClass('ie6') || $html.hasClass('ipad') ){
			
				$lp_o.css({
					'height':	$(document).height(),
					'opacity':	o.overlayOpacity
				});
				
				$('html,body').animate({
					'scrollTop': 0
				},1000,'easeInOutExpo');
				
			}
			
			$lp_o.fadeTo(200,o.overlayOpacity,function(){
			
				var h = $lp_b.outerHeight();
				var y = Math.round( ( $(window).height() - h ) / 2 );
			
				if( $html.hasClass('webkit') && o.no3D == false ){
				
					$lp_b.css({
						'top':			'50%',
						'margin-top':	0 - Math.round( h / 2 )
					}).bind({
						'webkitAnimationEnd':	showListener
					});
				
					$lp.addClass('show');
					
				}else{
				
					$lp_b.show().css({
						'top':			0 - ( h + 50 ),
						'margin-top':	0
					}).animate({
						'top':	y
					},400,'easeOutExpo',function(){
						
						activate();
						
						$lp_b.css({
							'top':			'50%',
							'margin-top':	0 - Math.round( h / 2 )
						});
						
					});
				
				}
			
			});
		
		}
		
		
		//////////////////////////
		// ACTIVATE SEARCH
		
		var activateSearch = function(){

			var $error;
			var error = false;
			var result = false;
			
			var message = function(html){

				// Do we need to create the error div?
				if( $('#' + o.prefix + 'error').length == 0 ){
				
					$error = $('<div/>',{
						'id':		o.prefix + 'error',
						'html':		'<div class="alert">' + html + '</div>'
					}).appendTo('#' + o.prefix + 'search').hide().fadeIn(200);
					
				}else{
				
					$error.fadeOut(100,function(){
						$(this).html('<div class="alert">' + html + '</div>').fadeIn(200);
					});
					
				}
				
				$lp.removeClass('loading');
				
				searchBan = false;
				result = false;
				error = true;
				
			}

			// Unbind the previous submit, and apply another so that we use current settings
			$lp_f.unbind('submit').submit(function(e){

				// Disable if in the middle of search or Google Maps not loaded
				if(searchBan || !googleMapsEnabled) return false;
				else searchBan = true;
				
				// Set a delay if we already have a result or an error
				if( error || result ){
				
					if( error ) $error.fadeOut(100);
					if( result ) $lp_r.fadeOut(100);
					
					var delay = 150;
					
				}else{
				
					var delay = 0;
				
				}
				
				setTimeout(function(){
					if( searchBan ) $lp.addClass('loading');
				},300);
				
				setTimeout(function(){
				
					// Start search
					findMyNearest($lp_sp.val(), {
						dataSource: '/locations/json_full',
						searchTotal: 4,
						logger: true,
						loggerUrl: '/locations/logfindmynearest',
						onBlank: function() {
							message('<h4>Oops&hellip;</h4><p>To find your nearest you need to enter a search term. Why not try:</p><ul><li>A full UK postcode</li><li>A UK city, town or village</li><li>UK landmark (e.g. Big Ben)</li></ul>');
						},
						onNoResult: function() {
							message('<h4>Sorry, no results&hellip;</h4><p>Why not try searching using one of the following:</p><ul><li>A full UK postcode</li><li>A UK city, town or village</li><li>UK landmark (e.g. Big Ben)</li></ul>');
						},
						onLondon: function() {
							message('<h4>Sorry&hellip;</h4><p>We have many restaurants in London so please be a bit more specific.</p><p>For example, try entering a London suburb such as &lsquo;Islington&rsquo;.</p>');
						},
						onResult: function(results) {
							
							var html = '';
							var disabled = '';
							result = true;
							error = false;
							
							$lp.removeClass('loading');
							
							for(var key in results) {
								
								// Disabled?
								disabled = '';
								if(o.disabledOptions.length) {
									if($.inArray(results[key].slug, o.disabledOptions) >= 0) {
										disabled = 'disabled';
									}
								}
								
								html += '<li class="' + disabled + '"><a href="' + o.url.replace('[location]',results[key].slug) + '">' + results[key].name + ' <small>' + results[key].distance + ' ' + o.searchDist + '</small></a></li>';
								
							}
							
							$lp_r.fadeIn().find('ul').empty().append(html);
							
							// Disable clicks on disabled links
							if(o.disabledOptions.length) {
								$lp_r.find('.disabled a').css({opacity: '0.4'}).live('click', function(e) {
									e.preventDefault();
								});
							}
							
							searchBan = false;
							
						}
					});
				
				},delay);
								
				e.preventDefault();
				
			});
			
		}
		
		
		//////////////////////////
		// ACTIVATE SCROLLING
		
		var activateList = function(){

			// Objects
			var $g = $lp_l.parent().find('.' + o.prefix + 'track span');
			
			// Variables
			var drag = false;
			var scrollDrag = false;
			var vH = $lp_l.parent().outerHeight(true);
			var cH = $lp_l.height();
			var gH = Math.round( ( vH * vH ) / cH );
			
			// Quickly set min height
			if( gH < 40 ) gH = 40;
			
			var maxGY = vH - gH;
			var maxCY = vH - cH;
			
			if( $html.hasClass('ipad') === false ){
			
				//console.log('Viewport height: ' + vH + ' Content height: ' + cH + ' Grip height: ' + gH + ' Max grip Y: ' + maxGY );
				
				// Don't bother if it's not a long list
				if( cH > vH ){
	
					// Set height of grip
					$g.css({
						'height': gH
					}).parent().fadeIn(100);
					
					$g.mousedown(function(e){
		
						scrollDrag = true;
						
						//$lp_b.noSelect();
						
						var startY = e.pageY;
						var contentY = $lp_l.parent().offset().top;
						var gripY = $g.offset().top;
										
						$(document).bind({
						
							mousemove: function(e){
								
								// Work out position of grip
								var y = ( e.pageY - contentY ) - ( startY - gripY );
								
								// Stop it from going too far
								if( y > maxGY ){
									y = maxGY;
								}else if( y < 0 ){
									y = 0;
								}
								
								// Set the position
								$g.css({
									'top': y
								});
								
								//NewValue = (((OldValue - OldMin) * (NewMax - NewMin)) / (OldMax - OldMin)) + NewMin
								
								// Move the list to the correct position
								$lp_l.css({
									'top': 0 - ( ( y * ( cH - vH ) ) / maxGY )
								});
								
								// Stop selecting stuff
								
								return false;
								
							},
							mouseup: function(){
								$(document).unbind('mousemove');
							}
						
						});
						
						e.preventDefault();
					
					});
					
				}
				
				
				// Mousewheel
				
				$lp_l.parent().bind('mousewheel', function(event, delta) {
					
					// Get the velocity
					vel = Math.abs(delta) * o.scrollSpeed;
					
					if( vel > 200 && $('html').hasClass('safari') && !$('html').hasClass('chrome') ) o.scrollSpeed = o.magicScrollSpeed;
					
					// Current position
					var y = $lp_l.position().top;
					
					// Get direction
					y = delta > 0 ? y + vel : y - vel;
					
					// Stop it from going too far
					if( y < maxCY ){
						y = maxCY;
					}else if( y > 0 ){
						y = 0;
					}
					
					// Set the list position
					$lp_l.css({
						'top': y
					});
					
					// Set the scroll wheel position
					$g.css({
						'top': ( y * maxGY ) / maxCY
					});
					
					return false;
				});
				
			}else{
			
				$lp_l.parent('div').swipe({
					triggerOnTouchEnd:	true,	
					swipeStatus:		swipeStatus,
					allowPageScroll:	'none',
					threshold:			50,
					click:				function(event,target){
						var href = $(target).parent('a').attr('href');
						
						if( href != undefined ){
							window.location = href;
						}
					}
				});
				
				var speed = 200;
				var height = $lp_l.parent('div').height();
				var origin;
				var current = 0;
						
				function swipeStatus(event, phase, direction, distance){
				
					//If we are moving before swipe, and we are going Lor R in X mode, or U or D in Y mode then drag.
					
					if( phase == 'start' ){
					
						origin = $lp_l.css('-webkit-transform');
						
						if( origin == 'none' ){
							origin = 0;
						}else{
							origin = origin.replace('matrix(1, 0, 0, 1, 0, ','').replace('-','').replace(')','');
						}
						
					}
					
					if( phase == 'move' && ( direction == 'up' || direction == 'down' ) ){
					
						if( direction == 'up' ){
							scrollList( ( 0 - origin ) - distance, direction);
						}else if( direction == 'down'){
							scrollList( ( 0 - origin ) + distance, direction);
						}
						
						drag = true;
						
					}
					
					if( phase == 'end' ){
					
						if( current > 0 ){
						
							$lp_l.css({
								'-webkit-transition-duration': '.4s',
								'-webkit-transform': 'translate3d(0px,' + 0 + 'px,0px)'
							});
							
						}else if( current < maxCY ){
						
							$lp_l.css({
								'-webkit-transition-duration': '.4s',
								'-webkit-transform': 'translate3d(0px,' + maxCY + 'px,0px)'
							});
							
						}
						
						drag = false;
						
					}
					
				}
				
				// Manually update the position of the imgs on drag
				function scrollList(distance, direction){
				
					// Set duration
					$lp_l.css('-webkit-transition-duration', '.05s');
					
					// Set position
					$lp_l.css({
						'-webkit-transform':	'translate3d(0px,' + distance + 'px,0px)'
					});
					
					current = distance;
					
				}
			
			}
			
		}
		
		
		//////////////////////////
		// HIDE
		
		jQuery.location.hide = function(){
		
			// Clean up
			var deactivate = function(){

				// Hide the location picker
				$lp.hide();
				
				// Remove search results and clear the form
				$lp_sp.val('');
				$lp_r.hide().find('ul').empty();
				$('#' + o.prefix + 'error').remove();
				
				// Show livebookings content
				var $live = $('#LivebookingsDirect');
				if( $live.length != 0 ){
					$live.removeAttr('style').attr('style',$live.data('style'));
				}
				
				// Show selects if ie6
				if( $('html').hasClass('ie6') ){
					$('select').removeAttr('style');
				}
				
				// Callback
				o.afterHide.apply(this);
				
				// Unban the mouse
				mooseBan = false;
			}
			
			if( mooseBan == false ){
				
				mooseBan = true;
				
				if( $html.hasClass('webkit') && o.no3D == false ){
				
					var hideListener = function(event){
						$lp.removeClass('hide');
						
						$lp_o.fadeOut(function(){
						
							deactivate();
							
						});
						
						$lp_b.unbind('webkitAnimationEnd');
					}
		
					$lp.addClass('hide').removeClass('show');
					
					$lp_b.bind({
						'webkitAnimationEnd':	hideListener
					});
				
				}else{
				
					var h = $lp_b.outerHeight();
					var y = Math.round( ( $(window).height() - h ) / 2 );
				
					$lp_b.css({
						'top':			y,
						'margin-top':	0
					}).animate({
						'top':			0 - ( h + 50 )
					},400,'easeInExpo',function(){
					
						$lp_o.fadeOut(function(){
							deactivate();
						});
						
					});
				
				}
				
				// Clear clicks so that we can make way for new settings
				$('#' + o.prefix + 'close, #' + o.prefix + 'overlay').unbind();
				$('#' + o.prefix + 'list a, #' + o.prefix + 'search a').die();
			
			}
		
		}
		
		$.location.create();
		
	};

})(jQuery);
