gogoGoogleMap = 
{
  
  auto_attach_picker: function(form, inline) 
  {
    // Search the document input elements for something named Latitude or Longitude
    // When found one, search for the matching other half
    // Look for any applicable Country, City, Street fields
    //  (to use for geocoding)
    // When we have everything attach a button to the second co-ordinate field (Longitude Probably)
    // which opens the picker window with the current Lat, Lon and Address, and callback for 
    // saving the values
    
    if(!form)
    {
      var forms = document.getElementsByTagName('form');
      for(var x = 0; x < forms.length; x++)
      {
        this.auto_attach_picker(forms[x], inline);
      }      
      return;
    }
    
    // Find input elements
    var ielms = form.getElementsByTagName('input');    
    var telms = form.getElementsByTagName('textarea');
    var inputs = [];
    
    for(var i = 0; i < ielms.length; i++)
    {
      inputs[inputs.length]=ielms[i];
    }
    
    for(var i = 0; i < telms.length; i++)
    {
      inputs[inputs.length]=telms[i];
    }
    
    //alert(inputs.length);
    // Look for lat or lon    
    for(var x = 0; x < inputs.length; x++)
    {
      var fields = { Latitude: null, Longitude: null, Street: null, City: null, Country: null };
      var prefix = null;
      var suffix = null;
      var attachTo = null;
      
      if(inputs[x].name.match(/^(.*)(Latitude|Longitude)(.*)$/))
      {
        prefix = RegExp.$1;                
        suffix = RegExp.$3;        
        var thisIs = RegExp.$2;
        fields[thisIs] = inputs[x];
                
        // And find the matching
        var lookingFor = prefix + (thisIs === 'Latitude' ? 'Longitude' : 'Latitude') + suffix; 
        for(var i = x+1; i < inputs.length; i++)
        {
          if(inputs[i].name == lookingFor)
          {
            fields[(thisIs === 'Latitude' ? 'Longitude' : 'Latitude')] = inputs[i];
            attachTo = inputs[i];
            break;
          }
        }
        
        if(fields.Longitude && fields.Latitude)
        {          
          // Got both, try and find street city and country data
          // note region doesn't work so well because Google gets confused on like
          // "South Island" as a region
          for(var i = 0; i < inputs.length; i++)
          {
            if(fields.Country == null && inputs[i].name === (prefix + 'Country' + suffix))
            {
              fields.Country = inputs[i];
            }
            else if(fields.Region == null && inputs[i].name === (prefix + 'Region' + suffix))
            {
              fields.Region = inputs[i];
            }
            else if(fields.Province == null && inputs[i].name === (prefix + 'Province' + suffix))
            {
              fields.Province = inputs[i];
            }
            else if(fields.City == null && inputs[i].name === (prefix + 'City' + suffix))
            {
              fields.City = inputs[i];
            }
            else if (
              fields.Street == null &&
              (
                    inputs[i].name === (prefix + 'Street' + suffix)
                ||  inputs[i].name === (prefix + 'Address' + suffix)
                ||  inputs[i].name === (prefix + 'Street1' + suffix)
              )
            )
            {              
              fields.Street = inputs[i];
            }
            else
            {
           //                  alert(prefix + ' ' + suffix + ' ' + inputs[i].name);
            }
          }

          if(inline)
          {
            if(typeof inline == 'boolean')
            {
              var mapHolder = document.createElement('div');
              mapHolder.className = 'googleMap clearfloat';
              mapHolder.style.border = '1px solid red;';
              mapHolder.style.display = 'block';
              mapHolder.style.cssFloat = 'none';
              mapHolder.style.clear    = 'both';
              mapHolder.style.height   = '480px';
              mapHolder.style.width    = '100%';
              attachTo.parentNode.appendChild(mapHolder);
              inline = mapHolder;
            }
            this.inline_picker(inline,fields);
          }
          else
          {
            this.attach_picker(attachTo, fields);
          }
          
        }
      }
    }    
    
  },
  
  attach_picker: function(attachTo, fields)
  {
    fields.button_callback = function(Latitude, Longitude)
    {
      this.Latitude.value  = Latitude;
      this.Longitude.value = Longitude;
    }
    
    var afi = this._active_fields.length;
    this._active_fields[this._active_fields.length] = fields;    
    
    var button = document.createElement('input');
    button.type = 'button';
    button.value = 'Map';
    button.gogoGoogleMapFieldIndex = afi;
    
    button.onclick             = function()
      {
        var fields = gogoGoogleMap._active_fields[this.gogoGoogleMapFieldIndex];
        
        // Build an address string
        var address = [ ];
        if(fields.Street.value)
        {
          address[address.length] = fields.Street.value;
        }
        
        if(fields.City.value)
        {
          address[address.length] = fields.City.value;  
        }
        
        if(fields.Country.value)
        {
          address[address.length] = fields.Country.value;
        }
        
        address = address.join(', ');
           
        var url = '/__classpath/gogo/gogoGoogleMap/picker.html?Callback=gogoGoogleMap._active_fields[' + this.gogoGoogleMapFieldIndex + '].button_callback&Address=' + encodeURIComponent(address) + '&Latitude=' + encodeURIComponent(fields.Latitude.value) + '&Longitude=' + encodeURIComponent(fields.Longitude.value);
        
        var win = window.open(url, 'MapWindow', 'width=570,height=540');
        win.focus();
        
      }
      
      attachTo.parentNode.insertBefore(button, attachTo.nextSibling);
  },
  
  inline_picker: function(parentElement, fields)
  {
    var map;
    var selectedMarker;
    var mapHandler = this;
    var zoom       = 1; 
    
    function picker_marker(point)
    {
      if(!point) return false;
      
      if (selectedMarker) 
      {
        map.removeOverlay(selectedMarker);
      }
      selectedMarker = new GMarker(point, {clickable:true,draggable:true}); 
      map.addOverlay(selectedMarker);
      update_point();      
      GEvent.addListener(selectedMarker, "dragend", function() {
        update_point();
      });
    }
    
    function update_point()
    {
      if(!selectedMarker) return false;
      
      var point = selectedMarker.getPoint();
      var lat = Math.round(point.lat() * 100000) / 100000;
      var lng = Math.round(point.lng() * 100000) / 100000;
      fields.Latitude.value  = lat;
      fields.Longitude.value = lng;
      return true;      
    }

    function update_geocode()
    {
      var address = [ ];
      
      zoom = 1;
      
      if(fields.Street.value)
      {
        zoom = Math.max(16,zoom);
        address[address.length] = fields.Street.value;
      }
      
      if(fields.City.value)
      {
        zoom = Math.max(12,zoom);
        address[address.length] = fields.City.value;  
      }
      else 
      {
        if(fields.Province.value)
        {
          zoom = Math.max(8,zoom);
          address[address.length] = fields.Province.value;  
        }
         
        if(fields.Region.value)
        {
          zoom = Math.max(6,zoom);
          address[address.length] = fields.Region.value;  
        }
      }
      
      if(fields.Country.value)
      {
        zoom = Math.max(5,zoom);
        address[address.length] = fields.Country.value;
      }            
      
      
      address = address.join(' ');
      
      // alert(address);
      
      mapHandler.geocode(address,
                         function(point) 
                         { 
                           if(point == null) return false; 
                           if(fields.Street.value) 
                           { 
                             picker_marker(point); 
                           }
                           else
                           {
                              if (selectedMarker) 
                              {
                                map.removeOverlay(selectedMarker);
                              }
                              selectedMarker = null;
                           }
                           map.setCenter(point, zoom); }
                        );
      
    }
    
    if (GBrowserIsCompatible()) 
    {      
      fields.Longitude.gogoGoogleMap =
      fields.Latitude.gogoGoogleMap =
      parentElement.gogoGoogleMap =
      map = new GMap2(parentElement);
          
      map.addControl(new GLargeMapControl());
      map.addControl(new GMapTypeControl());
      
      if(fields.Latitude.value && fields.Longitude.value)
      {
        zoom = 16;
        var point = new GLatLng(fields.Latitude.value, fields.Longitude.value);
        map.setCenter(point, zoom); //-43.531065, 172.636564), 14);                
        picker_marker(point);        
      }
      else
      {
        zoom = 1;
        map.setCenter(new GLatLng(-43.531065, 172.636564), zoom);            
        update_geocode();
      }
      
      GEvent.addListener(map, "dblclick", function(marker, point) 
      { 
        picker_marker(point);
        update_point();            
      });
       
      fields.Longitude.onchange =
      fields.Latitude.onchange  = function()
      {
        var point = new GLatLng(fields.Latitude.value, fields.Longitude.value);
        map.setCenter(point, zoom); //-43.531065, 172.636564), 14);                
        picker_marker(point);        
      }
      
      fields.Street.onchange  =
      fields.City.onchange    =
      fields.Province.onchange    =
      fields.Region.onchange    =
      fields.Country.onchange = function() { update_geocode(); } 
    }
  },
  
  geocode: function(address, point_callback)
  {
    if(this._geocode_cache[address])
    {
      point_callback(this._geocode_cache[address]);
    }
    else
    {
      var mapper = this;
      var geocoder = new GClientGeocoder();
      geocoder.getLatLng
      (
        address,
        function(point) { mapper._geocode_cache[address] = point; point_callback(point); }      
      );
    }
  },
  
  _geocode_cache: { },
  _active_fields: [ ]
}