	  
	  if(!sLat && !sLon && !defaultLoc) {
	var sLat = -37.814251;
	  var sLon = 144.963169;
	  var defaultLoc = 'Melbourne, Vic, Australia';
	}
	
	  var initialRoute = false;
      var map = new GMap2(document.getElementById("map"));
	  var geocoder = new GClientGeocoder();
      map.addControl(new GLargeMapControl());
      map.addControl(new GMapTypeControl());
      
		var markerImage = [
		"http://www.google.com/intl/en_ALL/mapfiles/marker.png",
		"http://maps.google.com/mapfiles/dd-start.png",
		"http://maps.google.com/mapfiles/dd-end.png",
		"http://esa.ilmari.googlepages.com/markeryellow.png",//3 yellow
		"http://www.google.com/uds/samples/places/temp_marker.png",//4 turquoise
		]
      
		var prettyIcon = new GIcon();
		prettyIcon.image = markerImage[3];
		prettyIcon.iconSize = new GSize(20, 34);
		prettyIcon.iconAnchor = new GPoint(9, 34);
		prettyIcon.infoWindowAnchor = new GPoint(7,7);
      
      // == use different GDirections for adding and dragging, it is just simpler that way ==
      var dirn1 = new GDirections();
      var dirn2 = new GDirections();
      var dirn3 = new GDirections();
      var dirn4 = new GDirections();
      
      var firstpoint = true;
      var gmarkers = [];
      var gpolys = [];
      var galtitude = [];
      var gdurations = [];
      var gcontent = [];
      var gmaxcontent = [];
      var gtitle = [];
      var focuspoly = 0;
      var lastindex = 0;
      var debug = false;
      
      var nodes;
      var maxNodes = 10;
      var distance;

      GEvent.addListener(map, "click", executeNewPoint);
      
      function executeNewPoint(overlay,point) {
      	if(point) {
      	// if we don't have excess content, then we needs it
      	if(gmarkers.length == gcontent.length) {
      		gcontent.push('My Point');
      		gmaxcontent.push('');
      		gtitle.push('');
      	}
	//console.log(point.lat()+', '+point.lng());
      
        // == When the user clicks on the map, get directions from that point to itself ==
          if (firstpoint) {
            dirn1.loadFromWaypoints([point.toUrlValue(6),point.toUrlValue(6)],{getPolyline:true});
          } else {
            dirn1.loadFromWaypoints([gmarkers[gmarkers.length-1].getPoint(),point.toUrlValue(6)],{getPolyline:true});
          }
		}
      }

      function calculateDistance() {
        var dist = 0;
        for (var i=0; i<gpolys.length; i++) {
          dist+=gpolys[i].Distance();
        }
        distance = (dist/1000).toFixed(2);
        document.getElementById("distance").innerHTML=distance+" km";
      }
      
      function renderPointDetails(arrLoc) {
        // == Add this point to the list ==
        var itinerary = document.getElementById('itinerary');
		itinerary.innerHTML += '<div id="it_'+gmarkers.length+'" class="destination">'+(gcontent[arrLoc])+'</div>';
        YAHOO.util.Event.addListener('it_'+gmarkers.length, "click", deletePoint); 
      }
      
      function deletePoint(e) {
		var target = YAHOO.util.Event.getTarget(e);

        // remove it from the map
        var id = target.id.replace('it_','');
        map.removeOverlay(gmarkers[id-1]);
        map.removeOverlay(gpolys[id-2]);

        // remove it from the display divs
		var locs = document.getElementById('itinerary').childNodes;
		for(var x=0;x<locs.length;x++) {
			if(locs[x].id == target.id) {
				document.getElementById('itinerary').removeChild(document.getElementById('itinerary').childNodes[x]);
			}
		}

        // iterate the lists and remove it from there
        gmarkers.splice(id-1,1);
        gpolys.splice(id-2,1);
        
		// recalculate the poly between pre and post points
      }

      function calculateDuration() {
        var dist = 0;
        for (var i=0; i<gdurations.length; i++) {
          dist+=gdurations[i];
        }
        document.getElementById("duration").innerHTML=secondsToString(dist);
      }

      function calculateLocation() {
        var totLat = 0;
        var totLon = 0;
        
        for (var i=0; i<gmarkers.length; i++) {
          var point = gmarkers[i].getPoint();
          totLat+=point.lat();
          totLon+=point.lng();
        }
        point = new GLatLng(totLat/gmarkers.length,totLon/gmarkers.length);
        //var marker=new GMarker(point);
        //geocoder.getLocations(point, showAddress);
        
        //map.addOverlay(marker);
      }

	function secondsToString(seconds)
	{
		var numdays = Math.floor(seconds / 86400);
		var numhours = Math.floor((seconds % 86400) / 3600);
		var numminutes = Math.floor(((seconds % 86400) % 3600) / 60);
		var numseconds = ((seconds % 86400) % 3600) % 60;
	
		var finalString = '';
		if(numdays) {
			finalString += numdays+' days ';
		}
		if(numhours) {
			finalString += numhours+' hours ';
		}
		if(numminutes) {
			finalString += numminutes+' minutes ';
		}
		if(numseconds) {
			finalString += numseconds+' seconds';
		}
	
		return finalString;
	}

	function addressToPoints(address) {
	  geocoder.getLatLng(
	    address,
	    function(point) {
	      if (point) {
	        //map.setCenter(point, 8);
			sLon = point.lng();
			sLat = point.lat();
	      }
	      else {
	      	if(address == 'Shanghai, China') {
	      		sLat = 31.27855085894653;
	      		sLon = 121.728515625;
	      	}
	      	else if(address == 'London, England, UK') {
	      		sLat = 51.53608560178475;
	      		sLon = -0.1318359375;
	      	}
	      	else {
		      	document.getElementById('newRoute').location.value = defaultLoc;
			}
	      }
		map.setCenter(new GLatLng(sLat, sLon),8);
		getDestinations();
	    }
	  );
	}
	
	function resetRoute(form) {
		addressToPoints(form.location.value);
	}

      function showAddress(response) {
          if (!response || response.Status.code != 200) {
            alert("Status Code:" + response.Status.code);
          } else {
            place = response.Placemark[0];
            document.getElementById('location').innerHTML =
            place.AddressDetails.Country.AdministrativeArea.Locality.LocalityName+', ' + place.AddressDetails.Country.AdministrativeArea.AdministrativeAreaName + ', ' + place.AddressDetails.Country.CountryName;
          }
        }

      function getAltitude() {
       	  nodes = 0;
          for (var x=0; x<gpolys.length; x++) {
              var poly=gpolys[x];

              focuspoly = x;
    	      galtitude[focuspoly] = [];

    	      for (var i=0; i<maxNodes; i++) {
    	      var point = poly.GetPointAtDistance(i*poly.Distance()/maxNodes);

              GDownloadUrl('/elevation.php?lng=' +point.lng()+ '&lat=' +point.lat(), function(data) {
                  var doc = GXml.parse(data);
                  galtitude[focuspoly].push(parseInt(GXml.value(doc)));
                  nodes = nodes+1;
                  if (nodes == maxNodes*gpolys.length) {
                      drawAltitude();
                  }
              });
              }
          }
      }
      
      function getDestinations() {
         document.getElementById('loading').style.display = 'block';
         var dist = 150;
         if(document.getElementById('newRoute').distance.value) {
         	dist = document.getElementById('newRoute').distance.value;
         }
         var interest = '';
         if(document.getElementById('type-eat').checked) {
         	interest += '&what[]=eat';
         }
         if(document.getElementById('type-sleep').checked) {
         	interest += '&what[]=sleep';
         }
         if(document.getElementById('type-do').checked) {
         	interest += '&what[]=do';
         }
         if(document.getElementById('type-see').checked) {
         	interest += '&what[]=see';
         }         
         if(document.getElementById('type-shop').checked) {
         	interest += '&what[]=shop';
         }
         if(document.getElementById('type-night').checked) {
         	interest += '&what[]=night';
         }
         if(document.getElementById('type-general').checked) {
         	interest += '&what[]=general';
         }               
               // start point
           	initialRoute = false;
            	gcontent.push('<strong>'+document.getElementById('newRoute').location.value+'</strong><br/>Designated starting location!');
            	gmaxcontent.push('This is your starting location. You can drag this point around if you want to work out the travel time when starting from another location.');
            	gtitle.push('<strong>'+document.getElementById('newRoute').location.value+'</strong>');
            	executeNewPoint(null,new GLatLng(sLat,sLon));
            	firstpoint = false;
                           
         //console.log('/mage_test.php?distance='+dist+'&long=' +sLon+ '&lat=' +sLat+interest);
         GDownloadUrl('/mage_test.php?distance='+dist+'&long=' +sLon+ '&lat=' +sLat+interest, function(data, responseCode) {

            if(responseCode == 200) {

            var doc = GXml.parse(data);
            
            var poi = doc.documentElement.getElementsByTagName('poi');

            if(!poi || (poi.length == 0)) {
            document.getElementById('loading').innerHTML = 'There was a problem.<br/>Please try again.';
            } else {
            
            for(var x=0;x<poi.length;x++) {
            	//console.log(poi[x].getElementsByTagName('name')[0].firstChild.textContent);
            	var lat = poi[x].getElementsByTagName('digital-latitude')[0].firstChild.textContent;
            	var lng = poi[x].getElementsByTagName('digital-longitude')[0].firstChild.textContent;

				var interest = poi[x].getElementsByTagName('poi-type')[0].firstChild.textContent;
				var icon = '';
				if(interest == 'See') {
					icon = '<img src="/icons/eye.png" title="'+interest+'" alt="'+interest+'" align="left"/>';
				}
				if(interest == 'Do') {
					icon = '<img src="/icons/anchor.png" title="'+interest+'" alt="'+interest+'" align="left"/>';
				}
				if(interest == 'Shop') {
					icon = '<img src="icons/cart.png" title="'+interest+'" alt="'+interest+'" align="left"/>';
				}
				if(interest == 'Eat') {
					icon = '<img src="/icons/cake.png" title="'+interest+'" alt="'+interest+'" align="left"/>';
				}
				if(interest == 'Night') {
					icon = '<img src="/icons/drink.png" title="'+interest+'" alt="'+interest+'" align="left"/>';
				}
				if(interest == 'General') {
					icon = '<img src="/icons/asterisk_yellow.png" title="'+interest+'" alt="'+interest+'" align="left"/>';
				}
				if(interest == 'Sleep') {
					icon = '<img src="/icons/zzz.gif" title="'+interest+'" alt="'+interest+'" align="left"/>';
				}
				//console.log(interest);
				gcontent.push('<strong>'+icon+' &nbsp;&nbsp;'+poi[x].getElementsByTagName('name')[0].firstChild.textContent+'</strong>');
				gmaxcontent.push(poi[x].getElementsByTagName('review')[0].firstChild.textContent);
				gtitle.push('<strong>'+icon+' &nbsp;&nbsp;'+poi[x].getElementsByTagName('name')[0].firstChild.textContent+'</strong>');
            	
   	        	setTimeout('initialRoute = true; executeNewPoint(null,new GLatLng('+lat+','+lng+'))',1500*(x+1));
            }
            setTimeout('initialRoute = false;',2000*poi.length);
            
            /*
            if(poi) {
            	gcontent.push('finish point!');
    	        setTimeout('executeNewPoint(null,new GLatLng('+sLat+','+sLon+'))',1000*poi.length);
            }
            */
            document.getElementById('loading').style.display = 'none';
            }

            } else {
            document.getElementById('loading').innerHTML = 'There was a problem.<br/>Please try again.';
            }
         });
      }

      function drawAltitude() {
        var min=Infinity, max=0;
        // ==== some Google Chart parameters ====
        var allpoints = '';
        var url = "http://chart.apis.google.com/chart?cht=lc&amp;chs=400x130&amp;chco=333333&amp;chm=B,6ec563,0,0,0&amp;chxt=x,y,x,y&amp;chxl=2:||Kilometers||3:|||Meters||&amp;chco=ffffff&amp;chd=t:";
        for (var x=0; x<galtitude.length; x++) {
        	allpoints += '<br/>Poly '+x+': ';
        for (var i=0; i<galtitude[x].length; i++) {
          // == filter out bogus values ==
          if (galtitude[x][i] < -10000000000) {galtitude[x][i] = 0;}
          if (galtitude[x][i] > max) { max = galtitude[x][i]; }
          if (galtitude[x][i] < min) { min = galtitude[x][i]; }

          // == add to the Chart URL ==
          url += galtitude[x][i];
          allpoints += ', '+galtitude[x][i];
          if (i<maxNodes-1) {url += ","; }
        }
        }
        // == add min/max values to Chart URL ==
        url += "&amp;chxr=0,1,"+(maxNodes/4);
        // == create the Google Chart image ==
        if (debug) {GLog.write("create chart "+url);}
        document.getElementById("altitude").innerHTML = allpoints+'<br/><img src="' +url+ '" width=400 height=130 >';
      }

      // == when the load event completes, plot the point on the street ==
      GEvent.addListener(dirn1,"load", createPoint);
      
      function createPoint() {
        // snap to last vertex in the polyline
        var n = dirn1.getPolyline().getVertexCount();
        var p=dirn1.getPolyline().getVertex(n-1);
        //gcontent.push(p.lat+', '+p.lng);
        
        if(!initialRoute) {
	        var marker=new GMarker(p,{draggable:true});
	}
	else {
	        var marker=new GMarker(p,{icon:prettyIcon});
	}

        GEvent.addListener(marker, "dblclick", function() {        
	        // remove it from the map
	        var id = marker.MyIndex+1;
	
			if(!gmarkers[id-1].LPPoint) {
		        map.removeOverlay(gmarkers[id-1]);
			}
	        gmarkers.splice(id-1,1);
	        gdurations.splice(id-1,1);
	
	        if(gpolys[id-2]) {
		        map.removeOverlay(gpolys[id-2]);
		        gpolys.splice(id-2,1);
	        }
	        if(gpolys[id-2]) {
		        map.removeOverlay(gpolys[id-2]);
	        	gpolys.splice(id-2,1);
	        }
	
	        // remove it from the display divs
			var locs = document.getElementById('itinerary').childNodes;
			for(var x=0;x<locs.length;x++) {
				if(locs[x].id == 'it_'+id) {
					document.getElementById('itinerary').removeChild(document.getElementById('itinerary').childNodes[x]);
					break;
				}
			}
			// recalculate the ids
			for(var x=0;x<locs.length;x++) {
				locs[x].id = 'it_'+(x+1);
			}
	
			// recalculate the poly between pre and post points
			lastIndex = id-2;
            var point = gmarkers[id-1].getPoint();
            dirn4.loadFromWaypoints([gmarkers[lastIndex].getPoint(),point.toUrlValue(6)],{getPolyline:true});
			
			// cleanup indexes
			for(var x=0;x<gmarkers.length;x++) {
				gmarkers[x].MyIndex -= 1;
			}
			
			
		  calculateDistance();
          calculateDuration();
		});

		if(!initialRoute) {
         GEvent.addListener(marker, "dragend", function() {
          lastIndex = marker.MyIndex;
          var point = marker.getPoint();
          if (lastIndex>0) {
            // recalculate the polyline preceding this point
            dirn2.loadFromWaypoints([gmarkers[lastIndex-1].getPoint(),point.toUrlValue(6)],{getPolyline:true});
          }
          if (lastIndex<gmarkers.length-1) {
            // recalculate the polyline following this point
            dirn3.loadFromWaypoints([point.toUrlValue(6),gmarkers[lastIndex+1].getPoint()],{getPolyline:true});
          }
        });
       }
        
       GEvent.addListener(marker, "click", function() {
       	 if(gmaxcontent[marker.MyIndex] != '') {
	         marker.openInfoWindowHtml(gcontent[marker.MyIndex],{maxContent: gmaxcontent[marker.MyIndex], maxTitle: gtitle[marker.MyIndex]});
		 }
		 else {
	         marker.openInfoWindowHtml(gcontent[marker.MyIndex]);
		 }
       });

        map.addOverlay(marker);
        // store the details
        marker.MyIndex=gmarkers.length;
        marker.LPPoint = initialRoute;
        gmarkers.push(marker);
        if (gmarkers.length > 1) {
          //console.log('Point '+gmarkers.length);
          map.addOverlay(dirn1.getPolyline());
          gpolys.push(dirn1.getPolyline());
          gdurations.push(dirn1.getDuration().seconds);
          calculateDistance();
          calculateDuration();
          calculateLocation();
          //getAltitude();
        }
        renderPointDetails(marker.MyIndex);
        firstpoint = false;
        //initialRoute = false;
      }

      // == connect two points together ==
      GEvent.addListener(dirn4,"load", function() {
        // add the new polyline
        map.addOverlay(dirn4.getPolyline());
        gpolys.splice(lastIndex-2,0,dirn4.getPolyline());
        gdurations.push(dirn4.getDuration().seconds);
  
      });

      // == move the polyline preceding this point ==
      GEvent.addListener(dirn2,"load", function() {
        // snap to last vertex in the polyline
        var n = dirn2.getPolyline().getVertexCount();
        var p=dirn2.getPolyline().getVertex(n-1);
        gmarkers[lastIndex].setPoint(p);
        // remove the old polyline
        map.removeOverlay(gpolys[lastIndex-1]);
        // add the new polyline
        map.addOverlay(dirn2.getPolyline());
        gpolys[lastIndex-1] = (dirn2.getPolyline());
        gdurations.push(dirn2.getDuration().seconds);
        calculateDistance();
        calculateDuration();
        calculateLocation();
        //getAltitude();
      });

      // == move the polyline following this point ==
      GEvent.addListener(dirn3,"load", function() {
        // snap to first vertex in the polyline
        var p=dirn3.getPolyline().getVertex(0);
        gmarkers[lastIndex].setPoint(p);
        // remove the old polyline
        map.removeOverlay(gpolys[lastIndex]);
        // add the new polyline
        map.addOverlay(dirn3.getPolyline());
        gpolys[lastIndex] = (dirn3.getPolyline());
        gdurations.push(dirn3.getDuration().seconds);
        calculateDistance();
        calculateDuration();
        calculateLocation();
        //getAltitude();
      });

      GEvent.addListener(dirn1,"error", function() {
        GLog.write("Failed: "+dirn1.getStatus().code);
      });
      GEvent.addListener(dirn2,"error", function() {
        GLog.write("Failed: "+dirn2.getStatus().code);
      });
      GEvent.addListener(dirn3,"error", function() {
        GLog.write("Failed: "+dirn3.getStatus().code);
      });

	addressToPoints(document.getElementById('newRoute').location.value);

    // This Javascript is based on code provided by the
    // Community Church Javascript Team
    // http://www.bisphamchurch.org.uk/   
    // http://econym.org.uk/gmap/
