<?php
/**
* @version	$Id: geocode_helper.php 15137 2012-03-04 08:06:21Z alex $
* @package	In-Portal
* @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license      GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/

	defined('FULL_PATH') or die('restricted access!');

	class GeoCodeHelper extends kHelper {

		/**
		 * Returns Longitude & Latitude by US address provided
		 *
		 * @param string $address
		 * @param string $city
		 * @param string $state
		 * @param string $zip
		 * @return Array
		 */
		function QueryCoordinates($address, $city, $state, $zip)
		{
			$user = $this->Application->ConfigValue('GeoCodeUser');
			$pass = $this->Application->ConfigValue('GeoCodePass');

			$rie_path = sprintf(FULL_PATH.'/tools/rie/rie -u %s -p %s -g "%s" -l',
								$user,
								$pass,
								$address.'|'.$city.'|'.$state.'|'.$zip
						);

			exec($rie_path, $geo_array, $code);

			if ($code == 0) {
				$out_data = explode('|', $geo_array[2]);

//				include_once(FULL_PATH.'/compat/array_combine.php');
				$assoc_data = array_combine(explode('|', $geo_array[1]), $out_data);

				$lon = abs($out_data[8]); // set to positive, because required by SQL formula
				$lat = $out_data[7];

				$zip4 = $out_data[9];
				$dpbc = $out_data[10];
				$carrier = $out_data[11];
			}
			else {
				$lon = '';
				$lat = '';
				$zip4 = '';
				$dpbc = '';
				$carrier = '';
				$assoc_data = Array();
			}

			return Array($lon, $lat, $zip4, $dpbc, $carrier, serialize($assoc_data));
		}

		function getTag($tag, $xml)
		{
			$open_tag_pos = strpos($xml, '<'.$tag.'>');
			$close_tag_pos = strpos($xml, '</'.$tag.'>');
			if (!$open_tag_pos || !$close_tag_pos)
			{
				return '';
			}
			$tag_length = strlen($tag) + 2;
			return substr($xml, $open_tag_pos + $tag_length, $close_tag_pos - $open_tag_pos - $tag_length);
		}

		function QueryCoordinatesFromGoogle($address, $city, $state, $zip)
		{
		//	1908 Pike pl, Seattle, WA
		// http://maps.google.com/maps/geo?
		// ABQIAAAAzNbTbxHki-PAnXzsrA7z2hR0fs2_a3JecCfKmMFhGT8VtEjV7xRV8rMK1czaEH2ZG3eiYJMuej_vnQ

		    $qaddress = $address.', '.$city.', '.$state;
		    $request_url = $this->Application->ConfigValue('GoogleMapsURL').'output=xml&key='.
		    	$this->Application->ConfigValue('GoogleMapsKey').'&q='.urlencode($qaddress);

		    $curl_helper = $this->Application->recallObject('CurlHelper');
			/* @var $curl_helper kCurlHelper */

		    $delay = 0;
		    while (true)
		    {
			    $xml = $curl_helper->Send($request_url);

			    if (strpos($xml, '<code>620</code>')) {
			    	$delay += 100000;
			    } elseif (strpos($xml, '<code>200</code>')) {
			    	// get latitude, longitude and zip  from xml-answer
					$a_coords = explode(',', $this->getTag('coordinates', $xml));
					$lat = $a_coords[1];
					$lon = abs($a_coords[0]); // set to positive, because required by SQL formula
					$zip4 = $this->getTag('PostalCodeNumber', $xml);
					$dpbc = '';
					$carrier = '';
					$assoc_data = Array();
					break;
			    } else {
					$lon = '';
					$lat = '';
					$zip4 = '';
					$dpbc = '';
					$carrier = '';
					$assoc_data = Array();
					break;
			    }
		    	usleep($delay);
		    }

			return Array($lon, $lat, $zip4, $dpbc, $carrier, serialize($assoc_data));

		}

		/**
		 * Try to find lon, lat by address return false if failed
		 *
		 * @param string $address
		 * @param string $city
		 * @param string $state
		 * @param int $zip
		 * @param bool $no_cache
		 * @param bool $force_cache
		 * @return Array|bool (lon, lat)
		 * @access public
		 */
		public function GetCoordinates($address, $city, $state, $zip, $no_cache = false, $force_cache = false)
		{
			if ( !$zip && !$state ) {
				// if state or zip missing then do nothing
				return false;
			}

			$zip_info = $no_cache ? false : $this->GetFromCache($address, $city, $state, $zip);

			if ( !$zip_info && !$force_cache ) {
				list($lon, $lat, $zip4, $dpbc, $carrier, $geocode_answer) = $this->QueryCoordinatesFromGoogle($address, $city, $state, $zip);

				if ( $lon != '' && $lat != '' ) {
					// valid position returned by geocode => add to cache
					$fields_hash = 	Array(
						'zipcode'			=>	$zip4,
						'address'			=>	$address,
						'city'				=>	$city,
						'state'				=>	$state,
						'lat'				=>	$lat,
						'lon'				=>	$lon,
						'zip4'				=>	$zip4,
						'dpbc'				=>	$dpbc,
						'carrier'			=>	$carrier,
						'geocode_answer'	=>	$geocode_answer,
					);

					$this->Conn->doInsert($fields_hash, TABLE_PREFIX . 'ZipCodes');
					return Array ($lon, $lat, $zip4, $dpbc, $carrier);
				}
				else {
					// bad case, rie call failed => no data retrieved
					return false;
				}
			}

			return Array ($zip_info['lon'], $zip_info['lat'], getArrayValue($zip_info, 'zip4'), getArrayValue($zip_info, 'dpbc'), getArrayValue($zip_info, 'carrier'));
		}

		/**
		 * Try to find cached lon, lat by address
		 *
		 * @param string $address
		 * @param string $city
		 * @param string $state
		 * @param int $zip
		 * @return Array|bool (lon, lat)
		 */
		function GetFromCache($address, $city, $state, $zip)
		{
			$zip = substr($zip, 0, 5); // use only first 5 digits
			$sql = 'SELECT lon, lat
					FROM ' . TABLE_PREFIX . 'ZipCodes
					WHERE zipcode = ' . $this->Conn->qstr($zip);
			return $this->Conn->GetRow($sql);
		}
	}