<?php

require_once('GeoCoder.interface.php');
class GeoCoder implements iGeoCoder
{
	private $coordinates = array();
	private $polyline = "";
	
	public function __construct()
	{
		$this->coordinates[0]['lat'] = DEFAULT_LAT;
		$this->coordinates[0]['lon'] = DEFAULT_LON;
		$this->polyline = "";
	}

	public function getCoordinates()
	{
		return $this->coordinates;
	}

	public function getPolyLine()
	{
		return $this->polyline;
	}

	public function lookupCoordinates($Addresses)
	{
		if (is_array($Addresses))
		{
			if($this->queryRouteCoordinates($Addresses))
				return true;
			else
				return false;
		}
		else
		{
			if($this->queryAreaCoordinates($Addresses))
				return true;
			else
				return false;
		}
	}

	private function queryAreaCoordinates($Addresses)
	{
		$coordinates = array();
		$geocode_url =
			sprintf('http://api.local.yahoo.com/MapsService/V1/geocode?appid=%s&location=%s&output=xml',
			YAHOO_KEY, rawurlencode($Addresses));
		$geocode_xml = file_get_contents($geocode_url);
		if($geocode_xml)
		{
	                preg_match('/<Latitude>(.*)\<\/Latitude>/', $geocode_xml, $coordinates['lat']);
			preg_match('/<Longitude>(.*)\<\/Longitude>/', $geocode_xml, $coordinates['lon']);
			$this->coordinates[0]['lat'] = $coordinates['lat'][1];
			$this->coordinates[0]['lon'] = $coordinates['lon'][1];
			return true;
		}
		else
			return false;
	}

	private function queryRouteCoordinates($Addresses)
	{
		$coordinates = array();
		$geocode_url =
		sprintf('http://maps.google.com/maps?ie=UTF-8&oe=UTF-8&hl=en&tab=wl&saddr=%s&daddr=%s&output=js',
			rawurlencode($Addresses[0]), rawurlencode($Addresses[1]));
		$geocode_js = file_get_contents($geocode_url);
		if($geocode_js)
		{
	                preg_match('/\"id\":\"route0\",\"points\":\"(.*)\",\"/', $geocode_js, $polyline);
			if(!isset($polyline[1]))
				return false;
			$temp_coordinates = $this->decodePolyLine($polyline[1]);

			// remove nonsensical coordinates
			$j = 0;
			for($i = 0; $i < count($temp_coordinates); $i++)
			{
				// basic coordinate outline of US
				if( ($temp_coordinates[$i]['lat'] < 50)
					and ($temp_coordinates[$i]['lat'] > 25)
					and ($temp_coordinates[$i]['lon'] < -65)
					and ($temp_coordinates[$i]['lon'] > -125) )
				{
					$this->coordinates[$j]['lat'] = $temp_coordinates[$i]['lat'];
					$this->coordinates[$j]['lon'] = $temp_coordinates[$i]['lon'];
					$j++;
				}
				else {
					break;
				}
			}

			$this->polyline = $polyline[1];
			return true;
		}
		else
			return false;
	}

	// unofficial google hack, adapted return structure
	private function decodePolyline( $a ) {
		$b = strlen($a);
		$c = 0;
		$d = Array();
		$e = 0;
		$f = 0;
		$index = 0;

		while($c < $b)
		{
			$g = 0;
			$h = 0;
			$i = 0;

			do
			{
				$g = ord(substr($a,$c++,1)) - 63;
				$i |= ($g & 31) << $h;
				$h += 5;
			}
			while($g >= 32);

			$k = $i & 1 ? ~($i >> 1) : $i >> 1;
			$e += $k;
			$h = 0;
			$i = 0;

			do {
				$g = ord(substr($a,$c++,1)) - 63;
				$i |= ($g & 31) << $h;
				$h += 5;
			}
			while($g >= 32);

			$l = $i & 1 ? ~($i >> 1) : $i >> 1;
			$f += $l;
			$d[$index]['lat'] = $e*1.0E-5;
			$d[$index]['lon'] = $f*1.0E-5;
			$index++;
		}

		return $d;
	}

}

?>
