
var GoogleMap = IMap.extend({
	init: function(id) {
		this.localMarkers = new Array();
		this.localDirections = null;
		this.localDirectionsS = null;
		this.localDirectionsE = null;
		this._super(id);
	},
	load: function(params) {
		if (!this.map) {
			var _this = this;
		
			this.map = new GMap2($("#" + this.id).get(0));
			
//		    this.map.addMapType(G_SATELLITE_3D_MAP);
		    
		    this.map.addControl(new GSmallMapControl());
		    this.map.addControl(new GMapTypeControl());
		    this.map.addControl(new GScaleControl());

		    this.overview = new GOverviewMapControl();
		    this.map.addControl(this.overview);
		    
		    this.map.enableScrollWheelZoom();
		    this.map.enableContinuousZoom();
		    
		    GEvent.addListener(this.map, "click", function(){_this._eventHandler(arguments);});

		    this.map.setCenter(new GLatLng(0,0), 2);
		    
		    $(document.body).unload(GUnload);
	    } else {
			this.resize();
	    }
	    
		this._super(params);
	},
	resize: function() {
		if (this.map) {
			this.map.checkResize();
		}
	},
	getPosition: function() {
		var latitude = 0;
		var longitude = 0;
		if (this.map) {
			var c = this.map.getCenter();
			latitude = c.lat();
			longitude = c.lng();
		}
		return new MapPoint(latitude, longitude);
	},
	setPosition: function(point, zoom) {
		if (this.map) {
			point = point || this.getPosition();
			if (!zoom || zoom == this.getZoom()) {
				this.map.panTo(this._localPoint(point));
			} else {
				this.map.setCenter(this._localPoint(point), zoom);
			}
		}
	},
	getZoom: function() {
		return this.map ? this.map.getZoom() : 2;
	},
	setZoom: function(zoom) {
		if (this.map && zoom) {
			this.map.setZoom(zoom);
		}
	},
	getMapType: function() {
		var type = MapTypes.Road;
		if (this.map) {
			switch (this.map.getCurrentMapType()) {
				case G_SATELLITE_MAP:
					type = MapTypes.Satellite;
					break;
				case G_HYBRID_MAP:
					type = MapTypes.Hybrid;
					break;
				case G_NORMAL_MAP:
				default:
					type = MapTypes.Road;
					break;
			}
		}
		return type;
	},
	setMapType: function(type) {
		if (this.map) {
			switch (type) {
				case MapTypes.Road:
					this.map.setMapType(G_NORMAL_MAP);
					break;
				case MapTypes.Satellite:
					this.map.setMapType(G_SATELLITE_MAP);
					break;
				case MapTypes.Hybrid:
					this.map.setMapType(G_HYBRID_MAP);
					break;
			}
		}
	},
	getOverviewVisible: function() {
		var visible = true;
		if (this.overview && this.overview.getOverviewMap()) {
			visible = $(this.overview.getOverviewMap().getContainer()).parent().width() > 15;
		}
		return visible;
	},
	setOverviewVisible: function(visible) {
		if (this.overview) {
			if (visible && !this.getOverviewVisible()) {
				this.overview.show();
			} else if (!visible && this.getOverviewVisible()) {
				this.overview.hide();
			}
		}
	},
	getCursor: function() {
		var cursor = this.map ? this.map.getDragObject().Fd : null;
		if (cursor == this.defaultCursor || cursor == "") {
			cursor = null;
		}
		return cursor; 
	},
	setCursor: function(cursor) {
		if (this.map) {
			if (cursor == null) {
				cursor = this.defaultCursor;
			}
			this.map.getDragObject().setDraggableCursor(cursor);
		}
	},
	framePoints: function(points) {
		if (this.map && points && points.length) {
			var bounds = new GLatLngBounds();
			for (var i in points) {
				bounds.extend(this._localPoint(points[i]));
			}
			this.setPosition(this._mapPoint(bounds.getCenter()), this.map.getBoundsZoomLevel(bounds));
		}
	},
	mark: function(marker) {
		if (this.map && marker) {
			var options = {icon:G_DEFAULT_ICON,clickable:marker.clickable,draggable:marker.draggable,title:marker.tooltip,bouncy:true};
			var construct = GMarker;
			if (marker.icon) {
				var icon = new GIcon();
				icon.image = marker.icon.image;
				icon.iconSize = new GSize(marker.icon.size.x,marker.icon.size.y);
				icon.iconAnchor = new GPoint(marker.icon.offset.x, marker.icon.offset.y);
				icon.infoWindowAnchor = new GPoint(parseInt(marker.icon.size.x / 2),0);
				$.extend(options,{icon:icon});
				if (marker.icon.text) {
					$.extend(options,{
						text: marker.icon.text,
						textOffset: new GSize(marker.icon.textOffset.x, marker.icon.textOffset.y),
						textSize: marker.icon.textSize
					});
					construct = GMarkerX;
				}
			}
			var m = new construct(this._localPoint(marker.point),options);
			
			m.bindInfoWindowHtml(marker.content);
			this.map.addOverlay(m);
			if (!marker.visible) {
				m.hide();
			}
			if (marker.draggable) {
				var _this = this;
				GEvent.addListener(m, "drag", function() {
					marker.point = _this._mapPoint(this.getPoint());
					for (var i in marker.events) {
						if (marker.events[i][0] == "drag") {
							marker.events[i][1]({marker:marker});
						}
					}
				});
				GEvent.addListener(m, "dragend", function() {
					marker.point = _this._mapPoint(this.getPoint());
					if (_this.directions) {
						if ($.inArray(marker.id, _this.directions.ids) >= 0) {
							_this.resetDirections();
						}
					}
					for (var i in marker.events) {
						if (marker.events[i][0] == "dragend") {
							marker.events[i][1]({marker:marker});
						}
					}
				});
			}
			for (var i in marker.events) {
				if (marker.events[i][0] != "drag" && marker.events[i][0] != "dragend") {
			    	GEvent.addListener(m, marker.events[i][0], function(){marker.events[i][1]({marker:marker})});
			    }
			}
			
			this.localMarkers.push([marker.id, m]);
		}
		this._super(marker);
	},
	unmark: function(id) {
		if (this.map && id) {
			for (var i = this.localMarkers.length - 1; i >= 0; i--) {
				if (this.localMarkers[i][0] == id) {
					this.map.removeOverlay(this.localMarkers[i][1]);
					this.localMarkers.splice(i, 1);
					break;
				}
			}
		}
		this._super(id);
	},
	unmarkAll: function() {
		if (this.map) {
			this.map.clearOverlays();
			this.localMarkers = new Array();
		}
		this._super();
	},	
	moveMarker: function(id, point) {
		if (this.map && id && point) {
			for (var i in this.localMarkers) {
				if (this.localMarkers[i][0] == id) {
					this.localMarkers[i][1].setLatLng(this._localPoint(point));
					break;
				}
			}
		}
		this._super(id, point);
	},
	updateMarkerContent: function(id, content) {
		if (this.map && id) {
			for (var i in this.localMarkers) {
				if (this.localMarkers[i][0] == id) {
					this.localMarkers[i][1].bindInfoWindowHtml(content);
					break;
				}
			}
		}
		this._super(id, content);
	},
	showMarkerContent: function(id, content) {
		if (this.map && id) {
			for (var i in this.localMarkers) {
				if (this.localMarkers[i][0] == id) {
					if (!content) {
						for(var i in this.markers) {
							if (this.markers[i].id == id) {
								content = this.markers[i].content;
								break;
							}
						}			
					}
					this.localMarkers[i][1].openInfoWindowHtml(content);
					break;
				}
			}
		}
	},
	hideMarkerContent: function() {
		if (this.map) {
			this.map.closeInfoWindow();
		}
	},
	setMarkerVisibility: function(id, visible) {
		if (this.map && id) {
			for (var i in this.localMarkers) {
				if (this.localMarkers[i][0] == id) {
					if (visible) {
						this.localMarkers[i][1].show();
					} else {
						this.localMarkers[i][1].closeInfoWindow();
						this.localMarkers[i][1].hide();
					}
					break;
				}
			}						
		}
		this._super(id, visible);
	},
	setDirections: function(ids, fn, visible) {
		visible = (visible == false) ? false : true;
		this.clearDirections();
		if (this.map && ids) {
			this.map.closeInfoWindow();
			this.localDirections = new GDirections();
			var wp = new Array();
			for (var i in ids) {
				var m = this.getMarker(ids[i]);
				if (m) {
					wp.push(this._localPoint(m.point));
				}
			}
       		var _this = this;
			GEvent.addListener(this.localDirections, "load", function() {
	       		_this.directions = new MapDirections(ids, this.getDistance().meters, this.getDuration().seconds, visible);

      			_this.localDirectionsS = new GPolylineX([wp[0],this.getPolyline().getVertex(0)],null,null,null,{style:"dashed"});
       			_this.map.addOverlay(_this.localDirectionsS);
       			_this.directions.steps.push(new MapDirectionsStep(directionsDepart, _this.localDirectionsS.getLength(), 0, _this._mapPoint(wp[0])));

        		var routes = this.getNumRoutes();
        		for (var i = 0; i < routes; i++) {
        			var route = this.getRoute(i);
        			var steps = route.getNumSteps();
		       		for (var j = 0; j < steps; j++) {
		       			var step = route.getStep(j);
		       			_this.directions.steps.push(new MapDirectionsStep($.text(step.getDescriptionHtml()), step.getDistance().meters, step.getDuration().seconds, _this._mapPoint(step.getLatLng())));
		       		}
        		}
				
				var last = this.getPolyline().getVertex(this.getPolyline().getVertexCount() - 1);
       			_this.localDirectionsE = new GPolylineX([last,wp[wp.length - 1]],null,null,null,{style:"dashed"});
       			_this.map.addOverlay(_this.localDirectionsE);
       			_this.directions.steps.push(new MapDirectionsStep(directionsArrive, _this.localDirectionsE.getLength(), 0, _this._mapPoint(last)));

       			_this.directions.distance += _this.directions.steps[0].distance + _this.directions.steps[_this.directions.steps.length - 1].distance;
				_this.map.addOverlay(this.getPolyline());
				
				if (!visible) {
					_this.setDirectionsVisibility(visible);
				}

		       	if (fn) {
	        		_this.directions.callback = fn;
	        		fn(_this.directions);
        		}
  	    	});
  	    	GEvent.addListener(this.localDirections, "error", function() {
      			_this.localDirectionsS = new GPolylineX(wp,null,null,null,{style:"dashed"});
       			_this.directions = new MapDirections(ids, _this.localDirectionsS.getLength(), "?", visible);
       			_this.map.addOverlay(_this.localDirectionsS);

		       	if (fn) {
	        		_this.directions.callback = fn;
	        		fn(_this.directions);
        		}  	    		
  	    	});
			this.localDirections.loadFromWaypoints(wp,{getPolyline:true,getSteps:true,preserveViewport:false});
		}
	},
	clearDirections: function() {
		if (this.map) {
			if (this.localDirections) {
				if (this.localDirections.getPolyline()) {
					this.map.removeOverlay(this.localDirections.getPolyline());
				}
				this.localDirections.clear();
			}
			if (this.localDirectionsS) {
				this.map.removeOverlay(this.localDirectionsS);
			}
			if (this.localDirectionsE) {
				this.map.removeOverlay(this.localDirectionsE);
			}
		}
		this.localDirections = null;
		this.localDirectionsS = null;
		this.localDirectionsE = null;

		this._super();
	},
	frameDirections: function() {
		if (this.localDirections && this.map) {
			var bounds = this.localDirections.getBounds() || new GLatLngBounds();
			if (this.directions) {
				var m = this.getMarker(this.directions.ids[0]);
				if (m) {
					bounds.extend(this._localPoint(m.point));				
				}
				m = this.getMarker(this.directions.ids[this.directions.ids.length - 1]);
				if (m) {
					bounds.extend(this._localPoint(m.point));				
				}
			}
			this.setPosition(this._mapPoint(bounds.getCenter()), this.map.getBoundsZoomLevel(bounds));
		}
	},
	setDirectionsVisibility: function(visible) {
		if (visible) {
			if (this.localDirections && this.localDirections.getPolyline()) {
				this.localDirections.getPolyline().show();
			}
			if (this.localDirectionsS) {
				this.localDirectionsS.show();
			}
			if (this.localDirectionsE) {
				this.localDirectionsE.show();
			}
		} else {
			if (this.localDirections && this.localDirections.getPolyline()) {
				this.localDirections.getPolyline().hide();
			}		
			if (this.localDirectionsS) {
				this.localDirectionsS.hide();
			}
			if (this.localDirectionsE) {
				this.localDirectionsE.hide();
			}
		}
		this._super(visible);
	},
	_mapPoint: function(point) {
		if (point) {
			return new MapPoint(point.lat(), point.lng());
		}
		return null;
	},
	_localPoint: function(point) {
		if (point) {
			return new GLatLng(point.latitude, point.longitude);
		}
		return null;
	},
	_eventHandler: function(args) {
		if (this.map) {
			for (var i in this.events) {
				switch (this.events[i][0]) {
					case "click":
						if (args[1]) {
							this.events[i][1]({point:this._mapPoint(args[1])});
						}
						break;
				}
			}
		}
	}	
});


function GMarkerX(latlng, opts) {
	this.options = $.extend(opts, {
		text: opts.text || "",
		textOffset: opts.textOffset || new GSize(0, 0),
		title: opts.title || ""
	});
	
	GMarker.apply(this, arguments);
}
GMarkerX.prototype = new GMarker(new GLatLng(0,0));
GMarkerX.prototype.initialize = function(map) {
	var icon = this.getIcon(); 
	this.div = $("<div/>").addClass("mapper-icon").attr("title",this.options.title).append(
		$("<img/>").attr("src", icon.image)
	).append(
		$("<span/>").css({left:this.options.textOffset.width,top:this.options.textOffset.height}).text(this.options.text)
	);
	this.div.children("img").andSelf().css({height:icon.iconSize.height, width:icon.iconSize.width});	
	if (this.options.textSize) {
		this.div.children("span").css({fontSize: this.options.textSize + "pt"});
	}
	this.div.appendTo(map.getPane(G_MAP_MARKER_PANE));

	GMarker.prototype.initialize.apply(this, arguments);
	this.image = this.div.next("img");
	this.image.css("opacity", 0);
}
GMarkerX.prototype.redraw = function(force) {
	GMarker.prototype.redraw.apply(this, arguments);
	
	if (force) {
		this.div.css({left:this.image.css("left"),top:this.image.css("top"),zIndex:GOverlay.getZIndex(this.getLatLng().lat()) - 1});
	}
}
GMarkerX.prototype.remove = function() {
	GEvent.clearInstanceListeners(this.div.get(0));
	this.div.remove();
	this.div = null;
	GMarker.prototype.remove.apply(this, arguments);
}
GMarkerX.prototype.copy = function() {
	return new GMarkerX(this.getLatLng(), this.options);
}
GMarkerX.prototype.hide = function() {
	this.div.hide();
	GMarker.prototype.hide.apply(this, arguments);
}
GMarkerX.prototype.show = function() {
	this.div.show();
	GMarker.prototype.show.apply(this, arguments);
}


function GPolylineX(latlngs, color, weight, opacity, opts) {
	this.options = $.extend(opts, {
		style: (opts && opts.style) ? opts.style : "solid"
	});
	
	this.isVml = ($.browser.msie);
	
	GPolyline.apply(this, arguments);
}
GPolylineX.prototype = new GPolyline(new Array(new GLatLng(0,0)));
GPolylineX.prototype.initialize = function(map) {
	GPolyline.prototype.initialize.apply(this, arguments);
	this.shape = ({});
}
GPolylineX.prototype.redraw = function(force) {
	GPolyline.prototype.redraw.apply(this, arguments);
	
	this.shape = (this.isVml ? $(this.ca) : $(this.ca).children("path:last")); // this.ca is the current Google API location for the web line object (warning, Google could change this at any time) 
	
	this.setStyle(this.options["style"]);
}
GPolylineX.prototype.copy = function() {
	var latlngs = new Array();
	for (var i = 0; i < this.getVertexCount(); i++) {
		latlngs.push(this.getVertex(i));
	}
	return new GPolylineX(latlngs, this.color, this.weight, this.opacity, this.options);
}
GPolylineX.prototype.getStyle = function() {
	return this.options["style"];
}
GPolylineX.prototype.setStyle = function(style) {
	this.options["style"] = style || "solid";
	
	if (this.isVml) {
		switch (this.options["style"]) {
			case "dashed":
				this.shape.children("stroke").attr("dashstyle","dash");
				break;
			case "dotted":
				this.shape.children("stroke").attr("dashstyle","dot")
				break;
			case "solid":
			default:
				this.shape.children("stroke").attr("dashstyle","")
				break;
		}
	} else {
		switch (this.options["style"]) {
			case "dashed":
				this.shape.attr("stroke-dasharray", "10,10");
				break;
			case "dotted":
				this.shape.attr("stroke-dasharray", "3,17");
				break;
			case "solid":
			default:
				this.shape.attr("stroke-dasharray", "");
				break;
		}
	}
}
