/**
 * Support functions for Google Maps interaction.
 */
var GoogleMapsSupport = {
  _maps: [],
  
  /**
   * Registers a map.
   */
  registerMap: function(map, point) {
    point = point || map.getCenter();
    this._maps.push({map: map, point: point});
  },
  
  /**
   * Check resize on all registered maps.
   */
  checkAllResize: function() {
    this._maps.each(function(hash) {
      // This forces the map to reconsider its existence
      var map = hash.map;
      map.checkResize();
      
      // GMaps tend to select the wrong panning position when a map is re-shown, so fix this
      var point = hash.point;
      if (point) {        
        map.setCenter(point);
      }
    });
  }
};

if (typeof GIcon != "undefined") {
  ICONS = {};

  ICONS['venue'] = new GIcon();
  ICONS['venue'].iconSize = new GSize(21,31);
  ICONS['venue'].iconAnchor = new GPoint(10, 31);
  ICONS['venue'].shadowSize = new GSize(21, 31);
  ICONS['venue'].infoWindowAnchor = new GPoint(11, 5);
  ICONS['venue'].image = "/images/markers/green.png";
  ICONS['venue'].shadow = "/images/markers/color_marker_shadow.png";

  ICONS['bulletin'] = new GIcon();
  ICONS['bulletin'].iconSize = new GSize(21,31);
  ICONS['bulletin'].iconAnchor = new GPoint(10, 31);
  ICONS['bulletin'].shadowSize = new GSize(21, 31);
  ICONS['bulletin'].infoWindowAnchor = new GPoint(11, 5);
  ICONS['bulletin'].image = "/images/markers/orange.png";
  ICONS['bulletin'].shadow = "/images/markers/color_marker_shadow.png";
  ICONS['pro_con'] = ICONS['bulletin']

  ICONS['workgroup'] = new GIcon();
  ICONS['workgroup'].iconSize = new GSize(21,31);
  ICONS['workgroup'].iconAnchor = new GPoint(10, 31);
  ICONS['workgroup'].shadowSize = new GSize(21, 31);
  ICONS['workgroup'].infoWindowAnchor = new GPoint(11, 5);
  ICONS['workgroup'].image = "/images/markers/blue.png";
  ICONS['workgroup'].shadow = "/images/markers/color_marker_shadow.png";
  ICONS['local_paper'] = ICONS['workgroup']

  ICONS['faceless_user'] = new GIcon();
  ICONS['faceless_user'].iconSize = new GSize(22,29);
  ICONS['faceless_user'].iconAnchor = new GPoint(10, 28);
  ICONS['faceless_user'].shadowSize = new GSize(21, 31);
  ICONS['faceless_user'].infoWindowAnchor = new GPoint(11, 5);
  ICONS['faceless_user'].image = "/images/markers/faceless_user_24.png";
  ICONS['faceless_user'].shadow = "/images/markers/color_marker_shadow.png";
}

var MarkerNavigator = {
  attach: function(map, baseUrl, options) {
    this.baseUrl = baseUrl;
    this.map = map;
		this.markers = new Hash();
    this.options = options || {};
    GEvent.addListener(this.map, "movestart", this.hideBubbles.bind(this));
    GEvent.addListener(this.map, "moveend", this.update.bind(this));
    GEvent.addListener(this.map, "zoomend", function() { 
																													this.clear_markers(); 
																												}.bind(this));
    this.progressControl = new LProgressControl(this.map);
		this.map.addControl(this.progressControl);
    this.update();
  },
  
  hideBubbles: function() {
  },

	open_info_url: function(gmarker, url) {
    gmarker.openInfoWindowHtml('<img src="/images/progress/lights.gif"/>');
    var request = new Ajax.Request(url, {
			method: 'get',
			onComplete: function(xhr) {
				gmarker.openInfoWindowHtml(xhr.responseText);
			}.bind(this)
		});		
	},

	set_markers: function(markers) {
		markers.each(function(marker) {
			if (!this.markers[marker['id']]) {
				var point = new GLatLng(marker['lat'], marker['lng'])
				if (marker['icon']['type']) {
					icon = ICONS[marker['icon']['type']];
				} else {					
					icon = new GIcon();
					dims = marker['icon']['dimensions']
					icon.iconSize = new GSize(dims[0], dims[1]);
					icon.iconAnchor = new GPoint(dims[2], dims[3]);
					icon.shadowSize = new GSize(dims[4], dims[5]);
					icon.infoWindowAnchor = new GPoint(dims[6], dims[7]);
					icon.image = marker['icon']['image'];
					icon.shadow = marker['icon']['shadow'];
				}
        var gmarker = new GMarker(point, icon);
        GEvent.addListener(gmarker, 'click', 
          function() {
            this.open_info_url(gmarker, marker['content_url']);
          }.bind(this))
				this.map.addOverlay(gmarker);
				this.markers[marker['id']] = gmarker;
			}
		}.bind(this))
	},
	
  // constructs a "slightly bigger" GLatLngBounds box
	_getExpandedMapBounds: function() {
    var bounds = this.map.getBounds();
    var southWest = bounds.getSouthWest();
    var northEast = bounds.getNorthEast();
    var lngDelta = (northEast.lng() - southWest.lng()) * 1.015;
    var latDelta = (northEast.lat() - southWest.lat()) * 1.1;
    var rectBounds = new GLatLngBounds(
        new GLatLng(northEast.lat() - latDelta, northEast.lng() - lngDelta),
        new GLatLng(southWest.lat() + latDelta, southWest.lng() + lngDelta)
      );
    return rectBounds;
	},
	
	prune_markers: function() {
		var bounds = this._getExpandedMapBounds();
		this.markers.each(function(marker_entry) {
			if(!(bounds.containsLatLng(marker_entry.value.getPoint()))) {
				this.map.removeOverlay(marker_entry.value);
				delete this.markers[marker_entry.key]
			}			
		}.bind(this));
	},
	
	clear_markers: function() {
		this.markers = new Hash();
		this.map.clearOverlays();
	},
	
  update: function() {
    this.prune_markers();
    var map = this.map;
    var bounds = map.getBounds();
		this.progressControl.loading();
    if (this.options.sandboxId) {
      requestUrl = "/markers/" + this.options.sandboxId;
    } else {  
      requestUrl = "/markers"
    }
    if (this.options.limit) {
      requestUrl += "?limit=" + this.options.limit;
    }
  	var request = new Ajax.Request(this.baseUrl + requestUrl, {
  		method: 'get',
  		parameters: $H({
  		  sw_lat: bounds.getSouthWest().lat(),
  		  sw_lng: bounds.getSouthWest().lng(),
  		  ne_lat: bounds.getNorthEast().lat(),
  		  ne_lng: bounds.getNorthEast().lng(),
				format: 'json'
  		}).toQueryString(),
  		onComplete: function(xhr) {
				this.progressControl.done();
    		try {
    			eval("markerData = " + xhr.responseText);
    			this.set_markers(markerData['markers']);
        } catch (e) {
          alert("Error: " + e);
        }
  		}.bind(this)
  	});
  }
}

if (typeof GControl != "undefined") {
  
  function LProgressControl() {
  }

  LProgressControl.prototype = new GControl();

  LProgressControl.prototype.initialize = function(map) {
  	this.map = map
    var progressDiv = $(document.createElement("div"));
    this.map.getContainer().appendChild(progressDiv);
  	var spinner = $(document.createElement('img'));
  	spinner.src = "/images/progress/lights.gif";
  	spinner.style.display = 'block';
  	this.spinner = spinner;
  	progressDiv.appendChild(spinner);
  	this.loading_status = 0;
  	return progressDiv;
  };

  LProgressControl.prototype.loading = function() {
  	this.loading_status += 1;
  	if (this.loading_status > 0) {
  		this.spinner.style.display = 'block';
  	}
  };

  LProgressControl.prototype.done = function() {
  	this.loading_status -= 1;
  	if (this.loading_status < 1) {
  		this.spinner.style.display = 'none';
  	}
  };


  LProgressControl.prototype.getDefaultPosition = function() { 
  	return(new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(3,17)))
  };


  function LGeoCoderControl() {
  };

  LGeoCoderControl.prototype = new GControl();

  LGeoCoderControl.prototype.initialize = function(map) { 
  	this.map = map;
  	this.defaultText = 'Stedsnavn eller adresse';
	
    var navigatorDiv = $(document.createElement("div"));
    this.map.getContainer().appendChild(navigatorDiv);
  		
  	var controlsDiv = $(document.createElement('div'));
  	controlsDiv.className = "map_search_controls";
  	locationInputElement = $(document.createElement('input'));
  	locationInputElement.size = 20;
  	locationInputElement.value = this.defaultText;
  	locationInputElement.addClassName("unset");
  	locationInputElement.onfocus = function() {
  		if (locationInputElement.value == this.defaultText) {
  			locationInputElement.value = '';
  			locationInputElement.removeClassName("unset");
  		}
  	}.bind(this);
  	locationInputElement.onblur = function() {
  		if (locationInputElement.value == '') {
  			locationInputElement.value = this.defaultText;
  			locationInputElement.addClassName("unset");
  		}
  	}.bind(this);
  	Event.observe(locationInputElement, "keypress", function(event) {
      if (Event.getKey(event) == Event.KEY_RETURN) {
    		this.lookup(this.locationInputElement.value);
  			Event.stop(event);
  		}
  	}.bind(this));
  	controlsDiv.appendChild(locationInputElement);	
  	this.locationInputElement = locationInputElement;
  	controlsDiv.appendChild(Button.linkToFunction(_("Søk"), function(event) {
  		this.lookup(this.locationInputElement.value);
  	}.bind(this), {size: "small", color: "white"}));	
    if (this.onRemove) {
    	controlsDiv.appendChild(Button.linkToFunction(_("Fjern"), function(event) {
    		this.remove();
    	}.bind(this), {size: "small", color: "white"}));
  	}
  	navigatorDiv.appendChild(controlsDiv);

  	var spinner = $(document.createElement('img'));
  	spinner.src = "/images/progress/spinner_16.gif";
  	spinner.className = "progress_indicator"
  	spinner.style.display = 'none';
  	this.spinner = spinner;
  	navigatorDiv.appendChild(this.spinner);

	
  	var messageDiv = $(document.createElement('div'));
  	messageDiv.style.display = 'none';
  	messageDiv.className = "map_search_result";
  	this.messageDiv = messageDiv;
  	navigatorDiv.appendChild(messageDiv);
  	return navigatorDiv;
  }

  LGeoCoderControl.prototype.getDefaultPosition = function() { 
  	return(new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(5, 5)))
  };

  LGeoCoderControl.prototype.remove = function() {
    this.closeBalloon();
    if (this.onRemove) {
      this.onRemove();
  	}
  };

  LGeoCoderControl.prototype.lookup = function(text) {
  	if (text != this.defaultText && text.length > 0) { 
    	this.locationInputElement.value = text;
    	this.locationInputElement.removeClassName("unset");

      this.spinner.style.display = 'inline';
    	this.map.closeInfoWindow();
	
    	if (this.onInitiate) {
    		this.onInitiate();
    	}

      var bounds = this.map.getBounds();
      var southWest = bounds.getSouthWest();
      var northEast = bounds.getNorthEast();
      
      var lat_diff = northEast.lat() - southWest.lat();
      var lng_diff = northEast.lng() - southWest.lng();

    	var ajax = new Ajax.Request('/-/map/geocode', {
    		method: 'get', 			
    		parameters: $H({
    			location: text,
    			lng: this.map.getCenter().lng(),
    			lat: this.map.getCenter().lat(),
    			lat_diff: lat_diff,
    			lng_diff: lng_diff
    		}).toQueryString(),

    		onFailure: function(t) {
    		  if (this.onMiss) {
    				this.onMiss();
    			}
    			this.messageDiv.innerHTML = _('Fikk ikke kontakt med serveren. Prøv igjen senere');
    			new Effect.Appear(this.messageDiv, {duration: 0.2});
    			new Effect.Fade(this.messageDiv, {delay: 4, duration: 2});
    		}.bind(this),
		
    		onComplete: function(xhr) {
  		    this.closeBalloon();
    			this.spinner.hide();
    			eval(xhr.responseText);
          
    			if (geoCode.message) {
    				this.messageDiv.innerHTML = geoCode.message;
    				new Effect.Appear(this.messageDiv, {duration: 0.2});
    				new Effect.Fade(this.messageDiv, {delay: 4, duration: 2});
    			}

    			if (geoCode.length && geoCode.length > 0) {
    			  var hits = geoCode;
    			  var hit = hits[0];
    				this.onHit(new GLatLng(hit['lat'], hit['lng']), hits);
    				if (geoCode.length > 1) {
      				this.balloon = new Balloon({
                origin: this.locationInputElement,
                className: "map_geocoder_balloon",
                content: this.createHitList(text, hits),
                position: new Balloon.Position.Vertical(-75, -5),
                tail: null,
                rounded: true
              });
              this.balloon.open();
            }
    			} else if (this.onMiss) {
    				this.onMiss();
    			}			
    		}.bind(this),
		
        onException: function(request, exception) {
          Errors.log(exception);
        }.bind(this)			
    	});	
  	}
  };
	
  LGeoCoderControl.prototype.createHitList = function(query, hits) {
    var place = hits[0].matchText;
    if (hits[0].municipality) {
      place += " ";
      place += _("i");
      place += " ";
      place += hits[0].municipality;
    }
      
    var element = $(document.createElement("div"));
    var h4 = $(document.createElement("h4"));
    h4.appendChild(document.createTextNode(_("Vi tror du mente %s. Andre steder som passet:", place)));
    element.appendChild(h4);
  
    var list = $(document.createElement("ul"));
  	hits.slice(0, 3).each(function(hit) {
  	  list.appendChild(this.createHitItem(hit, hits));
  	}.bind(this));
    element.appendChild(list);

    if (hits.length > 3) {  
      var expandLink = $(document.createElement("a"));
      expandLink.href = "#";
      expandLink.appendChild(document.createTextNode(_("(Vis alle %s treff…)", hits.length)));
      expandLink.observe("click", function(event) {
        Event.element(event).remove();
        list2.show();
      	Event.stop(event);
      });
      element.appendChild(expandLink);
    
      var list2 = $(document.createElement("ul"));
      list2.style.display = "none";
    	hits.slice(3, 100).each(function(hit) {
    	  list2.appendChild(this.createHitItem(hit));
      }.bind(this));
      element.appendChild(list2);
    }
  
    return element;
  };

  LGeoCoderControl.prototype.createHitItem = function(hit, hits) {
    var item = $(document.createElement("li"));
    var link = $(document.createElement("a"));
    link.href = "#";
    link.appendChild(document.createTextNode(
      _("%s (%s)", hit.matchText, hit.municipality)));
    link.observe("click", function(event) {
      this.closeBalloon();
      this.locationInputElement.value = hit.matchText + ", " + hit.municipality;
    	this.onHit(new GLatLng(hit.lat, hit.lng), hits);
    	Event.stop(event);
    }.bind(this));
    item.appendChild(link);
    return item;
  };

  LGeoCoderControl.prototype.closeBalloon = function() {
  	if (this.balloon) {
  	  this.balloon.close();
  	  this.balloon = null;
  	}	  
  };

}
