var map;
var maptype;
var mapid;
var mapdetails;
var osVectorLayer;
var googlemaptypeid = google.maps.MapTypeId.ROADMAP;
var toggling = false;
var osapiloaded = false;
var osapisource = "http://openspace.ordnancesurvey.co.uk/osmapapi/openspace.js";
var osapikey;
var showtitle;
var titlevisible = true;;

var icon_directory = 'images/mapicons/';

var ocmMapType = new google.maps.ImageMapType({
	getTileUrl: function(coord, zoom) {
		return "http://tile.opencyclemap.org/cycle/" +
		zoom + "/" + coord.x + "/" + coord.y + ".png";
	},
	tileSize: new google.maps.Size(256, 256),
	isPng: true,
	alt: "OpenCycleMap layer",
	name: "OSM Cycle",
	maxZoom: 17
});

var osmMapType = new google.maps.ImageMapType({
	getTileUrl: function(coord, zoom) {
		return "http://tile.openstreetmap.org/" +
		zoom + "/" + coord.x + "/" + coord.y + ".png";
	},
	tileSize: new google.maps.Size(256, 256),
	isPng: true,
	alt: "OpenStreetMap layer",
	name: "OSM",
	maxZoom: 18
});

if (!self.os_icons) { os_icons = new Array(); }

$(document).ready(mapOnLoad);


function mapOnLoad() 
{
	$(window).resize(resizemap);
	mapid = $('#mapid').val();
	maptype = $('#maptype').val();
	showtitle = ($('#showmaptitle').val() === "true");
	
	if ($('#osapikey').length > 0) 
	{
		osapikey = $('#osapikey').val();
	}
	else
	{
		setuposicons();
	}

	if	(maptype === 'G' || osapiloaded)
	{
		getmapdetails();		
	}
	else
	{
		LazyLoad.js(osapisource + "?key=" + osapikey, getmapdetails);
	}
}


function getmapdetails()
{
	if	(maptype === 'O')
	{
		setuposicons();
	}

	$.ajax({ type: 'GET', url: 'mapdetails', data: { m: mapid, t: maptype }, dataType: 'json', success: initialiseMap, error: errorHandler}); 
}


function errorHandler(xhr, status)
{
	$('#map').empty().html('<p class="maperrormessage">Sorry, we are currently unable to load this map (' + status + ')</p>');
	$('#map').css('height', '100px');
} 


function initialiseMap(data)
{
	if (data.error !== undefined) 
	{
		if (data.error === 'Not found') 
		{
			window.location.href = getWindowLocation() + '/sorry';
		}
		else 
		{
			$('#map').empty().html('<p class="maperrormessage">' + data.error + '</p>');
			$('#map').css('height', '100px');
		}
		return;
	}
	
	mapdetails = data;
	
	if	(!showtitle)
	{
		mapdetails.showtitle = false;
	}
	
	setupMap();
}	


function setupMap()
{	
	sizes = getAvailableArea();
	
	$("#map").css("height", sizes[1]); 
	
	if (maptype === 'G') 
	{
		map = createGoogleMap("map");
	}
	else
	{
		$("#map").empty(); 
		map = createOSMap("map");
	}
 
 	toggling = false;
 
	$("#maptitle").html(mapdetails.maptitle); 
	document.title = mapdetails.maptitle.replace(/<br\/>/gi, " - ");

	var tablestarted = false;

	var html = "";

	for (var i = 0; i < mapdetails.tracks.length; i++) 
	{
		if	(!tablestarted)
		{
			html += '<table class="trackkey">';
			tablestarted = true;
		}
		
		if	(mapdetails.tracks[i].showonkey)
		{
			html += '<tr class="trackrow"><td class="trackcolour"><div style="background-color: ' + mapdetails.tracks[i].colour + '">&nbsp;</div></td>';
			html += '<td class="tracktext">' + mapdetails.tracks[i].tracktitle;
			
			if	(mapdetails.tracks[i].showdistance)
			{
				html += ' (' + mapdetails.tracks[i].length + 'km)';
			}
			html += '</td></tr>';
		}  
	}  	

	for (var i = 0; i < mapdetails.routes.length; i++) 
	{
		if	(!tablestarted)
		{
			html += '<table class="trackkey">';
			tablestarted = true;
		}

		if	(mapdetails.routes[i].showonkey)
		{
			html += '<tr class="trackrow"><td class="trackcolour"><div style="background-color: ' + mapdetails.routes[i].colour + '">&nbsp;</div></td>';
			html += '<td class="tracktext">' + mapdetails.routes[i].routetitle;
			
			if	(mapdetails.routes[i].showdistance)
			{
				html += ' (' + mapdetails.routes[i].length + 'km)';
			}
			html += '</td></tr>';
		}  
 	}

	if	(tablestarted)
	{
		html.innerHTML += '</table>';
		$("#trackkey").html(html);
	} 	

	resizemap();

	$.ajax({ type: 'GET', url: 'mapwaypointdetails', data: { m: mapid, t: maptype }, dataType: 'json', success: drawPoints, error: errorHandler}); 

	for (var i = 0; i < mapdetails.tracks.length; i++) 
	{
		$.ajax({ type: 'GET', url: 'maproutedetails', data: { r: mapdetails.tracks[i].routeid, t: maptype }, dataType: 'json', success: drawTrack, error: errorHandler}); 
	}
	
	for (var i = 0; i < mapdetails.routes.length; i++) 
	{
		$.ajax({ type: 'GET', url: 'maproutedetails', data: { r: mapdetails.routes[i].routeid, t: maptype }, dataType: 'json', success: drawTrack, error: errorHandler}); 
	}
}


function createGoogleMap()
{
	var mapCentre = new google.maps.LatLng(mapdetails.centrey, mapdetails.centrex);
	var mapOptions = 
	{
		zoom: 4,
		center: mapCentre,
		mapTypeId: googlemaptypeid,
		streetViewControl: true,
		mapTypeControlOptions: 
		{
			style: google.maps.MapTypeControlStyle.DEFAULT,
			mapTypeIds: [google.maps.MapTypeId.ROADMAP, google.maps.MapTypeId.SATELLITE, google.maps.MapTypeId.TERRAIN, google.maps.MapTypeId.HYBRID, "OpenCycleMap", "OpenStreetMap"]
		}			  
	}; 

	var newmap = new google.maps.Map($("#map")[0], mapOptions);
	newmap.mapTypes.set("OpenCycleMap", ocmMapType);
	newmap.mapTypes.set("OpenStreetMap", osmMapType);

	newmap.fitBounds( new google.maps.LatLngBounds(new google.maps.LatLng(mapdetails.miny, mapdetails.minx), new google.maps.LatLng(mapdetails.maxy, mapdetails.maxx)));
	newmap.enableKeyDragZoom();
   	return newmap;
}


function createOSMap()
{
 	var options = {resolutions: [2500, 1000, 500, 200, 100, 50, 25, 10, 5, 2.5, 2, 1]};
	var newmap = new OpenSpace.Map('map', options);
	
	var zoomLevel = newmap.getZoomForExtent(new OpenSpace.MapBounds(mapdetails.mineasting, mapdetails.minnorthing, mapdetails.maxeasting, mapdetails.maxnorthing));
	
	if	(toggling && zoomLevel < 10)
	{
		zoomLevel++;
	}
	
	newmap.setCenter(new OpenSpace.MapPoint(mapdetails.centreeasting, mapdetails.centrenorthing), zoomLevel);
		
    if	(mapdetails.tracks.length > 0 || mapdetails.routes.length > 0)
    {
 		osVectorLayer = newmap.getVectorLayer();    
 	}

	return newmap;
}


function resizemap()
{
	if	(map == null)
	{
		return;
	}
	
	sizes = getAvailableArea();

	if (mapdetails.showtitle && titlevisible) 
	{
		$('#titlepanel').css('display', 'block');
	}

	var panelSize = 180; 

	if	(sizes[0] < 400 || sizes[1] < 400)
	{
		panelSize /= 2;
		$('#mapwrapper').css('font-size', '50%');		
		$('#titlepanel').css('width', panelSize);
	}

	if (sizes[2] === 0)
	{
		sizes[2] = -20;		
	}
		
	var left = sizes[2] + sizes[0] - panelSize - 15;

	var top;

	if (maptype === 'G') 
	{
		top = sizes[3] + 65;
	}
	else
	{
		top = sizes[3] + 15;
	}

	if (mapdetails.showtitle && titlevisible) 
	{
		$('#titlepanel').offset({ left: left, top: top });
		$('#titlepanel').draggable();
	} 
	else
	{
		$('#titlepanel').css('display', 'none');
	}

	var useragent = navigator.userAgent;

	var isMobile = (useragent.indexOf('iPhone') != -1 || useragent.indexOf('Android') != -1 );
	var isSmallScreen =  (sizes[0] < 800 && sizes[1] < 800);

	$('#optionsdiv').html('<ul class="sf-menu" id="options"><li id="optionsmenu"><a href="#a"><span>Options</span></a></li></ul>');
	
	$('#optionsmenu').append('<ul id="optionsdetails"></ul>');
	
	if	(mapdetails.showtitle)
	{
		if (titlevisible) 
		{
			$('#optionsdetails').append('<li><a href="#" onclick="toggletitle(); return false">Hide title and key</a></li>');
		}
		else
		{
			$('#optionsdetails').append('<li><a href="#" onclick="toggletitle(); return false">Show title and key</a></li>');
		}
	}	

	if	(!isMobile && mapdetails.showostoggle)
	{
		if (maptype === 'G') 
		{
			$('#optionsdetails').append('<li id="togglelink"><a href="#">Ordnance Survey map</a></li>');
		}
		else
		{
			$('#optionsdetails').append('<li id="togglelink"><a href="#">Google &amp; OpenCycle map</a></li>');
		}

		$("#togglelink").click(togglemap);
	}	
	

	if	(!isMobile && mapdetails.profile.length > 0 && !isSmallScreen)
	{
		$('#optionsdetails').append('<li id="showheight"><a href="#" onclick="showprofile(); return false;">Show height profile</a></li>');
	}	

	if (!isMobile && $("#ctcmenupanel").length > 0) 
	{
		$('#optionsdetails').append('<li><a href="map?m=' + mapid + '&t=' + maptype + '&f=y"' + ' title="Opens in new window" onclick="window.open(this.href); return false;">Open as full page map</a></li>');
	}
	
	if	(mapdetails.allowgpx)
	{
		$('#optionsdetails').append('<li><a href="#a" onclick="showgpxdialogue(); return false;" >Download as GPX file</a></li>');
	}	

	if	(titlevisible)
	{
		top += $('#titlepanel').height() + 20;			
	}

	$('#optionsmenu').css('width', panelSize + 10);
	$('#optionsdiv').offset({left: left, top: top});
	$('#optionsdiv').draggable(); 

	$('ul#options').superfish();  

	if (maptype === 'G') 
	{
		google.maps.event.trigger(map, 'resize');
		map.setZoom(map.getZoom());
	}	
}



function getAvailableArea()
{
	var sizes = new Array();

	if ($('#ctcmap').length > 0) 
	{
		sizes[0] = $('#ctcmap').width();
		sizes[1] = $('#ctcmap').height();
		
		var pos =  $('#ctcmap').offset();
		
		sizes[2] = pos.left;
		sizes[3] = pos.top;
	}
	else 
	{
		if (document.documentElement && document.documentElement.clientWidth) 
		{
			sizes[0] = document.documentElement.clientWidth;
			sizes[1] = document.documentElement.clientHeight;
		}
		else 
		{
			if (document.body) 
			{
				sizes[0] = document.body.clientWidth;
				sizes[1] = document.body.clientHeight;
			}
			else 
			{
				sizes[0] = window.innerWidth;
				sizes[1] = window.innerHeight;
			}
		}
		sizes[2] = 0;
		sizes[3] = 0;
	}
    return sizes;
}


function drawTrack(track)
{
	var points = Array();

	if (maptype === 'G') 
	{
		for (var i = 0; i < track.points.length; i++) 
		{
			points.push(new google.maps.LatLng(parseFloat(track.points[i].y), parseFloat(track.points[i].x)));
		}

		var polyline = new google.maps.Polyline({ path: points, clickable: false, strokeColor: track.colour, opacity: parseFloat(track.opacity) / 100, strokeWeight: parseFloat(track.width) });
		polyline.setMap(map);
	}
	else	
	{
		for (var i = 0; i < track.points.length; i++) 
		{
			points.push(new OpenLayers.Geometry.Point(track.points[i].easting, track.points[i].northing));
		}
	 	
	 	var trackstyle = { strokeColor: track.colour, strokeOpacity : (parseFloat(track.opacity) / 100), strokeWidth:  parseFloat(track.width) }; 
		var lineString  = new OpenLayers.Geometry.LineString(points);
	    var lineFeature = new OpenLayers.Feature.Vector(lineString, null, trackstyle); 
	 	osVectorLayer.addFeatures([lineFeature]);
	}
}


function drawPoints(points)
{
	for (var i = 0; i < points.length; i++) 
	{
		if (maptype === 'G')
		{ 
			addGoogleIcon(points[i].y, points[i].x, points[i].title, points[i].comment, points[i].colour, points[i].symbol);
		}
		else
		{
			addOSIcon(points[i].easting, points[i].northing, points[i].title, points[i].comment, points[i].colour, points[i].symbol);
		}
	}
}


function addOSIcon(easting, northing, pointname, text, colour, symbol)
{
	var icon = new OpenSpace.Icon(icon_directory + symbol + '/' + colour + '.png', os_icons[symbol]["size"], os_icons[symbol]["offset"]);
	var pos = new OpenSpace.MapPoint(easting, northing);
	var html = "<div class=\"osinfo\">" + "<p class=\"pointname\">" + pointname + "</p>" + text + "</div>";
	
	var marker = map.createMarker(pos, icon, html);
	marker.icon.imageDiv.firstChild.title = pointname;

}


function addGoogleIcon(lat, lon, pointname, text, colour, symbol)
{
	var baseurl = icon_directory + symbol;
	var iconurl = baseurl + '/' + colour + '.png';

	var pos = new google.maps.LatLng(parseFloat(lat), parseFloat(lon));
	var image = new google.maps.MarkerImage(iconurl);
	var shadow = new google.maps.MarkerImage(baseurl + '/shadow.png');
	
	var marker = new google.maps.Marker({
		icon: image,
		shadow: shadow,
		title: pointname,
		map: map,
		position: pos
	});

	var infoWindowOptions = {
		content: "<div class=\"info\">" + "<p class=\"pointname\">" + pointname + "</p>" + text + "</div>"
	};

	var infoWindow = new google.maps.InfoWindow(infoWindowOptions);

	google.maps.event.addListener(marker, 'click', function() {
		infoWindow.open(map,marker);
	});	
}


function togglemap()
{
	$('#togglelink').unbind('click');
	toggling = true;

	if	(osapiloaded)
	{
		dotoggle();		
	}	
	else
	{
		LazyLoad.js(osapisource + "?key=" + osapikey, dotoggle);
	}
}


function dotoggle()
{
	if (!osapiloaded) 
	{
		setuposicons();
	}
		
	var gridProjection = new OpenSpace.GridProjection();

	if	(maptype == 'G')
	{
		googlemaptypeid = map.getMapTypeId();		

		var bounds = map.getBounds();
		
		var swLatLng = bounds.getSouthWest();
		var neLatLng = bounds.getNorthEast();
		var centreLatLng = bounds.getCenter();

		var ne = gridProjection.getMapPointFromLonLat(new OpenLayers.LonLat(neLatLng.lng(), neLatLng.lat()));
		var sw = gridProjection.getMapPointFromLonLat(new OpenLayers.LonLat(swLatLng.lng(), swLatLng.lat()));
		var centre = gridProjection.getMapPointFromLonLat(new OpenLayers.LonLat(centreLatLng.lng(), centreLatLng.lat()));
	
		mapdetails.minx  = swLatLng.lng();
		mapdetails.maxx  = neLatLng.lng();
		mapdetails.miny  = swLatLng.lat();
		mapdetails.maxy  = neLatLng.lat();
		mapdetails.centrex  = centreLatLng.lng();
		mapdetails.centrey  = centreLatLng.lat();

		mapdetails.mineasting  = sw.getEasting();
		mapdetails.maxeasting  = ne.getEasting();
		mapdetails.minnorthing = sw.getNorthing();
		mapdetails.maxnorthing = ne.getNorthing();
		mapdetails.centrenorthing = centre.getNorthing();
		mapdetails.centreeasting  = centre.getEasting();

		maptype = 'O';	
	}
	else
	{
		var bounds = map.getExtent();
		var lbrt = bounds.toArray();			
		
		var sw = gridProjection.getLonLatFromMapPoint(new OpenSpace.MapPoint(lbrt[0], lbrt[1])); 
		var ne = gridProjection.getLonLatFromMapPoint(new OpenSpace.MapPoint(lbrt[2], lbrt[3])); 
		var centre = gridProjection.getLonLatFromMapPoint(new OpenSpace.MapPoint((lbrt[2] - lbrt[0]) / 2, (lbrt[3] - lbrt[1]) / 2)); 
	
		mapdetails.minx  = sw.lon;
		mapdetails.maxx  = ne.lon;
		mapdetails.miny  = sw.lat;
		mapdetails.maxy  = ne.lat;

		mapdetails.centrex  = centre.lon;
		mapdetails.centrey  = centre.lat;

		mapdetails.mineasting  = lbrt[0];
		mapdetails.maxeasting  = lbrt[2];
		mapdetails.minnorthing = lbrt[1];
		mapdetails.maxnorthing = lbrt[3];
		mapdetails.centrenorthing = (lbrt[3] - lbrt[1]) / 2;
		mapdetails.centreeasting  = (lbrt[2] - lbrt[0]) / 2;
		
		maptype = 'G';		
	}
	
	setupMap();
}

function setuposicons()
{
	os_icons['circle'] 		= { size : new OpenLayers.Size(12, 12), offset : new OpenLayers.Pixel(-6, -6) };
	os_icons['square'] 		= { size : new OpenLayers.Size(12, 12), offset : new OpenLayers.Pixel(-6, -6) };
	os_icons['triangle'] 	= { size : new OpenLayers.Size(14, 14), offset : new OpenLayers.Pixel(-7, -7) };
	os_icons['diamond'] 	= { size : new OpenLayers.Size(14, 14), offset : new OpenLayers.Pixel(-7, -7) };
	os_icons['google'] 		= { size : new OpenLayers.Size(20, 34), offset : new OpenLayers.Pixel(-10, -34) };
	os_icons['googleblank'] = { size : new OpenLayers.Size(20, 34), offset : new OpenLayers.Pixel(-10, -34) };
	os_icons['googlemini'] 	= { size : new OpenLayers.Size(12, 20), offset : new OpenLayers.Pixel(-6, -20) };
	os_icons['openspace'] 	= { size : new OpenLayers.Size(34, 45), offset : new OpenLayers.Pixel(-17, -45) };

	osapiloaded = true;
}

function showgpxdialogue()
{
	$("#gpxdownloadbutton").button();
	$("#gpxdownloadbutton").click(dogpxdownload);
	$("#gpxdialogue").dialog({ resizable: false, title: "Download GPX file", zIndex: 1050,  width: 450  }); 

	if (mapdetails.routes.length > 0) 
	{
		$("#multilabel").html('<input type="radio" id="multi" name="gpxchoices" checked />&nbsp;&nbsp;as ' + mapdetails.routes.length + ' routes, as on the map');
		$("#gpxchoices").show();
	}
	else if (mapdetails.tracks.length > 1) 
	{
		$("#multilabel").html('<input type="radio" id="multi" name="gpxchoices" checked />&nbsp;&nbsp;as ' + mapdetails.tracks.length + ' tracks, as on the map');
		$("#gpxchoices").show();
	}
	else 
	{
		$("#gpxchoices").hide();
	}
}

function dogpxdownload()
{
	var downloadurl = getWindowLocation() + '/mapgpxdownload?m=' + mapid; 

	if ($("#single").is(':checked'))
	{
		downloadurl += "&s=y"; 				
	}

	window.location.href = downloadurl; 

	$("#gpxdialogue").dialog("close");
}

function showprofile()
{
	$("#profile").empty().html('<div id="elevationprofile"><img src="' + mapdetails.profile  +  '" alt="" title="graph of height (metres) vs distance (km)" /></div>').dialog({ resizable: false, title: "Elevation profile", zIndex: 1050, width: 765 });
}

function toggletitle()
{
	titlevisible = !titlevisible;
	resizemap();
}

function getWindowLocation()
{
	return window.location.href.substr(0, window.location.href.lastIndexOf("/"));
}
