var map, geocoder, markers, currentWindow = false, searchMarker, searchIndex, featured = false;

$(document).ready(function(){

	findFeatured();

	map			= showMap();
				   
	markers		= showMarkers(map);
	geocoder	= setupGeocoder();
	
	searchIndex = getSearchIndex();
	
	google.maps.event.addListener(map, 'click', mapClick);
	//google.maps.event.addListener(map, 'tilesloaded', 	);
	
	
	setupSwfAddress();
	
	showFeatured();
	
	findUser();
	
});
 
/*----------------- SHOW THE GOOGLE MAPS ----------------- */



function showMap(){
	var latlng = mkLatLng(54,-3.119648);
    var myOptions = {
      zoom: 6,
	  disableDefaultUI: true,
	  navigationControl: true,
	  navigationControlOptions: google.maps.NavigationControlStyle.SMALL,
      center: latlng,
      mapTypeId: google.maps.MapTypeId.ROADMAP
    };
    var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
	positionMap();
	$(window).resize(positionMap);
	
	return map;
}

function positionMap(){
	//Position to 15 px down, fitting full screen
	var t = 20;
	var h = $(window).height();
	var m = $('#map_canvas');
	m.height(h-t);
	m.css({top:t});	
}

function mkLatLng(lat,long){
	return new google.maps.LatLng(lat,long);
}

function findUser(){
	if (typeof(navigator.geolocation) != 'undefined') {
		navigator.geolocation.getCurrentPosition(function(position) {
			var lat = position.coords.latitude;
			var lng = position.coords.longitude;
			var position = new google.maps.LatLng(lat, lng);
			//changeAddress('menu/nearest');
			//foundNearest(position,(SWFAddress.getPath()!="/"));
		});	
	}
}

function findFeatured(){
	var f = $('#featured');
	if(!f || f.length == 0) return false;
	var id = f.attr('data-locationID');
	featured = id;
}

function showFeatured(){
	if(map && featured !== false) urlForward('#/');
	//showLocation(id)
}

/*----------------- ADD THE MARKERS -------------------- */

function showMarkers(){
	var markers = new Array();
	for(var i = 0 ; i < locations.length; i++){
		markers.push(marker(i));
	}
	return markers;
}


function marker(i){
	var s = locations[i];
	
	var m = new Array();
	m.id = i;
	
	var mark = new google.maps.Marker({
		map: map,
		position: mkLatLng(s['latitude'],s['longitude']),
		title: s['name']
	});
	
	var infowindow = new google.maps.InfoWindow({
   		content: '<div class="infowindow">'
		+	"<h2>" + s['name'] + "</h2>"
		+	"<h3>" + s['sub_location'] + (s['sub_location'] ? ', ' : '') + s['location'] + "</h3>"
		+	"<h4><a href='#' onclick='return showLocation(" + i + ",true)'>(zoom here)</a></h4>"
		
		+	"<div class='info_left'>"
		+	"<p>" + s['address']
		+	"<br />" + s['postcode']
		+	"</p></div><div class='info_right'>"
		+	"<p>" + s['phone_number']
		+	"</p>"
		+	"</div>"
		+	"</div>"
	});
	
	m.open = false;
	
	google.maps.event.addListener(mark, 'click', function() {
		if(currentWindow == i) changeAddress('close');
		else changeAddress(id2name(i))
	});
	
	m.marker = mark;
	m.infowindow = infowindow;
	
	return m;
}

function toggleInfoWindow(id){
	if(markers[id].open) closeInfoWindow(id);
	else openInfoWindow(id);
}

function showLocation(id,reposition){
	var latLng = markers[id].marker.getPosition();
	if(reposition || !inBounds(latLng.lat(),latLng.lng())){
		map.setCenter(latLng);
		map.setZoom(16);
	}
	openInfoWindow(id);	
	return false;
}

function openInfoWindow(id){
	
	if(id === false) return false;
	
	var mark 		= markers[id].marker;
	var infowindow 	= markers[id].infowindow;
	if(currentWindow !== false) closeInfoWindow(currentWindow); 
	
	infowindow.open(map,mark);
	currentWindow = id;
	markers[id].open = true;
	google.maps.event.addListener(infowindow, 'closeclick', function() {
		changeAddress('close');
	});
	
}

function closeInfoWindow(id){
	
	if(id === false) return false;
	
	var mark 		= markers[id].marker;
	var infowindow 	= markers[id].infowindow;
	
	infowindow.close(map,mark);
	currentWindow = false;
	markers[id].open = false;
}


/*------------------ SwfAddress --------------------- */


function setupSwfAddress(){

	var addressChange = function(e){
		//Get parts
		var parts = e.value.split('/');
		var p0 = parts[1];
		var p1 = parts[2];
		var p2 = parts[3];

		//If it's blank
		if(p0 == ''){
			closeInfoWindow(currentWindow);
			showUK();
			return true;	
		}
		
		//Menus
		if(p0 == 'menu' && p1 == "close"){
			closeMenu();
			return true;
		}
		
		if(p0 == 'menu' && !p2){
			openMenu(p1);
			return true;
		}
		
		//Locations
		if(p0 == "UK")	return showUK();
		else if(p0 == "Tadcaster") return showTadcaster();
		else if(p0 == "London") return showLondon();


		//Searches
		if(p0 == "search"){
			if(p1 == 'clear') clearSearchResults();
			return true;
		}

		//Nearest
		if(p0 == "nearest"){
			if(p1 == 'clear') clearNearestResults();
			else if(p1) findNearest(unescape(p1));	
			return true;
		}


		//Find if it's a pub to show
		for(var i in locations){
			var p = locations[i]; 
			if(p.path == p0){

				if(p1 && p2) clickSearchResults(markers[i].id,p1,p2);
				else showLocation(markers[i].id,p1 ? p1 : false);	
				return true;
			}
		}
		//Close an info window
		if(p0 == 'close'){
			closeInfoWindow(currentWindow);
			return true;
		}

	}
	
	SWFAddress.addEventListener(SWFAddressEvent.CHANGE, addressChange);
	
}

function id2name(id){
	return locations[id].path;
}

function name2id(name){
	for(var i in locations){
		var l = locations[i]; 
		if(l.path == name){
			return markers[i].id;
		}
	}
}

function changeAddress(address){
	window.location.href = "#/" + address;
	return false;
}



/*------------------ GENERAL ------------------------- */

function clearDefault(input,str){
	if(input.value == str) input.value = '';
}

function urlForward(){
	var h = window.location.href
	var l = h.substr(h.length-1,h.length);
	if(l == "/") h = h.substr(0,h.length-1);
	var base	= h.substr(0,h.lastIndexOf('/')+1);
	var content = h.substr(h.lastIndexOf('/')+1);
	window.location.href=base+'#/'+content;	
}

Number.prototype.toRad = function() { return this * Math.PI / 180; }  // convert degrees to radians
Number.prototype.toDeg = function() { return this * 180 / Math.PI; }  // convert radians to degrees (signed)


/*------------------ SEARCH --------------------------- */

var ignore_words = ['xyz','yyy']//"the","and","a","of"];

function sam_search(query){
	var sr = $('#search_results');
	
	if(query == "") return clearSearchResults();
	
	var results = doSearch(query,true);
	var str = '';
	if(results.length){
		str += '<ul>';
		for(var i in results){
			if(i > 40){
				str += '<li>...</li>';
				break;	
			}
			var id = results[i];
			var l = locations[id];

			str += '<li><a href="#" onclick="return changeAddress(id2name('+id+')+\'/true\')" >'+l['name']+' <em>'+l['location']+'</em></a></li>'
		}
		str += "</ul>";
		if(results.length == 1){
			var id = results[0];
			openInfoWindow(id);
		}
	}else{
		str += '<p><em>no results</em></p>'
	}

	if(str) str += "<p><a href='#' onclick='return changeAddress(\"search/clear\);'>clear search</a></p>";
	sr.html(str);
	sr.slideDown();
	
	return false;
}

function getSearchIndex(){
	var ignore = false;
	var index = new Array();
	for(var i = 0 ; i < locations.length; i++){
		var l = locations[i];
		var words = strToWords(l['name'] + ' ' + l['location'] + ' ' + l['sub_location']);
		for(var j in words){ var word = words[j];
			if(!index[word]) index[word] = new Array();
			index[word].push(i);
		}
	}
	//Sort the index array
	var keys = new Array();
	for(var i in index){
		keys.push(i);	
	}
	keys.sort();
	var index_sorted = new Array();
	for(var i in keys){
		index_sorted[keys[i]] = index[keys[i]];	
	}
	return index_sorted;
}

function strToWords(str){
	var ignore = false;
	var list = new Array();
	var words = str.split(' ');
	for(var j = 0 ; j < words.length ; j++){
		var word = words[j].toLowerCase();
		if(word == '' || word == ' ') continue;
		for(var k in ignore_words) if(ignore_words[k] == word){ ignore = true; break;}
		if(ignore){ ignore = false; continue; }
		list.push(word);
	}
	return list
}

function doSearch(str,exact){
	var words = strToWords(str);
	var matches = new Array();
	for(var j in words){
		var word = words[j];
		matches[j] = new Array();
		for(var k in searchIndex){
			if(k.substr(0,word.length) == word){
				var r = searchIndex[k];
				for(var l in r)	matches[j][r[l]] = true;
			}
		}
	}

	var m = new Array();
	var total = matches.length;
	for(var i in matches){
		for(var j in matches[i]){
			if(!m[j]) m[j] = 1;
			else m[j] ++;
		}
	}
	var results = new Array();
	for(var i in m){
		if(m[i] == total){
			results.push(i);
		}
	}
	
	return results;
	
}


/*------------------ MAIN MENU ---------------------*/

var currentMenu	= false;
var nextMenu	= false;


function showUK(){
	var latLng = mkLatLng(54,-3.119648);
	map.setCenter(latLng);
	map.setZoom(6);
	return false;
}

function showLondon(){
	var latLng = mkLatLng(51.510772,-0.119648);
	map.setCenter(latLng);
	map.setZoom(14);
	return false;
}

function showTadcaster(){
	var latLng = mkLatLng(53.88297997,-1.26370019);
	map.setCenter(latLng);
	map.setZoom(14);
	return false;
	
	
}

function openMenu(name){
	if(name!=currentMenu){
		toggleMenu(name);	
	}
}

function closeMenu(name){
	if(!name) name = currentMenu;
	if(!name) return false;
	if(name == currentMenu){
		toggleMenu(name);
	}
}

function toggleMenu(name){
	nextMenu = false;
	if(!currentMenu){
		currentMenu = name;
		$('#'+name).slideDown('fast');
	}else{
		if(name != currentMenu) nextMenu = name;
		$('#'+currentMenu).slideUp('fast',function(){
			currentMenu = false;
			if(nextMenu) toggleMenu(nextMenu);
		});
		resetMarkers();
	}
	currentMenu = name;
	return false;
}

function clickMenu(name){
	if(name == currentMenu) return changeAddress('menu/close');
	else return changeAddress('menu/'+name);
	//return openMenu(name);
}


/*------------------ GEOCODER ------------------------ */

function setupGeocoder(){
	return new google.maps.Geocoder();
}

function findNearest(address){
	//Clear previous results
	clearNearestResults();
	showNearestLoading();
	if(isValidPostcode(address)){
		var latLng = getLatLngFromPostcode(address)
	}else{
		var latLng = getLatLngFromAddress(address);
	}
	return false;
}

function isValidPostcode(p) {
	var postcodeRegEx = /[A-Z]{1,2}[0-9]{1,2} ?[0-9][A-Z]{2}/i;
	return postcodeRegEx.test(p);
}

function foundNearest(latLng,onlyShow){
	var nr = $('#nearest_results');	
	//We're ready
	if(latLng){
		var lat1 = latLng.lat(), lng1 = latLng.lng();
		var distances = new Array();
		for(var i in locations){
			var lat2 = locations[i].latitude, lng2 = locations[i].longitude;	
			distances[i] = {'id':i,'distance':calcDistance(lat1,lng1,lat2,lng2),'location':locations[i],'marker':markers[i]};
		}
		distances = distances.sort(cmpDistance);	
			
		//Zoom to centre:
		if(!onlyShow) {
			map.setCenter(latLng);
			map.setZoom(17);
		}
		
		if(!searchMarker){
			searchMarker = new google.maps.Marker({
			map: map,
			title: 'Search Location',
			icon: 'images/blue_dot.png'
			});
		}
		searchMarker.setPosition(latLng);
		searchMarker.setVisible(true);
		
		var list = new Array();
		//Show only a certain amount
		for(var i in distances){
			var d = distances[i];
			var id = d.id;
			var l = locations[id];
			var m = d.marker;
			var show = (i < 4 || d.distance < 10);
			if(show){
				list.push({'id':id,'name':l.name,'distance':Math.round(d.distance*10)/10});	
			}
			
			//Show the first few
			if(!onlyShow){
				if(i == 0){
					//var bounds = new google.maps.LatLngBounds(latLng,latLng);
					//bounds.extend(m.marker.getPosition());
					//map.fitBounds(bounds);
					var selected = id;
					//openInfoWindow(id);
					m.marker.setVisible(true);
				}else if(show){		
					m.marker.setVisible(true);
				}else{
					m.marker.setVisible(false);
				}
			}
		}

		if(!onlyShow) clickSearchResults(selected,latLng.lat(),latLng.lng());
		
		var str = '<ul>';
		for(var i in list){
			var l = list[i];
			str += '<li><a href="#" onclick="return changeAddress(\''+id2name(l.id)+'/'+ latLng.lat() +'/'+ latLng.lng() +'\');" >'+l['name']+' <em>'+l['distance']+' miles</em></a></li>'
		}
		str += "</ul>";
		str += "<p><a href='#' onclick='return changeAddress(\"nearest/clear\")' >clear results</a></p>";
		nr.hide();
		nr.html(str);
		nr.slideDown();
	}
	
	return false;
}

function foundNearestError(){
	var nr = $('#nearest_results');	
	nr.html('<p>Cannot perform search. Please try again later.</p>');	
}

function foundNearestNone(){
	var nr = $('#nearest_results');	
	nr.html('<p>Location not found.</p>');	
}

function clickSearchResults(id,searchLat,searchLng){
	//We want to add an extra 10% border to each result, plus the width of the side menu...

	var searchLatLng = mkLatLng(searchLat,searchLng);
	var latLng = markers[id].marker.getPosition();
	var bounds = new google.maps.LatLngBounds(latLng,latLng);
	
	bounds.extend(searchLatLng);
	
	bounds = growBoundsScale(bounds,0.1,0.1,0.1,0.1);
	
	map.fitBounds(bounds); 
	
	var realBounds = map.getBounds();
	
	var neLatLongReal = realBounds.getNorthEast()
	var swLatLongReal = realBounds.getSouthWest();
	var widthReal = neLatLongReal.lng() - swLatLongReal.lng();
	var heightReal = neLatLongReal.lat() - swLatLongReal.lat();
	var rReal = widthReal/heightReal;
	
	var neLatLong = bounds.getNorthEast()
	var swLatLong = bounds.getSouthWest();
	var width = neLatLong.lng() - swLatLong.lng();
	var height = neLatLong.lat() - swLatLong.lat();
	var r = width/height;
	
	//If our bounds are wider than the screen then increase on right
	//Width Real should be 60% wider than Width
	
	var s = 2.5;
	if(widthReal / width < s){
		bounds = growBoundsScale(bounds,0,s - (widthReal / width),0,0);
	}
	
	//If our marker is at the top and our bounds are taller than the screen, increase on top
	if(r <= rReal){
		if(latLng.lat() > searchLatLng.lat()){
			var s = 2.5;
			bounds = growBoundsScale(bounds,0,0,s - (heightReal / height),0);
		}
	}
	
	map.fitBounds(bounds); 
	openInfoWindow(id);
	
	//Limit the zoominess
	if(map.getZoom() > 17) map.setZoom(17);
	
}

function growBounds(bounds,s){
	return growBoundsScale(bounds,s,s,s,s);	
}

function growBoundsScale(bounds,s1,s2,s3,s4){
	
	var neLatLong = bounds.getNorthEast()
	var swLatLong = bounds.getSouthWest();
	var width = neLatLong.lng() - swLatLong.lng();
	var height = neLatLong.lat() - swLatLong.lat();
	
	var neLatLongNew = mkLatLng((neLatLong.lat()+(s3*height) / 2), (neLatLong.lng()+(s2*width) / 2));
	var swLatLongNew = mkLatLng((swLatLong.lat()-(s4*height) / 2), (swLatLong.lng()-(s1*width) / 2));

	bounds.extend(neLatLongNew);
	bounds.extend(swLatLongNew);
	
	return bounds;
}

function inBounds(lat,lng){
	try{
		var realBounds = map.getBounds();
		
		var neLatLongReal = realBounds.getNorthEast()
		var swLatLongReal = realBounds.getSouthWest();
		var widthReal = neLatLongReal.lng() - swLatLongReal.lng();
		var heightReal = neLatLongReal.lat() - swLatLongReal.lat();
		var rReal = widthReal/heightReal;
		
		if(lat <  neLatLongReal.lat() && lng < neLatLongReal.lng()){
			if(lat > swLatLongReal.lat()  && lat > swLatLongReal.lat()){
				return true;
			}
		}
		return false;
	}catch(err){
		return false;	
	}
}

function clearNearestResults(){
	document.getElementById('nearest_form').address.value = '';
	if(searchMarker) searchMarker.setVisible(false);
	for(var i in markers){
		markers[i].marker.setVisible(true);	
	}
	var nr = $('#nearest_results');	
	nr.slideUp('medium',function(){});
	return false;
}


function showNearestLoading(){
	document.getElementById('nearest_form').address.value = '';
	var nr = $('#nearest_results');	
	nr.html("<p>Loading...</p>");
	//nr.slideUp('medium',function(){});
	return false;
}

function resetMarkers(){
	for(var i in markers){
		markers[i].marker.setVisible(true);	
	}

}

function clearSearchResults(){
	document.getElementById('search_form').query.value = '';
	var nr = $('#search_results');	
	nr.slideUp('medium',function(){});
	return false;
}

function cmpDistance(a,b){
	if ( a.distance < b.distance )	return -1;
	if ( a.distance > b.distance )	return 1;
	return 0;
}

function calcDistance(lat1,lng1,lat2,lng2){
    var d = Math.acos(Math.sin(lat1.toRad())*Math.sin(lat2.toRad()) + Math.cos(lat1.toRad())*Math.cos(lat2.toRad()) * Math.cos(lng2.toRad()-lng1.toRad())) * 3958.75587 ;
	return d;
}

  
function getLatLngFromAddress(address){
	if (geocoder) {
		geocoder.geocode( { 'address': address, 'country':'uk', 'bounds':map.getBounds()}, function(results, status){
			if (status == google.maps.GeocoderStatus.OK) {
				foundNearest( results[0].geometry.location );
			}else if(status == google.maps.GeocoderStatus.ZERO_RESULTS){
				foundNearestNone();
			}else{
				foundNearestError();
			}
		});
	}
}

function getLatLngFromPostcode(postcode){
	$.ajax({
		url: "postcode/"+escape(postcode)+"/",
		dataType:'json',
		success: function(result){
			if(result.error){
				getLatLngFromAddress(postcode);
			}else{
				var latLng = mkLatLng(result.lat,result.lng);
				foundNearest(latLng);
			}
			
		},
		error: function(msg){
			getLatLngFromAddress(postcode);
		}
	});
	
}


/*----------------------- COORDINATES ------------------------------------ */


function updateCoordinates(evt){
	$('#latLngText').html('Ai: ' + mouseX(evt) + ' ' + mouseY(evt));	
}

function mouseX(evt) {
	if (evt.pageX) return evt.pageX;
	else if (evt.clientX) return evt.clientX + (document.documentElement.scrollLeft ? document.documentElement.scrollLeft :	document.body.scrollLeft);
	else return null;
}
function mouseY(evt) {
	if (evt.pageY) return evt.pageY;
	else if (evt.clientY) return evt.clientY + (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop);
	else return null;
}

function mapClick(e) {
	var lat = jRound(e.latLng.lat(),8);
	var lng = jRound(e.latLng.lng(),8);
	$('#latLngText').html('Latitude: ' + lat.toString() + '<br/>Longitude: ' + lng.toString());	
}

function jRound(n,p){
	var m = 1;
	for(var i = 0; i < p; i++) m *= 10;
	return Math.round(n*m)/m;
	
}


