var localSearch = new GlocalSearch();

//get coordinates using all sorts of APIs and the functions below:
var localSearch = new GlocalSearch();
function getCoords(postcode, callbackFunction) {
  
  localSearch.setSearchCompleteCallback(null,
    function() {
      
      if (localSearch.results[0]) {    
        document.getElementById('locate_latitude').value = localSearch.results[0].lat;
        document.getElementById('locate_longitude').value = localSearch.results[0].lng;
		p=new LatLon(document.getElementById('locate_latitude').value.parseDeg(),document.getElementById('locate_longitude').value.parseDeg());
		os = (LatLongToOSGrid(p));
		if (os){
			document.getElementById('locate_os').value = os
		} else {
			alert("Postcode not valid!");
			return false;
		}
		
		document.getElementById('locate_mx').value = gridrefLetToNum(document.getElementById('locate_os').value)[0];
		document.getElementById('locate_my').value = gridrefLetToNum(document.getElementById('locate_os').value)[1];
		document.getElementById('latlong').innerHTML=' Location: '+ localSearch.results[0].lat +', '+localSearch.results[0].lng
      }else{
        alert("Postcode not found!");
      }
    });  
    
  localSearch.execute(postcode + ", UK");
}
//return key disable

/*function checkCR(evt) {

var evt  = (evt) ? evt : ((event) ? event : null);

var node = (evt.target) ? evt.target : ((evt.srcElement) ? evt.srcElement : null);

if ((evt.keyCode == 13) && (node.type=="text")) {return false;}

}

document.onkeypress = checkCR;
*///
//
//
//function to cycle through the spans calculating distances
/*function getDistances(){
	distanceArray = new Array();
	var myRE = /^calc[0-9\.\-\,\:]+$/;
	var elem = document.getElementsByTagName('span');
	var j=0;
	for (var i = 0; i < elem.length; i++) {
		if (elem[i].id.match(myRE)){
			pcArray = elem[i].id.split(':')
			distanceArray[j] = new Array();
			distanceArray[j]['from'] = pcArray[1]
			distanceArray[j]['to'] = pcArray[2]
			distanceArray[j]['id'] = elem[i].id
			++j;
		}
	}	
}*/
function getDistances(sightsArray, method){
	distanceArray = new Array();
	for (var i = 0; i < sightsArray.length; i++) {
		pcArray = sightsArray[i].split(':')
		distanceArray[i] = new Array();
		distanceArray[i]['from'] = from
		distanceArray[i]['to'] = pcArray[1]
		distanceArray[i]['id'] = pcArray[0]
	}	
	method == 'crow' ? calculateCrowDistances() : calculateRoadDistances();
}
//
/*function calculateDistances(){
	GUnload();
	gd = new GDirections();
	fromto = "from: "+distanceArray[0]['from'] + " to: " + distanceArray[0]['to'];
	//gd.load("from: "+distanceArray[0]['from'] + ",UK to: " + distanceArray[0]['to'] + ", UK");
	gd.load(fromto);
	  GEvent.addListener(gd,"error",function() {
		document.getElementById(distanceArray[0]['id']).innerHTML = "Error: status: " + gd.getStatus().code;
		distanceArray.shift();
		calculateDistances();
	  });
	  GEvent.addListener(gd,"load",function() {
		// should always be 200 for a successful load
		document.getElementById(distanceArray[0]['id']).innerHTML = (gd.getDistance().meters/1604).toFixed(2) + " miles";
		distanceArray.shift();
		if (distanceArray.length == 0) window.clearInterval(distanceInterval);
	  }); 
}*/
function calculateRoadDistances(){
	if (!distanceArray[0]){
		return false;
	}
	//GUnload();
	gd = new GDirections();
	fromto = "from: "+distanceArray[0]['from'] + " to: " + distanceArray[0]['to'];
	//alert (fromto);
	gd.load(fromto);		
	GEvent.addListener(gd,"error",function() {
		document.getElementById(distanceArray[0]['id']).innerHTML = 'error';
		distanceArray.shift();
		calculateRoadDistances();
	});
	GEvent.addListener(gd,"load",function() {
		// should always be 200 for a successful load
		document.getElementById(distanceArray[0]['id']).innerHTML = '<a href="http://maps.google.com/maps?f=d&amp;hl=en&amp;geocode=&amp;saddr='+distanceArray[0]['from']+'&amp;daddr='+distanceArray[0]['to']+'" target="_blank">'+(gd.getDistance().meters/1604).toFixed(2) + ' miles</a>';
		distanceArray.shift();
		calculateRoadDistances();
	}); 
}
function calculateCrowDistances(){
	dLatLon = distanceArray[0]['from'].split(',');
	aLatLon = distanceArray[0]['to'].split(',');
	var R = 6371; // km
	var dLat = (dLatLon[0]-aLatLon[0]).toRad();
	var dLon = (dLatLon[1]-aLatLon[1]).toRad(); 
	var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
			Math.cos(parseFloat(dLatLon[0]).toRad()) * Math.cos(parseFloat(aLatLon[0]).toRad()) * 
			Math.sin(dLon/2) * Math.sin(dLon/2); 
	var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
	var d = R * c;
	document.getElementById(distanceArray[0]['id']).innerHTML = (d/1.604).toFixed(2) + ' miles</a>';
	distanceArray.shift();
	if (!distanceArray[0]){
		return false;
	}
	calculateCrowDistances();
}
//
/*
 * convert geodesic co-ordinates to OS grid reference
 *   see www.gps.gov.uk/guidecontents.asp Annex C
 */
function LatLongToOSGrid(p) {
  var lat = p.lat.toRad(), lon = p.lon.toRad();
  
  var a = 6377563.396, b = 6356256.910;          // Airy 1830 major & minor semi-axes
  var F0 = 0.9996012717;                         // NatGrid scale factor on central meridian
  var lat0 = (49).toRad(), lon0 = (-2).toRad();  // NatGrid true origin
  var N0 = -100000, E0 = 400000;                 // northing & easting of true origin, metres
  var e2 = 1 - (b*b)/(a*a);                      // eccentricity squared
  var n = (a-b)/(a+b), n2 = n*n, n3 = n*n*n;

  var cosLat = Math.cos(lat), sinLat = Math.sin(lat);
  var nu = a*F0/Math.sqrt(1-e2*sinLat*sinLat);              // transverse radius of curvature
  var rho = a*F0*(1-e2)/Math.pow(1-e2*sinLat*sinLat, 1.5);  // meridional radius of curvature
  var eta2 = nu/rho-1;

  var Ma = (1 + n + (5/4)*n2 + (5/4)*n3) * (lat-lat0);
  var Mb = (3*n + 3*n*n + (21/8)*n3) * Math.sin(lat-lat0) * Math.cos(lat+lat0);
  var Mc = ((15/8)*n2 + (15/8)*n3) * Math.sin(2*(lat-lat0)) * Math.cos(2*(lat+lat0));
  var Md = (35/24)*n3 * Math.sin(3*(lat-lat0)) * Math.cos(3*(lat+lat0));
  var M = b * F0 * (Ma - Mb + Mc - Md);              // meridional arc

  var cos3lat = cosLat*cosLat*cosLat;
  var cos5lat = cos3lat*cosLat*cosLat;
  var tan2lat = Math.tan(lat)*Math.tan(lat);
  var tan4lat = tan2lat*tan2lat;

  var I = M + N0;
  var II = (nu/2)*sinLat*cosLat;
  var III = (nu/24)*sinLat*cos3lat*(5-tan2lat+9*eta2);
  var IIIA = (nu/720)*sinLat*cos5lat*(61-58*tan2lat+tan4lat);
  var IV = nu*cosLat;
  var V = (nu/6)*cos3lat*(nu/rho-tan2lat);
  var VI = (nu/120) * cos5lat * (5 - 18*tan2lat + tan4lat + 14*eta2 - 58*tan2lat*eta2);

  var dLon = lon-lon0;
  var dLon2 = dLon*dLon, dLon3 = dLon2*dLon, dLon4 = dLon3*dLon, dLon5 = dLon4*dLon, dLon6 = dLon5*dLon;

  var N = I + II*dLon2 + III*dLon4 + IIIA*dLon6;
  var E = E0 + IV*dLon + V*dLon3 + VI*dLon5;

  return gridrefNumToLet(E, N, 8);
}


/*
 * convert OS grid reference to geodesic co-ordinates
 */
function OSGridToLatLong(gridRef) {
  var gr = gridrefLetToNum(gridRef);
  var E = gr[0], N = gr[1];

  var a = 6377563.396, b = 6356256.910;              // Airy 1830 major & minor semi-axes
  var F0 = 0.9996012717;                             // NatGrid scale factor on central meridian
  var lat0 = 49*Math.PI/180, lon0 = -2*Math.PI/180;  // NatGrid true origin
  var N0 = -100000, E0 = 400000;                     // northing & easting of true origin, metres
  var e2 = 1 - (b*b)/(a*a);                          // eccentricity squared
  var n = (a-b)/(a+b), n2 = n*n, n3 = n*n*n;

  var lat=lat0, M=0;
  do {
    lat = (N-N0-M)/(a*F0) + lat;

    var Ma = (1 + n + (5/4)*n2 + (5/4)*n3) * (lat-lat0);
    var Mb = (3*n + 3*n*n + (21/8)*n3) * Math.sin(lat-lat0) * Math.cos(lat+lat0);
    var Mc = ((15/8)*n2 + (15/8)*n3) * Math.sin(2*(lat-lat0)) * Math.cos(2*(lat+lat0));
    var Md = (35/24)*n3 * Math.sin(3*(lat-lat0)) * Math.cos(3*(lat+lat0));
    M = b * F0 * (Ma - Mb + Mc - Md);                // meridional arc

  } while (N-N0-M >= 0.00001);  // ie until < 0.01mm

  var cosLat = Math.cos(lat), sinLat = Math.sin(lat);
  var nu = a*F0/Math.sqrt(1-e2*sinLat*sinLat);              // transverse radius of curvature
  var rho = a*F0*(1-e2)/Math.pow(1-e2*sinLat*sinLat, 1.5);  // meridional radius of curvature
  var eta2 = nu/rho-1;

  var tanLat = Math.tan(lat);
  var tan2lat = tanLat*tanLat, tan4lat = tan2lat*tan2lat, tan6lat = tan4lat*tan2lat;
  var secLat = 1/cosLat;
  var nu3 = nu*nu*nu, nu5 = nu3*nu*nu, nu7 = nu5*nu*nu;
  var VII = tanLat/(2*rho*nu);
  var VIII = tanLat/(24*rho*nu3)*(5+3*tan2lat+eta2-9*tan2lat*eta2);
  var IX = tanLat/(720*rho*nu5)*(61+90*tan2lat+45*tan4lat);
  var X = secLat/nu;
  var XI = secLat/(6*nu3)*(nu/rho+2*tan2lat);
  var XII = secLat/(120*nu5)*(5+28*tan2lat+24*tan4lat);
  var XIIA = secLat/(5040*nu7)*(61+662*tan2lat+1320*tan4lat+720*tan6lat);

  var dE = (E-E0), dE2 = dE*dE, dE3 = dE2*dE, dE4 = dE2*dE2, dE5 = dE3*dE2, dE6 = dE4*dE2, dE7 = dE5*dE2;
  lat = lat - VII*dE2 + VIII*dE4 - IX*dE6;
  var lon = lon0 + X*dE - XI*dE3 + XII*dE5 - XIIA*dE7;

  return new LatLon(lat.toDeg(), lon.toDeg());
}


/* 
 * convert standard grid reference ('SU387148') to fully numeric ref ([438700,114800])
 *   returned co-ordinates are in metres, centred on grid square for conversion to lat/long
 *
 *   note that northern-most grid squares will give 7-digit northings
 *   no error-checking is done on gridref (bad input will give bad results or NaN)
 */
function gridrefLetToNum(gridref) {
  // get numeric values of letter references, mapping A->0, B->1, C->2, etc:
  var l1 = gridref.toUpperCase().charCodeAt(0) - 'A'.charCodeAt(0);
  var l2 = gridref.toUpperCase().charCodeAt(1) - 'A'.charCodeAt(0);
  // shuffle down letters after 'I' since 'I' is not used in grid:
  if (l1 > 7) l1--;
  if (l2 > 7) l2--;

  // convert grid letters into 100km-square indexes from false origin (grid square SV):
  var e = ((l1-2)%5)*5 + (l2%5);
  var n = (19-Math.floor(l1/5)*5) - Math.floor(l2/5);

  // skip grid letters to get numeric part of ref, stripping any spaces:
  gridref = gridref.slice(2).replace(/ /g,'');

  // append numeric part of references to grid index:
  e += gridref.slice(0, gridref.length/2);
  n += gridref.slice(gridref.length/2);

  // normalise to 1m grid, rounding up to centre of grid square:
  switch (gridref.length) {
    case 6: e += '50'; n += '50'; break;
    case 8: e += '5'; n += '5'; break;
    // 10-digit refs are already 1m
  }

  return [e, n];
}


/*
 * convert numeric grid reference (in metres) to standard-form grid ref
 */
function gridrefNumToLet(e, n, digits) {
  // get the 100km-grid indices
  var e100k = Math.floor(e/100000), n100k = Math.floor(n/100000);
  
  if (e100k<0 || e100k>6 || n100k<0 || n100k>12) return '';

  // translate those into numeric equivalents of the grid letters
  var l1 = (19-n100k) - (19-n100k)%5 + Math.floor((e100k+10)/5);
  var l2 = (19-n100k)*5%25 + e100k%5;

  // compensate for skipped 'I' and build grid letter-pairs
  if (l1 > 7) l1++;
  if (l2 > 7) l2++;
  var letPair = String.fromCharCode(l1+'A'.charCodeAt(0), l2+'A'.charCodeAt(0));

  // strip 100km-grid indices from easting & northing, and reduce precision
  e = Math.floor((e%100000)/Math.pow(10,5-digits/2));
  n = Math.floor((n%100000)/Math.pow(10,5-digits/2));

  var gridRef = letPair + e.padLZ(digits/2) + n.padLZ(digits/2);

  return gridRef;
}


/*
 * pad a number with sufficient leading zeros to make it w chars wide
 */
Number.prototype.padLZ = function(w) {
var n = this.toString();
var l = n.length;
for (var i=0; i<w-l; i++) { 
	n = '0' + n;
  }
  return n;
}


// ---- the following are duplicated from LatLong.html ---- //


/*
 * construct a LatLon object: arguments in numeric degrees
 *
 * note all LatLong methods expect & return numeric degrees (for lat/long & for bearings)
 */
function LatLon(lat, lon) {
  this.lat = lat;
  this.lon = lon;
}


// 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;
}

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


// extend Number object with methods for presenting bearings & lat/longs

Number.prototype.toDMS = function() {  // convert numeric degrees to deg/min/sec
  var d = Math.abs(this);  // (unsigned result ready for appending compass dir'n)
  d += 1/7200;  // add ½ second for rounding
  var deg = Math.floor(d);
  var min = Math.floor((d-deg)*60);
  var sec = Math.floor((d-deg-min/60)*3600);
  // add leading zeros if required
  if (deg<100) deg = '0' + deg; if (deg<10) deg = '0' + deg;
  if (min<10) min = '0' + min;
  if (sec<10) sec = '0' + sec;
  return deg + '\u00B0' + min + '\u2032' + sec + '\u2033';
}

Number.prototype.toLat = function() {  // convert numeric degrees to deg/min/sec latitude
  return this.toDMS().slice(1) + (this<0 ? 'S' : 'N');  // knock off initial '0' for lat!
}

Number.prototype.toLon = function() {  // convert numeric degrees to deg/min/sec longitude
  return this.toDMS() + (this>0 ? 'E' : 'W');
}
//
//
//array multisort
function multisort(arrayOfArrays){
if(!arrayOfArrays || typeof(arrayOfArrays)!="object"){return false;};
var gather=[];
//Sort leading array only.
arrayOfArrays[0].sort(
	function(a,b){
	return gather[++gather.length-1]=(a-b)
	}
);
//Reorder other arrays:
for(var i=1; i<arrayOfArrays.length; i++){
var feedIterator=0;
arrayOfArrays[i].sort(
	function(a,b){
	return gather[feedIterator++];
	}
);
}
return arrayOfArrays;
/* keep this comment to reuse freely:
http://www.fullposter.com/?1 */
}