var CustomMapTypes = {};

CustomMapTypes.Coordinate = function() {
};

CustomMapTypes.Coordinate.prototype = {
	name : 'Coordinate',
	alt : 'Background map type',
	tileSize : new google.maps.Size(256, 256),
	minZoom : 7,
	maxZoom : 13,
	getTile : function(coord, zoom, ownerDocument) {
		var div = ownerDocument.createElement('DIV');
		div.innerHTML = coord;
		div.style.width = this.tileSize.width + 'px';
		div.style.height = this.tileSize.height + 'px';
		div.style.fontSize = '10';
		div.style.borderStyle = 'solid';
		div.style.borderWidth = '1px';
		div.style.borderColor = '#AAAAAA';
		return div;
	}
};

CustomMapTypes.None = function() {
};

CustomMapTypes.None.prototype = {
	name : 'None',
	alt : 'None map type',
	tileSize : new google.maps.Size(256, 256),
	minZoom : 7,
	maxZoom : 13,
	getTile : function(coord, zoom, ownerDocument) {
		var div = ownerDocument.createElement('DIV');
		div.style.width = this.tileSize.width + 'px';
		div.style.height = this.tileSize.height + 'px';
		return div;
	}
};

function MapTooltip(map) {
	/**
	 * Offset the control container from the mouse by this amount.
	 */
	this.anchorOffset = new google.maps.Point(14, 14);

	/**
	 * Pointer to the HTML container.
	 */
	this.node = this.createHtmlNode();

	// Add control to the map. Position is irrelevant.
	map.controls[google.maps.ControlPosition.TOP].push(this.node);

	// Bind this OverlayView to the map so we can access MapCanvasProjection
	// to convert LatLng to Point coordinates.
	this.setMap(map);

	// Register an MVC property to indicate whether this custom control
	// is visible or hidden. Initially hide control until mouse is over map.
	this.set('visible', false);
}

// Extend OverlayView so we can access MapCanvasProjection.
MapTooltip.prototype = new google.maps.OverlayView();
MapTooltip.prototype.draw = function() {};

/**
 * @private Helper function creates the HTML node which is the control
 *          container.
 * @return {HTMLDivElement}
 */
MapTooltip.prototype.createHtmlNode = function() {
	var divNode = MapTooltip.staticNode;
	if ( ! divNode ) {
		divNode = document.createElement('div');
		divNode.id = 'map-tooltip';
		divNode.index = 100;
                MapTooltip.staticNode = divNode;
	}
	return divNode;
};

/**
 * MVC property's state change handler function to show/hide the control
 * container.
 */
MapTooltip.prototype.visible_changed = function() {
	this.node.style.display = this.get('visible') ? '' : 'none';
};

MapTooltip.prototype.updatePosition = function(latLng, tooltip) {
	var projection = this.getProjection();
	var point = projection.fromLatLngToContainerPixel(latLng);
    
	// Update control position to be anchored next to mouse position.
	this.node.style.left = point.x + this.anchorOffset.x + 'px';
	this.node.style.top = point.y + this.anchorOffset.y + 'px';
	this.node.innerHTML = tooltip;
};

var changeMapType = function(map, name) {
	var map_type = new CustomMapTypes[name]();
	map.mapTypes.set(name, map_type);
};

var addMapTooltip = function(map,obj,tooltip) {
	var map_tooltip = new MapTooltip(map);
	map_tooltip.node.innerHTML = tooltip;
	google.maps.event.addListener(obj, 'mouseover', function(mEvent) {
		map_tooltip.set('visible', true);
	});
	google.maps.event.addListener(obj, 'mouseout', function(mEvent) {
		map_tooltip.set('visible', false);
	});
	google.maps.event.addListener(obj, 'mousemove', function(mEvent) {
		map_tooltip.updatePosition(mEvent.latLng, tooltip);
	});
};

var addMapPolygon = function(map, paths, fill, stroke, strokeWidth, fillOpacity, strokeOpacity, tooltip, highlight, zIndex, dont_add, pane) {
	if (!paths) {
		return false;
	}
	polygon_paths = [];
	for ( var i = 0; i < paths.length; i++) {
		var points = paths[i];
		if (points) {
			var google_map_points = [];
			for ( var j = 0; j < points.length; j++) {
				google_map_points.push(new google.maps.LatLng(points[j][0], points[j][1]));
			}
			polygon_paths.push(google_map_points);
		}
	}
	var options = {
		paths : polygon_paths,
		fillColor : fill,
		fillOpacity : fillOpacity,
		strokeColor : stroke,
		strokeOpacity : strokeOpacity,
		strokeWeight : strokeWidth
	};
	if ( highlight || ( ( typeof tooltip ) != 'undefined' ) ) {
		options.clickable = true;
	}
	else {
		options.clickable = false;
	}
	if ( zIndex ) {
		options.zIndex = zIndex;
	}
	if ( ! dont_add ) {
		options.map = map;
	}
	var polygon = new google.maps.Polygon( options );
	if ( ( ( typeof tooltip ) != 'undefined' ) && tooltip != null ) {
		addMapTooltip(map,polygon,tooltip);
	}
	if ( highlight ) {
		google.maps.event.addListener(polygon, 'mouseover', function() {
			this.setOptions( {
				fillColor : highlight
			});
		});
		google.maps.event.addListener(polygon, 'mouseout', function() {
			this.setOptions( {
				fillColor : fill
			});
		});
	}
	return polygon;
};

var addMapPolyline = function(map, points, stroke, strokeWidth, strokeOpacity, tooltip, highlight) {
	if (!points) {
		return false;
	}
	var google_map_points = [];
	for ( var j = 0; j < points.length; j++) {
		google_map_points.push(new google.maps.LatLng(points[j][0], points[j][1]));
	}
	var polyline = new google.maps.Polyline( {
		path : google_map_points,
		clickable : true,
		strokeColor : stroke,
		strokeOpacity : strokeOpacity,
		strokeWeight : strokeWidth,
		map : map
	});
	if ( ( typeof tooltip ) != 'undefined' ) {
		addMapTooltip(map,polyline,tooltip);
	}
	return polyline;
}

var addMapOverlay = function(map, id, pane) {
	var map_type = new google.maps.ImageMapType( {
		getTileUrl : function(coord, zoom) {
			return '/map/tile/' + id + '/' + zoom + '_' + coord.x + '_' + coord.y + '.png';
		},
		tileSize : new google.maps.Size(256, 256),
		isPng : true
	});
	map.overlayMapTypes.push( map_type );
	return map_type;
};

var limitZoom = function(map, zoom_min, zoom_max) {
	if (zoom_min <= zoom_max) {
		google.maps.event.addListener(map, 'zoom_changed', function() {
			if (map.getZoom() < zoom_min) {
				map.setZoom(zoom_min);
			} else if (map.getZoom() > zoom_max) {
				map.setZoom(zoom_max);
			}
			setTimeout(function() {
				if ( map_mask ) {
					map_mask.setMap(null);
					map_mask.setMap( map );
				}
			},200);
		});
	}
};

var limitBounds = function(map, lat_min, lat_max, lng_min, lng_max) {
	var allowed_bounds = new google.maps.LatLngBounds(
		new google.maps.LatLng(lat_min, lng_min),
		new google.maps.LatLng(lat_max, lng_max)
	);
	google.maps.event.addListener( map, 'drag', function() {
		var map_bounds = map.getBounds();
		var north_east = map_bounds.getNorthEast();
		var south_west = map_bounds.getSouthWest();
		if (allowed_bounds.contains(north_east)
				&& allowed_bounds.contains(south_west)) {
			return;
		}
		var c = map.getCenter();
		var x = c.lng();
		var y = c.lat()
		var xMax = north_east.lng();
		var yMax = north_east.lat();
		var xMin = south_west.lng();
		var yMin = south_west.lat();
		var xLimitMax = allowed_bounds.getNorthEast().lng();
		var yLimitMax = allowed_bounds.getNorthEast().lat();
		var xLimitMin = allowed_bounds.getSouthWest().lng();
		var yLimitMin = allowed_bounds.getSouthWest().lat();

		if (xMin < xLimitMin)
			x += xLimitMin - xMin;
		else if (xMax > xLimitMax)
			x -= xMax - xLimitMax;
		if (yMin < yLimitMin)
			y += yLimitMin - yMin;
		else if (yMax > yLimitMax)
			y -= yMax - yLimitMax;

		map.setCenter(new google.maps.LatLng(y, x));
	});

};

