	var geo;
    var reasons=[];
	var gdir;
	var stloc;
	var endloc;
	var tofrmMkr =[];
	
	
	geo = new GClientGeocoder(); 	
	gdir = new GDirections(null, document.getElementById("path"));
	
	// ====== Array for decoding the failure codes ======
    reasons[G_GEO_SUCCESS]            = "Success";
    reasons[G_GEO_MISSING_ADDRESS]    = "Missing Address: The address was either missing or had no value.";
    reasons[G_GEO_UNKNOWN_ADDRESS]    = "Unknown Address:  No corresponding geographic location could be found for the specified address.";
    reasons[G_GEO_UNAVAILABLE_ADDRESS]= "Unavailable Address:  The geocode for the given address cannot be returned due to legal or contractual reasons.";
    reasons[G_GEO_BAD_KEY]            = "Bad Key: The API key is either invalid or does not match the domain for which it was given";
    reasons[G_GEO_TOO_MANY_QUERIES]   = "Too Many Queries: The daily geocoding quota for this site has been exceeded.";
    reasons[G_GEO_SERVER_ERROR]       = "Server error: The geocoding request could not be successfully processed.";

    // ===== list of words to be standardized =====
    var standards = [   ["road","rd"],   
                        ["street","st"], 
                        ["avenue","ave"], 
                        ["av","ave"], 
                        ["drive","dr"],
                        ["saint","st"], 
                        ["north","n"],   
                        ["south","s"],    
                        ["east","e"], 
                        ["west","w"],
                        ["expressway","expy"],
                        ["parkway","pkwy"],
                        ["terrace","ter"],
                        ["turnpike","tpke"],
                        ["highway","hwy"],
                        ["lane","ln"]
                     ];

    // ===== convert words to standard versions =====
    function standardize(a) {
      for (var i=0; i<standards.length; i++) {
        if (a == standards[i][0])  {a = standards[i][1];}
      }
      return a;
    }

    // ===== check if two addresses are sufficiently different =====
    function different(a,b) {
      // only interested in the bit before the first comma in the reply
      var c = b.split(",");
      b = c[0];
      // convert to lower case
      a = a.toLowerCase();
      b = b.toLowerCase();
      // remove apostrophies
      a = a.replace(/'/g ,"");
      b = b.replace(/'/g ,"");
      // replace all other punctuation with spaces
      a = a.replace(/\W/g," ");
      b = b.replace(/\W/g," ");
      // replace all multiple spaces with a single space
      a = a.replace(/\s+/g," ");
      b = b.replace(/\s+/g," ");
      // split into words
      awords = a.split(" ");
      bwords = b.split(" ");
      // perform the comparison
      var reply = false;
      for (var i=0; i<bwords.length; i++) {
        //GLog.write (standardize(awords[i])+"  "+standardize(bwords[i]))
        if (standardize(awords[i]) != standardize(bwords[i])) {reply = true}
      }
      //GLog.write(reply);
      return (reply);
    }

      // ====== Geocoding ======
      function showAddress(adr) {
		
		$('#interactive_map_container').hide();		
		$('#map').hide();	
		document.getElementById("msg").innerHTML = "";		
	    var search;
		clearTable();		
		if (adr =="")
		{
			search = document.getElementById("addr").value;
		}
		else
		{
			search = adr;
		}
		
		if (search == "")
		{
			 r = crRow('');
			 c = crCellH("<font color='red'>Please enter an address</font>","","");
			 r = addCell(r,c);
			 addtblRow(r);
			 return;
		}
        // ====== Perform the Geocoding ======        
        geo.getLocations(search, function (result)
          {
            //map.clearOverlays(); 
            if (result.Status.code == G_GEO_SUCCESS) {
              // ===== If there was more than one result, "ask did you mean" on them all =====
              if (result.Placemark.length > 1) { 
			  	document.getElementById("map").style.display = "none";
				document.getElementById("map").style.visibility = "hidden";					
                //document.getElementById("message").innerHTML = "Did you mean:";
				var r = crRow("");
				var c = crCellH("Did you mean ?","","");
				r = addCell(r,c);
				addtblRowH(r);	
                // Loop through the results
                for (var i=0; i<result.Placemark.length; i++) {
                  var p = result.Placemark[i].Point.coordinates;                  
				  var cls = (i % 2)==0?"even":"odd";
				  r = crRow(cls);
				  c = crCell((i+1)+": <a href='javascript:showAddress(\""+result.Placemark[i].address+"\");'>"+ result.Placemark[i].address+"<\/a>");
				  r = addCell(r,c);
				  addtblRow(r);
                }				
              }              
              else {                				
                if (different(search, result.Placemark[0].address)) {                  
			      var r = crRow("");
				  var c = crCellH("Did you mean ?","","");
				  r = addCell(r,c);
				  addtblRowH(r);	
                  var p = result.Placemark[0].Point.coordinates;                 
				  r = crRow(cls);
				  c = crCell((1)+": <a href='javascript:showAddress(\""+result.Placemark[0].address+"\");'>"+ result.Placemark[0].address+"<\/a>");
				  r = addCell(r,c);
				  addtblRow(r);
                } else {
				 // location found
				  $('#interactive_map_container').show();
				  $('#map').show();

                  var p = result.Placemark[0].Point.coordinates;				  
				  // now set station distance for station and sort
				  for (var x=0;x < station_arr.length; x++)
				  {
						var d;
						d = distHaversine(p[1],p[0],station_arr[x].glat,station_arr[x].glong);
						station_arr[x].dist = d;						
				  }
				//sort by distance
				document.getElementById("map").style.display = "block";
				document.getElementById("map").style.visibility = "visible";		
				document.getElementById("addr").value ="";
				station_arr.sort(sortByDist);			
				displayRslt(0,result.Placemark[0].address,p[1],p[0]);
				load2(station_arr[0].glat,station_arr[0].glong,15,"","find");
                }
              }
            }
            // ====== Decode the error status ======
            else {
              var reason="Code "+result.Status.code;
              if (reasons[result.Status.code]) {
                reason = reasons[result.Status.code]
              } 
			  r = crRow(cls);
			  c = crCellH("Could not find "+search,"","");
			  r = addCell(r,c);
			  addtblRow(r);	
            }
          }
        );
      }
	  

/*
    // Most of the above This Javascript is based on code provided by the
    // Blackpool Community Church Javascript Team
    // http://www.commchurch.freeserve.co.uk/   
    // http://econym.googlepages.com/index.htm
*/	
/*
 * Use Haversine formula to Calculate distance (in km) between two points specified by 
 * latitude/longitude (in numeric degrees)
 *
 * example usage from form:
 *   result.value = LatLon.distHaversine(lat1.value.parseDeg(), long1.value.parseDeg(), 
 *                                       lat2.value.parseDeg(), long2.value.parseDeg());
 * where lat1, long1, lat2, long2, and result are form fields
 * http://www.movable-type.co.uk/scripts/latlong.html
 * note--For miles, divide km by 1.609344
 */
 function distHaversine(lat1, lon1, lat2, lon2) {
  var R = 6371; // earth's mean radius in km
  var dLat = (lat2-lat1).toRad();
  var dLon = (lon2-lon1).toRad();
  lat1 = lat1.toRad(), lat2 = lat2.toRad();

  var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
          Math.cos(lat1) * Math.cos(lat2) * 
          Math.sin(dLon/2) * Math.sin(dLon/2);
  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
  var d = R * c;
  //For miles, divide km by 1.609344
  d = d/1.609344;
  return d;
}


/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */

// extend String object with method for parsing degrees or lat/long values to numeric degrees
//
// this is very flexible on formats, allowing signed decimal degrees, or deg-min-sec suffixed by 
// compass direction (NSEW). A variety of separators are accepted (eg 3º 37' 09"W) or fixed-width 
// format without separators (eg 0033709W). Seconds and minutes may be omitted. (Minimal validation 
// is done).

String.prototype.parseDeg = function() {
  if (!isNaN(this)) return Number(this);                 // signed decimal degrees without NSEW

  var degLL = this.replace(/^-/,'').replace(/[NSEW]/i,'');  // strip off any sign or compass dir'n
  var dms = degLL.split(/[^0-9.]+/);                     // split out separate d/m/s
  for (var i in dms) if (dms[i]=='') dms.splice(i,1);    // remove empty elements (see note below)
  switch (dms.length) {                                  // convert to decimal degrees...
    case 3:                                              // interpret 3-part result as d/m/s
      var deg = dms[0]/1 + dms[1]/60 + dms[2]/3600; break;
    case 2:                                              // interpret 2-part result as d/m
      var deg = dms[0]/1 + dms[1]/60; break;
    case 1:                                              // decimal or non-separated dddmmss
      if (/[NS]/i.test(this)) degLL = '0' + degLL;       // - normalise N/S to 3-digit degrees
      var deg = dms[0].slice(0,3)/1 + dms[0].slice(3,5)/60 + dms[0].slice(5)/3600; break;
    default: return NaN;
  }
  if (/^-/.test(this) || /[WS]/i.test(this)) deg = -deg; // take '-', west and south as -ve
  return deg;
}
// note: whitespace at start/end will split() into empty elements (except in IE)

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */

// extend Number object with methods for converting degrees/radians

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


function sortByDist(a, b) {
    var x = a.dist;
    var y = b.dist;
    return ((x < y) ? -1 : ((x > y) ? 1 : 0));
}

function displayRslt(n,loc, lat,lng)
{	
	clearTable();
	document.getElementById("msg").innerHTML = "Location: "+loc;
	var r = crRow("");
	var c = crCellH("Metro Stations close to your location","colSpan","3");
	r = addCell(r,c);
	addtblRowH(r);	
	for (var x=0;x < 3; x++)
	{
		var data1;
		var data2;
		var data3;
		var cls;
		var cst;
		var staddr;
		cls = (x % 2)==0?"even":"odd";
		cst = x==n?"style='font-weight:bold'":"";		
		
		data1 = "<span id='c1"+x+"' name='c1"+x+"'  "+cst+">"+(x+1)+"</span>";
		data2 = "<span id='c2"+x+"' name='c2"+x+"' "+cst+">"+Math.round(station_arr[x].dist *100)/100+" miles</a></span>";
		data3 = "<span id='c3"+x+"' name='c3"+x+"' "+cst+"><a href='#c3"+x+"' onclick='reDisplayRslt(\""+x+"\",\"1\")'>"+station_arr[x].name+"</a><a href='/rail/station_detail.cfm?station_id="+station_arr[x].id+"'><span style='font-weight:normal'>  (Station Page)</span></a><br>"+station_arr[x].addr+","+station_arr[x].city_st+"</span>";
		data4 = "<a href='#path' onclick='getDirections(\""+loc+"\",\""+lat+"\",\""+lng+"\",\""+x+"\")'>Directions</a>";
		var r = crRow(cls);
		var c1 = crCell(data1);
		r = addCell(r,c1);
		var c2 = crCell(data2);
		r = addCell(r,c2);
		var c3  = crCell(data3);		
		r = addCell(r,c3);
		var c4 = crCell(data4);
		r = addCell(r,c4);
		addtblRow(r);	
	}
	document.getElementById("rw").value = 0;
	
}

function reDisplayRslt(x, pclr)
{
	// x= row and station
	var n = document.getElementById("rw").value;	
	$("#c1"+n).css("font-weight","normal");	
	$("#c2"+n).css("font-weight","normal");	
	$("#c3"+n).css("font-weight","normal");	
	$("#c1"+x).css("font-weight","bold");	
	$("#c2"+x).css("font-weight","bold");	
	$("#c3"+x).css("font-weight","bold");
	document.getElementById("rw").value = x;
	map.setCenter(new GLatLng(station_arr[x].glat,station_arr[x].glong));
	if (pclr =="1")
	{
		document.getElementById("path").innerHTML = "";
	}	
	
}

// ===== request the directions =====
GEvent.addListener(gdir,"error", function() {
        clearTable();
		var code = gdir.getStatus().code;
        var reason="Code "+code;
        if (reasons[code]) {
          reason = "Code "+code +" : "+reasons[code]
        } 
		r = crRow("");
		c = crCellH("Failed to obtain directions "+reason,"","");
		r = addCell(r,c);
		addtblRow(r);        
      });
var poly;
GEvent.addListener(gdir, "load", function() {
        if (poly) map.removeOverlay(poly);
        poly = gdir.getPolyline();		
        map.addOverlay(poly);
		displayDirections();
});

function getDirections(loc,lat, lng, x) {  
		addr1 = loc+"@"+lat+","+lng;
		addr2 = station_arr[x].addr+" "+station_arr[x].city_st+"@"+station_arr[x].glat+","+station_arr[x].glong;

		var locale = "en_US";
        var dirOpts = {locale: locale,getPolyline: true,getSteps: true};
        gdir.load("from: "+addr1+" to: "+addr2+"", dirOpts);		
		reDisplayRslt(x,"0");
		crToFromMkr(lat,lng,station_arr[x].glat,station_arr[x].glong);
      }
	  
function crToFromMkr(lat,lng, lat2, lng2)
{
	if (tofrmMkr.length > 0)
	{
		for (var x = 0; x < tofrmMkr.length ; x++)
		{
			map.removeOverlay(tofrmMkr[x]);
		}
		tofrmMkr = [];
	}
		
	var ic1 = G_START_ICON;
	var ic2 = G_END_ICON;
	var mkr =  new GMarker(new GLatLng(lat,lng),{icon:ic1});
	var mkr2 = new GMarker(new GLatLng(lat2,lng2),{icon:ic2});
	
	map.addOverlay(mkr);	
	map.addOverlay(mkr2);
	tofrmMkr.push(mkr);
	tofrmMkr.push(mkr2);	
}

function displayDirections()
{
	if (gdir.getNumRoutes() > 0 )
	{
		var rte = gdir.getRoute(0); //use first route
		var strhtml = "<table width='593px' class='tabular'>";
		strhtml += "<tr><td colspan='3'> From: ";
		strhtml += rte.getStartGeocode().address;
		strhtml += "<br />To: "+rte.getEndGeocode().address;
		strhtml += "</tr></td>";
		strhtml += "<tr><td colspan='3'> ";
		strhtml += rte.getSummaryHtml();
		strhtml += "</tr></td>";		
		for (var x=0; x < rte.getNumSteps(); x++)
		{
			var cls = (x % 2)==0?"even":"odd";
			var stp = rte.getStep(x);
			strhtml += "<tr class='"+cls+"'>";
			strhtml += "<td>"+x+".</td>";
			strhtml += "<td>"+stp.getDescriptionHtml()+"</td>";
			strhtml += "<td>"+stp.getDistance().html+"</td>";
			strhtml += "</tr>";
		}		
		strhtml += "</table>";
		document.getElementById("path").innerHTML = strhtml;
	}
}

// table functions for  table: document.getElementById('message_hd');
function crRowH(attr)
{
	var row = document.createElement('th');	
	row.setAttribute("class",attr);
	return row;
}

function crRow(attr)
{
	var row = document.createElement('tr');	
	row.setAttribute("class",attr);
	return row;
}

function addtblRowH(row)
{
	var th = document.getElementById('message_hd');
	th.appendChild(row);
	return th;
}
function addtblRow(row)
{
	var tbdy = document.getElementById('message_bdy');
	tbdy.appendChild(row);	
	return tbdy;
}

function clearTable()
{
	var tbl = document.getElementById('message');
	var tbdy = document.getElementById('message_bdy');
	var th = document.getElementById('message_hd');
	
	while(th.rows.length > 0)
	{
		th.deleteRow(0);
	}
	
	while(tbdy.rows.length > 0)
	{
		tbdy.deleteRow(0);
	}
}

function crCell(value)
{
	var c = document.createElement('td');
	c.innerHTML = value;
	return c;
}

function crCellH(value, attr, val)
{
	var c = document.createElement('th');
	if(attr !="")
	{
		c.setAttribute(attr,val);
	}
	c.innerHTML = value;
	return c;
}

function addCell(row,cell)
{
	row.appendChild(cell);
	return row;
}
