<?php
require_once 'XML/RPC.php';

/**
 * This class converts a street address to latitude-longitude coordinates. Example: 
 * <pre>
 *      $geocoderResult = geocode('1600 Pennsylvania Ave, Washington, DC');
 *      echo $geocoderResult['lat'];
 *      echo $geocoderResult['long']; 
 * </pre> 
 *
 * @author Jonathan Aquino
 */

class GeocodingHelper {	   
    
    /**
     * Given an address or intersection, return its latitude and longitude. Examples of addresses:
     * <ul>
     * <li>1600 Pennsylvania Ave, Washington, DC</li>
     * <li>3601 Lyon Street, 94123</li>
     * <li>Angela and Simonton, Key West, FL</li>
     * </ul>
     * @param string $addressOrIntersection An address or intersection, followed by city and state, or zip code.
     * @return array 
     * @throws XMLRPCException if an XML-RPC error occurs
     * @throws Exception if the address cannot be parsed, or if the address cannot be found.
     * @see http://geocoder.us/help/
     */
    public static function geocode($addressOrIntersection) {
        $parameters = array(new XML_RPC_Value($addressOrIntersection, 'string'));
        $message = new XML_RPC_Message('geocode', $parameters);
        $client = new XML_RPC_Client('/service/xmlrpc', 'rpc.geocoder.us');
        $response = $client->send($message);
        GeocodingHelper::checkResponse($response, $addressOrIntersection);
        $value = $response->value();
        $geocoderResult = XML_RPC_decode($value);
        GeocodingHelper::checkGeocoderResult($geocoderResult, $addressOrIntersection);
        return $geocoderResult[0];
    }
    private static function checkResponse($response, $addressOrIntersection) {
    	// Error handling based on the example given in http://pear.php.net/manual/en/package.webservices.xml-rpc.examples.php [Jon Aquino 2005-09-07]
        if (!$response) { throw new XMLRPCException($client->errstr . ": " . $addressOrIntersection); }
        if ($response->faultCode()) { throw new XMLRPCException($response->faultCode() . " - " . $response->faultString() . ": " . $addressOrIntersection); }
    }

    private static function checkGeocoderResult($geocoderResult, $addressOrIntersection) {
        // The various kinds of results are documented at http://geocoder.us/help/ [Jon Aquino 2005-09-06]
        if (count($geocoderResult ) == 0) { throw new Exception("Address cannot be parsed: " . $addressOrIntersection); }
        if (!isset($geocoderResult [0]['lat'])) { throw new Exception("Address not found: " . $addressOrIntersection); }
    }	    
    public static function geocodeViaMap($subjectType, $form) {
	$mapType = Config::$mapType;
echo <<<HTML
<script defer>
  var map;
  var handler = false;
  var finalizer = false;
  function content_finalize() {
    if( handler.readyState==4) {
      if( window && window.ActiveXObject ) { finalizer( handler ); }
      else finalizer( handler.responseXML );
    }
  }
  function content_load(file,_finalizer) {
    handler = false;
    finalizer = _finalizer;
    if (window && window.ActiveXObject) {
      s = document.getElementById("status");
      s.innerHTML = "Updating map...";
      try {
        handler = new ActiveXObject("Microsoft.XMLDOM");
        handler.async=true;
        handler.onreadystatechange=content_finalize;
      } catch (e) {
        try {
          handler = new ActiveXObject("Microsoft.XMLHTTP");
          handler.async=true;
          handler.onreadystatechange=content_finalize;
        } catch (E) {
          handler = false;
        }
      }
     } else {
      if(window.XMLHttpRequest || XMLHttpRequest != 'undefined') {  
        s = document.getElementById("status");
        s.innerHTML = "Updating map...";
        handler = new XMLHttpRequest();
        handler.onload=content_finalize;
        handler.onreadystatechange=content_finalize;
        handler.open('GET',file, true);
        handler.send("");
        return;
      }
    }
    if(!handler) {
      alert('Your browser can\'t handle this script');
      return;
    }
    handler.load(file);
  }
  function contentget(content,field) {
    if(!content) return "";
    for(var subnode = content.firstChild; subnode != null; subnode = subnode.nextSibling ) {
      if( field == subnode.nodeName ) {
        if( subnode.nodeType == 1 ) {
          if( subnode.firstChild ) {
            return subnode.firstChild.data;
          }
        }
        break;
      }
    }
    return "";
  }

  function node_skip_preamble(content) {
    if(!content) {
      return null;
    }
    for(var node = content; node != null; node = node.nextSibling ) {
      if( node.nodeName == 'items' ) return node;
    }
    for(var node = content.firstChild; node != null; node = node.nextSibling ) {
      if( node.nodeName == 'items' ) return node;
    }
    return null;
  }

  function node_get_first_item(content) {
    if(!content) return null;
    content = node_skip_preamble(content);
    if(!content) return null;
    content = content.firstChild;
    while( content != null && content.nodeName != 'item' ) { content = content.nextSibling; }
    return content;
  }


function finalizeaddress(content) {
  node = node_get_first_item(content);
  if(node) {
     var longitude = contentget(node,"longitude");
     var latitude = contentget(node,"latitude");
     var address = contentget(node,"address");
     var error = contentget(node,"error");
     if(map && longitude != 0 && latitude != 0) {
        s = document.getElementById("status");
        s.innerHTML = "Map Updated.";
        zoom = map.getZoomLevel();
        if (zoom > 4) {
            zoom = 4;
        }
        map.centerAndZoom(new GPoint(longitude,latitude),zoom);
        
        map_refresh_form();
     }
     if (error) {
        s = document.getElementById("status");
        s.innerHTML = "Could not update map: "+error;
     }
  }
}

function getaddress() {
   var node = document.getElementById("address");
   if(!node) return;
   if( node.value && node.value.length > 0 ) addr = node.value; else return;
   var node = document.getElementById("city");
   if( node.value && node.value.length > 0 ) addr += ", " + node.value; else return;
   var node = document.getElementById("state");
   if( node.value && node.value.length > 0 ) addr += ", " + node.value; else return;
   addr = escape(addr);
   addr = "geocode.php?address="+addr;
   content_load(addr,finalizeaddress);
}


    function map_refresh_form() {
        var c = map.getCenterLatLng();
        lon = document.getElementById('gmlong');
        if(lon) {
            lon.value=""+c.x;
        }
        lat = document.getElementById('gmlat');
        if(lat) {
            lat.value=""+c.y;
        }
        zoomLevel = map.getZoomLevel();
        zoom = document.getElementById('gmzoom');
        if(zoom) {
            zoom.value=""+zoomLevel;
        }
        
    }
HTML;

$lon = -122.141944;
$lat = 37.441944;
$span = 50;
if( Config::$googleMapsInitialExtentURL ) {
 $str = Config::$googleMapsInitialExtentURL;
 $str = explode('?',$str);
 if(strlen($str) > 0 ) {
   $str = explode('&',$str[1]);
   foreach($str as $s) {
     if($s[0] == 'l' && $s[1] == 'l' && $s[2] == '=') {
         $ll = explode(',',substr($s,3));
         $lat = floatval($ll[0]);
         $lon = floatval($ll[1]); 
     } else if($s[0]=='s' && $s[1]=='p' && $s[2]=='n' && $s[3]=='=') {
         $span = floatval(substr($s,4));
     }
   }
  }
}

echo <<<HTML
    var mapzoom = 8;
    var latmin = 0;
    var latmax = 0;
    var lonmin = 0;
    var lonmax = 0;
    var zoomarea = 0;
    var latmid = 0;
    var lonmid = 0;
    var maplatch = 0;

    var _zoomLevels = new Array 
    ( 
    0.006909370422363281, 
    0.013818740844726562, 
    0.027637481689453125, 
    0.05527496337890625, 
    0.1105499267578125, 
    0.221099853515625, 
    0.44219970703125, 
    0.8843994140625, 
    1.768798828125, 
    3.53759765625, 
    7.0751953125, 
    14.150390625, 
    28.30078125, 
    56.6015625, 
    113.203125, 
    226.40625, 
    452.8125,
    905.625 ); 

    function calculateZoomLevel(spanLng, spanLat) { 
        var level = _zoomLevels.length-1;
        var found = false; 
        var index = 0; 
        // Get largest value 
        var compareTo = spanLng; 
        if (spanLat>spanLng) compareTo = spanLat; 
        while (!found && index<_zoomLevels.length) { 
            if (_zoomLevels[index]>compareTo)  { 
                level = index; 
                found = true;
            } 
            index++;
        } 
        return level 
    }

    var centermarker = null;
    function map_recenter() {
        var center = map.getCenterLatLng();
        if( centermarker ) {
            map.removeOverlay(centermarker);
            centermarker = new GMarker(new GPoint(center.x,center.y));
            map.addOverlay(centermarker);
        }
        map_refresh_form();
    }

    function map_init(mapdivname) {
        map = new GMap(document.getElementById(mapdivname));
        map.addControl(new GSmallMapControl());
        map.addControl(new GMapTypeControl());
        var span = {$span};
        var lon = {$lon};
        var lat = {$lat};
        span = calculateZoomLevel(span,span/2);
        map.centerAndZoom(new GPoint(lon,lat),span);

        centermarker = new GMarker(new GPoint(lon,lat));
        map.addOverlay(centermarker);
        GEvent.addListener(map, "moveend", map_recenter );
        map.setMapType(map.getMapTypes()[{$mapType}]);
        map_refresh_form();
    }
map_init("selectmap");
getaddress();
HTML;
if ($_POST[$subjectType.":latitude"] && $_POST[$subjectType.":longitude"]) {
    echo "
    if( centermarker ) {
              map.removeOverlay(centermarker);
            }  
              map.centerAndZoom(new GPoint(".$_POST[$subjectType.":longitude"].", ".$_POST[$subjectType.":latitude"]."), {$_POST[$subjectType.":zoomLevel"]});
              centermarker = new GMarker(new GPoint(".$_POST[$subjectType.":longitude"].", ".$_POST[$subjectType.":latitude"]."));
              map.addOverlay(centermarker);</script>";

    echo "<input type='hidden' id='gmlat' name='$subjectType:latitude' value='{$_POST[$subjectType.":latitude"]}' />";
    echo "<input type='hidden' id='gmlong' name='$subjectType:longitude' value='{$_POST[$subjectType.":longitude"]}' />";
    echo "<input type='hidden' id='gmzoom' name='$subjectType:zoomLevel' value='{$_POST[$subjectType.":zoomLevel"]}' />";
            
} else {
    echo "</script>";
    echo $form->hidden($subjectType.":latitude", 'id="gmlat"');
    echo $form->hidden($subjectType.":longitude", 'id="gmlong"');
    echo $form->hidden($subjectType.":zoomLevel", 'id="gmzoom"');
}     
    }
}
class XMLRPCException extends Exception {}
