var GoogleMap = function() {
  var marker, map, point, geocoder;
  var addr_id, desc_id, lat_id, load_id, long_id, map_id, warn_id, zoom_id;

  return {
    initialize: function(id, coord, zoom) {
      addr_id = "address_google_map";
      desc_id = "description_google_map";
      lat_id  = "latitude_google_map";
      load_id = "loading_google_map";
      long_id = "longitude_google_map";
      map_id  = "view_google_map";
      warn_id = "warning_google_map";
      zoom_id = "zoom_google_map";

      if(id != "") {
        var append   = "_" + id;
        addr_id += append;
        desc_id += append;
        lat_id  += append;
        load_id += append;
        long_id += append;
        map_id  += append;
        warn_id += append;
        zoom_id += append;
      }

      geocoder = new GClientGeocoder();
      point    = new GLatLng(coord[0], coord[1]);
      marker   = new GMarker(point, { draggable: true });
      marker.bindInfoWindow(this.infoWindow());
      this.setLatLng(point);

      map = new GMap2($(map_id));
      map.addControl(new GLargeMapControl());
      map.addControl(new GMapTypeControl());
      this.initializeListeners();
      map.setCenter(point, zoom);
      map.addOverlay(marker);

      this.showInfoWindow();
      this.hideLoading();
    },

    initializeListeners: function() {
      var that = this;
      GEvent.addListener(marker, "click", function() {
        that.showInfoWindow();
      });

      GEvent.addListener(marker, "dragstart", function() {
        marker.closeInfoWindow();
      });

      GEvent.addListener(marker, "dragend", function() {
        that.showInfoWindow();
        that.setLatLng(marker.getPoint());
      });

      GEvent.addListener(map, "zoomend", function(o, n) {
        $(zoom_id).value = n;
      });

      Event.observe(window, 'unload', function() {
        GUnload();
      });
    },

    infoWindow: function() {
      var desc = this.getDescription();
      if(desc == "") { return null; }

      return new Element("div", { "class": "google-map-info-window" }).update(desc);
    },
    
    showInfoWindow: function() {
      var inner = this.infoWindow();
      if(inner) {
        marker.openInfoWindow(inner);
      } else {
        marker.closeInfoWindow();
        map.setCenter(marker.getPoint());
      }
    },

    refreshMap: function() {
      this.showLoading();
      this.setLatLng(marker.getPoint());
      this.showInfoWindow();
      this.hideLoading();
    },

    refreshAddress: function() {
      this.showLoading();
      address = $(addr_id).value;
      if(address != '') {
        var that = this;
        geocoder.getLatLng(address, this.refreshMarker.bind(this));
      }
      this.hideLoading();
    },

    refreshMarker: function(point) {
      if(point == null) {
        $(warn_id).show();
      } else {
        $(warn_id).hide();
        map.setCenter(point, map.getZoom());
        marker.setLatLng(point);
        this.refreshMap();
      }
    },

    getDescription: function()  { return $(desc_id).value; },
    getZoom:        function()  { return $(zoom_id).value; },
    hideLoading:    function()  { $(load_id).hide(); },
    showLoading:    function()  { $(load_id).show(); },
    refreshInfo:    function()  { this.showLoading(); this.showInfoWindow(); this.hideLoading(); },
    setLatLng:      function(p) { $(lat_id).value  = p.lat(); $(long_id).value = p.lng(); }
  };
};

GoogleMap.render = function(map_id, coord, zoom, desc) {
  var point  = new GLatLng(coord[0], coord[1]);
  var marker = new GMarker(point, { draggable: false });
  
  var map = new GMap2($(map_id));
  map.addControl(new GLargeMapControl());
  map.addControl(new GMapTypeControl());
  map.setCenter(point, zoom);
  map.addOverlay(marker);

  if(desc != "") {
    marker.openInfoWindow(new Element("div", { "class": "google-map-info-window" }).update(desc));
  }
};

