// geohash.js
// Geohash library for Javascript
// (c) 2008 David Troy
// Distributed under the MIT License

var GeoHash = {

	BITS = [16, 8, 4, 2, 1];

	BASE32 = 											   "0123456789bcdefghjkmnpqrstuvwxyz";
	NEIGHBORS = { right  : { even :  "bc01fg45238967deuvhjyznpkmstqrwx" },
								left   : { even :  "238967debc01fg45kmstqrwxuvhjyznp" },
								top    : { even :  "p0r21436x8zb9dcf5h7kjnmqesgutwvy" },
								bottom : { even :  "14365h7k9dcfesgujnmqp0r2twvyx8zb" } };
	BORDERS   = { right  : { even : "bcfguvyz" },
								left   : { even : "0145hjnp" },
								top    : { even : "prxz" },
								bottom : { even : "028b" } };

	NEIGHBORS.bottom.odd = NEIGHBORS.left.even;
	NEIGHBORS.top.odd = NEIGHBORS.right.even;
	NEIGHBORS.left.odd = NEIGHBORS.bottom.even;
	NEIGHBORS.right.odd = NEIGHBORS.top.even;

	BORDERS.bottom.odd = BORDERS.left.even;
	BORDERS.top.odd = BORDERS.right.even;
	BORDERS.left.odd = BORDERS.bottom.even;
	BORDERS.right.odd = BORDERS.top.even;

	function refine_interval(interval, cd, mask) {
		if (cd&mask)
			interval[0] = (interval[0] + interval[1])/2;
	  else
			interval[1] = (interval[0] + interval[1])/2;
	}

	function calculateAdjacent(srcHash, dir) {
		srcHash = srcHash.toLowerCase();
		var lastChr = srcHash.charAt(srcHash.length-1);
		var type = (srcHash.length % 2) ? 'odd' : 'even';
		var base = srcHash.substring(0,srcHash.length-1);
		if (BORDERS[dir][type].indexOf(lastChr)!=-1)
			base = calculateAdjacent(base, dir);
		return base + BASE32[NEIGHBORS[dir][type].indexOf(lastChr)];
	}

	function decodeGeoHash(geohash) {
		var is_even = 1;
		var lat = []; var lon = [];
		lat[0] = -90.0;  lat[1] = 90.0;
		lon[0] = -180.0; lon[1] = 180.0;
		lat_err = 90.0;  lon_err = 180.0;
		
		for (i=0; i<geohash.length; i++) {
			c = geohash[i];
			cd = BASE32.indexOf(c);
			for (j=0; j<5; j++) {
				mask = BITS[j];
				if (is_even) {
					lon_err /= 2;
					refine_interval(lon, cd, mask);
				} else {
					lat_err /= 2;
					refine_interval(lat, cd, mask);
				}
				is_even = !is_even;
			}
		}
		lat[2] = (lat[0] + lat[1])/2;
		lon[2] = (lon[0] + lon[1])/2;

		return { latitude: lat, longitude: lon};
	}

	function encodeGeoHash(latitude, longitude) {
		var is_even=1;
		var i=0;
		var lat = []; var lon = [];
		var bit=0;
		var ch=0;
		var precision = 12;
		geohash = "";

		lat[0] = -90.0;  lat[1] = 90.0;
		lon[0] = -180.0; lon[1] = 180.0;
		
		while (geohash.length < precision) {
		  if (is_even) {
				mid = (lon[0] + lon[1]) / 2;
			if (longitude > mid) {
					ch |= BITS[bit];
					lon[0] = mid;
			} else
					lon[1] = mid;
		  } else {
				mid = (lat[0] + lat[1]) / 2;
			if (latitude > mid) {
					ch |= BITS[bit];
					lat[0] = mid;
			} else
					lat[1] = mid;
		  }

			is_even = !is_even;
		  if (bit < 4)
				bit++;
		  else {
				geohash += BASE32[ch];
				bit = 0;
				ch = 0;
		  }
		}
		return geohash;
	}

}