var map;
var defaultLat = 54.278055,defaultLng = -2.307129, defaultZoom =7;
var doubleClick = false;
var route = new Array();
var currentLine = new Array(); // all points on line, visible or not
var vLines = new Array(); // visible lines
var markers = new Array();
var notes = new Array();
var distParts = new Array();
var distance=0;
var postcode='';
var distanceAlert=false;

function drawMap()
{
	//intialize the map
	map = new GMap2(document.getElementById("map"), {draggableCursor: 'crosshair', draggingCursor: 'crosshair'});
	map.setCenter(new GLatLng(defaultLat, defaultLng), defaultZoom);
	map.addControl(new GLargeMapControl());
	map.addControl(new GMapTypeControl());

	map.addControl(new GScaleControl());
	map.enableContinuousZoom();

	var keyHandle = new GKeyboardHandler(map);
	
	map.disableDoubleClickZoom();
	
	GEvent.addDomListener(map, "dblclick", function()
	{	
		doubleClick=true;		
	});
	
	GEvent.addListener(map, "moveend", function()
	{
		if(doubleClick)
		{
			var clickLoc = map.getCenter();
			appendRoute(clickLoc.lat(),clickLoc.lng());
		}
		
		drawLine();
		drawMarkers();

		doubleClick = false;
	});
	
	/*GEvent.addListener(map, "click", function(marker, point) 
	{  
		if (!e) var e = window.event;
		var keynum = e.keyCode || e.which;

		if (e.shiftKey)
		{	
			var size = notes.length;
			if (marker) 
			{    
				if(confirm('Are you sure you wish to remove this marker?'))
				{
					var pos = marker.title.split("-");
					map.closeInfoWindow();
					map.removeOverlay(marker); 
					if(notes.length==1)
						notes=new Array();
					else
						notes.splice(pos[0],1); 
				}
				
			} 
			else 
			{   
				var icon = new GIcon();
				icon.image = "http://www.cycle-route.com/images/pin.png";
				icon.iconSize = new GSize(20, 20);
				icon.iconAnchor = new GPoint(6, 18);
				icon.infoWindowAnchor = new GPoint(16,3);
				
				var marker =  new GMarker(point,icon);
				marker.title = notes.length+"-marker";
				map.addOverlay(marker);  
				notes.push('note '+notes.length);
				
				
				GEvent.addListener(marker, "click", function() 
				{
					if(e.shiftKey)
						return;
						
					marker.openInfoWindowHtml(notes[size]+"<br /><br />(hold shift key and click on marker to remove)");  }
				);
				marker.openInfoWindowHtml("<table><tr><td valign=\"top\">Note/Comment:<br /><textarea name=\"text"+size+"\" id=\"text"+size+"\" rows=\"3\" cols=\"30\"></textarea></td></tr><tr><td align=\"center\"><input type=\"button\" value=\"close\" onclick=\"notes["+size+"] = document.getElementById('text"+size+"').value; map.closeInfoWindow();\" /></td></tr></table>");  
			}
		}
	});*/
}

function appendRoute(lat, lng)
{
	if(map.getZoom()<9)
	{
		alert('Please zoom in further before starting your route');
		return;
	}

	if(!distanceAlert && distance>100)
	{
		alert('This route is more than 100 miles long. If it is much longer, please split into separate routes, e.g. label them Part 1 of X...) Your route may not be published otherwise.');
		distanceAlert=true;
	}
	route.push(new GLatLng(lat,lng));
	updateDistance(true);
}

function dependRoute()
{

	if(route.length > 0)
	{
		route.pop();
		updateDistance(false);
		drawMarkers();
		drawLine();
		
	}
	else
		alert('There are no points to remove');


}

function drawMarkers()
{
	if (route.length > 0)
	{
			//must be called BEFORE prepMarkerArray, to make sure that we
			//clear previously existing markers.
			removeAllMarkers();
			calculateMarkers();
	
			// add start and finish markers
			markers.unshift(new GMarker(route[0]));
  			map.addOverlay(markers[0]);

  			if(route.length>1)
  			{
  				markers.push(new GMarker(route[route.length-1]));
  				map.addOverlay(markers[markers.length-1]);
  			}

  			var miles = parseInt(distance,10);
			
			for (var m=1;m<markers.length-1;m++)
			{
				if(map.getBounds().contains(markers[m].getPoint()))
					map.addOverlay(markers[m]);

			}
	}

}


function calculateMarkers()
{
	var currentlength=0;
	var segment=0;
	var milefreq = 2;
	
	for (var k=0;k<distParts.length;k++)
	{
		
		// if the new length is greater than milefreq add a marker at the correct point
		if(distParts[k]+currentlength>milefreq)
		{
			//alert('in');
			segment = distParts[k];
			// store offset length
			var offset = currentlength;
			var mile=1;
			while(segment+currentlength>milefreq)
			{
				var p1 = route[k]; // point 1
				var p2 = route[k+1]; // point 2
				calculatePoint(p1,p2,distParts[k],((mile*milefreq)-offset));
				
				if(mile==1)
					segment = segment-(milefreq-currentlength);
				else
					segment -= milefreq;
					
				currentlength=0;
				mile++;
				
			}
			currentlength = segment;
		}
		else
			currentlength+=distParts[k];	
	}
	
}

function calculatePoint(p1,p2,seglen,reqlen)
{
	var deltax = p2.lng()-p1.lng();
	var deltay = p2.lat()-p1.lat();
	var gradient = deltay/deltax;
	
	//reqlen = (gradient<0)?1-reqlen:reqlen;
	
	var leng = Math.sqrt((deltax*deltax)+(deltay*deltay)); // length in points
	leng = (reqlen/seglen)*leng;
	
	var x = leng * Math.cos(Math.atan(Math.abs(gradient)));
	var y = leng * Math.sin(Math.atan(Math.abs(gradient)));
	
	
	if(p2.lat()>p1.lat())
		y = p1.lat()+ y;
	else
		y = p1.lat()-y;
	
	if(p2.lng()>p1.lng())
		x = p1.lng()+x;
	else
		x = p1.lng()-x;
	
	var icon = new GIcon();
	icon.image = "http://labs.google.com/ridefinder/images/mm_20_red.png";
	icon.shadow = "http://labs.google.com/ridefinder/images/mm_20_shadow.png";
	icon.iconSize = new GSize(12, 20);
	icon.shadowSize = new GSize(22, 20);
	icon.iconAnchor = new GPoint(6, 20);

	markers.push(new GMarker(new GLatLng(y,x),icon));
}


function removeAllMarkers()
{
	for (var m=0;m<markers.length;m++)
	{
		if (markers[m] != undefined)
		{
			map.removeOverlay(markers[m]);
			markers[m] = undefined;
		}

	}
	markers = new Array();
}

function round(number,X)
{
 	var X = (!X ? 2 : X);
    return Math.round(number*Math.pow(10,X))/Math.pow(10,X);
}


function updateDistance(add)
{
	if(route.length>1)
	{
		var oldpoint = route[route.length-2];
		var newpoint = route[route.length-1];

		var result = newpoint.distanceFrom(oldpoint) * .000621371192;

		if(add)
		{
			distance += result;
			distParts.push(result);
		}
		else
		{
			distance -= result;
			distParts.pop();
		}

		document.getElementById('distSpan').innerHTML = round(distance,2);
	}
}

// draws a line from the last point to the most recent point in the array
// if there is only one point nothing is done
function drawLine()
{
	if(route.length>1)
	{
		var newpoint = route[route.length-1];
		var oldpoint = route[route.length-2];
	}


	if(vLines.length>0)
	{
		// remove all the lines
		for (var i=0;i<route.length-1;i++)
		{
			if(vLines[i]!=undefined)
		  		map.removeOverlay(vLines[i]);
		}
	}

		//this function may be called from removeLastLeg, in which case
		//we still want to clear points (above) but don't want to draw a new one.
		if (route.length > 1)
		{
			var routeColor = '#0000FF';

			//to determine whether to draw a line segment, we check whether the rectangle described by the segment
			//intersects with the rectangle described by the current screen. If we just checked whether the begin and
			//end points were on the current map, we'd miss lines that pass through the current map without originating
			//there.
			var lastPtAdded = false;
			var mapSW = map.getBounds().getSouthWest();
			var mapNE = map.getBounds().getNorthEast();

			//using GBounds instead of GLatLngBounds because a GBound can be created using any two points.
			//Constructor of GLatLngBounds requires we calculate NE and SW corners of bounds, which we may not have
			var mapGBounds = new GBounds(new Array(map.fromLatLngToDivPixel(mapSW),map.fromLatLngToDivPixel(mapNE)));
			var thisGBounds;
			var nullPoint = new GPoint(0,0);
			var lines=0;

			for (var j=1; j<route.length; j++)
			{
				thisGBounds = new GBounds(new Array(map.fromLatLngToDivPixel(route[j]),map.fromLatLngToDivPixel(route[j-1])));

				if (doBoundsIntersect(mapGBounds,thisGBounds))
				{
					if (!lastPtAdded)
						currentLine.push(route[j-1]);

					currentLine.push(route[j]);
					lastPtAdded = true;
				}
				else
				{
					lastPtAdded = false;
					if (currentLine.length > 0)
					{
						drawPolyLineSegment(routeColor,lines);
						lines++;
					}

				}
			}
			if (currentLine.length > 0)
			{
				drawPolyLineSegment(routeColor,lines);
				lines++;
			}
		}
}

function drawPolyLineSegment(routeColor, line)
{
		vLines[line] = new GPolyline(currentLine, routeColor);
		map.addOverlay(vLines[line]);
		currentLine.splice(0,currentLine.length);
}

function doBoundsIntersect(rect1, rect2)
{

	var left1, right1, top1, bottom1;
	var left2, right2, top2, bottom2;

	left1 = rect1.minX;
	right1 = rect1.maxX;
	top1 = rect1.minY;
	bottom1 = rect1.maxY;

	left2 = rect2.minX;
	right2 = rect2.maxX;
	top2 = rect2.minY;
	bottom2 = rect2.maxY;

	return !(left2 > right1 || right2 < left1 || top2 > bottom1 || bottom2 < top1);

}

function clearRoute()
{
	route = new Array();
	currentLine = new Array(); 
	vLines = new Array();
	markers = new Array();
	distParts = new Array();
	distance=0;
	document.getElementById('distSpan').innerHTML = 0;
	map.clearOverlays();
}

function backtrack()
{
	dependRoute();
}

function closePopup()
{
	getElm('pop').style.visibility='hidden';
}

function pointssaved()
{
	//
}

function savePopup()
{
	
	postServ('http://www.cycle-route.com/routes/routeajax.php',pointssaved,'op=savepoints&points='+escape(route.toString())+'&notes='+escape(notes.toString()));
	
	
	if(empty(document.getElementById('distSpan').innerHTML)||parseFloat(document.getElementById('distSpan').innerHTML)<5)
	{
		alert('Your route is very short (<5 miles)\n\nPlease add sure more parts to your route before proceeding.');
		return false;
	}
	
	getElm('pop').style.visibility = 'visible';
	getElm('pop').style.left = '200';
	getElm('pop').style.top = '50';
	
}

function saveRoute()
{
	
	if(getElm('name').value=='')
	{
		alert('Please supply a name for your route before proceeding');
		return false;
	}
	
	if(getElm('desc').value=='')
	{
		alert('Please supply a description for your route before proceeding');
		return false;
	}
	else
	{
		var words = getElm('desc').value.toString().split(' ').length;
		if(words<10)
		{
			alert('Your description is quite short.\n\nPlease help others by adding more.\n\nFor example, what is the overall terrain, hilly?, suitable for\nmountain bikes, difficulty level, time taken e.t.c.\n\nYour route may not be added if you do not give a good description.');
			return false;
		}	
	}
	
	if(getElm('email').value=='')
	{
		alert('Please provide an email address to proceed.\nYour email is only used to notify you when the route is added to the website');
		return false;
	}
	
	getElm('points').value = route.toString();
	getElm('dist').value = document.getElementById('distSpan').innerHTML;
	return true;
}

function finished(xml)
{
	var status = getTag(xml,'status');
	alert(status[0].firstChild.nodeValue);
}

function handleDblClick(e)
{
	doubleClick = true;
}

function centerMapFromPostcode(posty)
{
	
	if(!posty.match('[a-zA-Z]{1,2}[0-9][0-9A-Za-z]? ?[0-9][a-zA-Z]{2}'))
	{
		alert('Please ensure you use a valid UK postcode format and try again.');
		return;
	}
	
	postcode=posty;
	//alert(postcode);
	
	postServ(siteurl+'includes/xml_routescommon.php',centerMapFromPostcodeResult,'op=lpoint&posty='+escape(postcode));
}

function centerMapFromPostcodeResult(xml)
{
	var posty = getTag(xml,'postcode')[0].firstChild.data;
	
	if(posty!="notfound")
	{
		var lat = getTag(xml,'lat')[0].firstChild.data;
		var lng = getTag(xml,'lng')[0].firstChild.data;
		map.setCenter(new GLatLng(lat,lng),13);
	}
	else
		usePointFromPostcode(postcode, setCenterToPoint);
		
}

function usePointFromPostcode(postcode, callbackFunction) 
{
	var localSearch = new GlocalSearch();
	localSearch.setSearchCompleteCallback(null,function(){
		if (localSearch.results[0])
		{		
			var point = new GLatLng(localSearch.results[0].lat,localSearch.results[0].lng);
			callbackFunction(point);
		}
	});	
		
	localSearch.execute(postcode + ", UK");
}

function setCenterToPoint(point)
{
	spoint(point);
	map.setCenter(point,13);
}

function spoint(point)
{
	postServ(siteurl+'includes/xml_routescommon.php',null,'op=spoint&lat='+point.lat()+'&lng='+point.lng()+'&posty='+escape(postcode));
}


if (navigator.appName == 'Microsoft Internet Explorer')
{
	document.ondblclick = handleDblClick;
	bIsIE = true;
}
else
{
	window.ondblclick = handleDblClick;
	bIsIE = false;
}


