google_api_version = gv_api_version = FindGoogleAPIVersion();
if (!self.gv_maptypecontrol_style) { gv_maptypecontrol_style = (self.maptypecontrol_style) ? maptypecontrol_style : 'menu'; } // BC
if (self.gv_filter_map_types==null) { gv_filter_map_types = (self.filter_map_types!=null) ? filter_map_types : true; }

/**************************************************
 * Custom map layers:
 * Adapted from Jef Poskanzer's Acme Mapper
 * (http://mapper.acme.com/)
 **************************************************/
if (gv_api_version >= 2) {
	USGS_TOPO_TILES = WMSCreateMap([{name:'Topo',copyright:'Topo maps by USGS via terraserver-usa.com',errorMessage:'Topo maps unavailable',minResolution:5,maxResolution:17,tileSize:400,baseUrl:'http://terraservice.net/ogcmap6.ashx?version=1.1.1&request=GetMap&styles=&srs=EPSG:4326&format=image/jpeg&bgcolor=0xCCCCCC&exceptions=INIMAGE&layers=DRG'}]);
	USGS_AERIAL_TILES = WMSCreateMap([{name:'Aerial',copyright:'Imagery by USGS via terraserver-usa.com',errorMessage:'USGS aerial imagery unavailable',minResolution:7,maxResolution:18,tileSize:400,baseUrl:'http://terraservice.net/ogcmap6.ashx?version=1.1.1&request=GetMap&styles=&srs=EPSG:4326&format=image/jpeg&bgcolor=0xCCCCCC&exceptions=INIMAGE&layers=DOQ'}]);
	USGS_AERIAL_HYBRID_TILES = WMSCreateMap([{name:'Aerial+',copyright:'Imagery by USGS via terraserver-usa.com',errorMessage:'USGS aerial imagery unavailable',minResolution:7,maxResolution:18,tileSize:256,baseUrl:'http://terraservice.net/ogcmap6.ashx?version=1.1.1&request=GetMap&styles=&srs=EPSG:4326&format=image/jpeg&bgcolor=0xCCCCCC&exceptions=INIMAGE&layers=DOQ',foreground:'G_HYBRID_MAP'}]);
	NRCAN_TOPO_TILES = WMSCreateMap([{name:'NRCan',copyright:'Maps by NRCan.gc.ca',errorMessage:'NRCan maps unavailable',minResolution:6,maxResolution:18,tileSize:600,baseUrl:'http://wms.cits.rncan.gc.ca/cgi-bin/cubeserv.cgi?version=1.1.3&request=GetMap&format=image/png&bgcolor=0xFFFFFF&exceptions=application/vnd.ogc.se_inimage&srs=EPSG:4326&layers=PUB_50K:CARTES_MATRICIELLES/RASTER_MAPS'}]);
	NRCAN_TOPO_NAMES_TILES = WMSCreateMap([{name:'NRCan+',copyright:'Maps by NRCan.gc.ca',errorMessage:'NRCan maps unavailable',minResolution:11,maxResolution:18,tileSize:600,baseUrl:'http://wms.cits.rncan.gc.ca/cgi-bin/cubeserv.cgi?version=1.1.3&request=GetMap&format=image/png&bgcolor=0xFFFFFF&exceptions=application/vnd.ogc.se_inimage&srs=EPSG:4326&layers=PUB_50K:CARTES_MATRICIELLES/RASTER_MAPS,TOPONYME_0:BNDT_50K/NTDB_50K'}]);
	NEXRAD_TILES = WMSCreateMap([{name:'NEXRAD',copyright:'NEXRAD imagery from Iowa Environmental Mesonet',errorMessage:'NEXRAD imagery unavailable',minResolution:3,maxResolution:14,tileSize:256,baseUrl:'http://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r.cgi?version=1.1.1&request=GetMap&srs=EPSG:4326&format=image/png&transparent=true&styles=&layers=nexrad-n0r',opacity:0.6,background:'G_HYBRID_MAP'}]); // NOTE: for combo maps using Google tiles, tileSize MUST be 256!!!
	LANDSAT_TILES = WMSCreateMap([{name:'Landsat',copyright:'Map by NASA',errorMessage:'OnEarth server unavailable',minResolution:3,maxResolution:15,tileSize:200,baseUrl:'http://onearth.jpl.nasa.gov/wms.cgi?request=GetMap&styles=&srs=EPSG:4326&format=image/jpeg&layers=global_mosaic'}]);
	BLUEMARBLE_TILES = WMSCreateMap([{name:'BlueMarble',copyright:'Map by NASA',errorMessage:'OnEarth server unavailable',minResolution:3,maxResolution:8,tileSize:128,baseUrl:'http://onearth.jpl.nasa.gov/wms.cgi?request=GetMap&styles=&srs=EPSG:4326&format=image/jpeg&layers=modis'}]);
	DAILY_TERRA_TILES = WMSCreateMap([{name:'"Terra"',copyright:'Map by NASA',errorMessage:'OnEarth server unavailable',minResolution:3,maxResolution:10,tileSize:200,baseUrl:'http://onearth.jpl.nasa.gov/wms.cgi?request=GetMap&styles=&srs=EPSG:4326&format=image/jpeg&layers=daily_terra'}]);
	// DAILY_TERRA_HYBRID_TILES = WMSCreateMap([{name:'"Terra"+G.',copyright:'Map by NASA',errorMessage:'OnEarth server unavailable',minResolution:3,maxResolution:10,tileSize:256,baseUrl:'http://onearth.jpl.nasa.gov/wms.cgi?request=GetMap&styles=&srs=EPSG:4326&format=image/jpeg&layers=daily_terra',foreground:'G_HYBRID_MAP'}]);
	DAILY_AQUA_TILES = WMSCreateMap([{name:'"Aqua"',copyright:'Map by NASA',errorMessage:'OnEarth server unavailable',minResolution:3,maxResolution:10,tileSize:200,baseUrl:'http://onearth.jpl.nasa.gov/wms.cgi?request=GetMap&styles=&srs=EPSG:4326&format=image/jpeg&layers=daily_aqua'}]);
	// DAILY_AQUA_HYBRID_TILES = WMSCreateMap([{name:'"Aqua"+G.',copyright:'Map by NASA',errorMessage:'OnEarth server unavailable',minResolution:3,maxResolution:10,tileSize:256,baseUrl:'http://onearth.jpl.nasa.gov/wms.cgi?request=GetMap&styles=&srs=EPSG:4326&format=image/jpeg&layers=daily_aqua',foreground:'G_HYBRID_MAP'}]);
	SRTM_COLOR_TILES = WMSCreateMap([{name:'SRTM',copyright:'SRTM elevation data by NASA',errorMessage:'SRTM elevation data unavailable',minResolution:6,maxResolution:14,tileSize:200,baseUrl:'http://onearth.jpl.nasa.gov/wms.cgi?request=GetMap&srs=EPSG:4326&format=image/jpeg&styles=&layers=huemapped_srtm'}]);
	// SRTM_COLOR_HYBRID_TILES = WMSCreateMap([{name:'SRTM',copyright:'SRTM elevation data by NASA',errorMessage:'SRTM elevation data unavailable',minResolution:6,maxResolution:14,tileSize:256,baseUrl:'http://onearth.jpl.nasa.gov/wms.cgi?request=GetMap&srs=EPSG:4326&format=image/jpeg&styles=&layers=huemapped_srtm',foreground:'G_HYBRID_MAP'}]);
}

function GV_Add_Custom_Layers(map) {
	map.addMapType(USGS_TOPO_TILES);
	map.addMapType(USGS_AERIAL_TILES);
	map.addMapType(USGS_AERIAL_HYBRID_TILES);
	map.addMapType(NEXRAD_TILES);
	map.addMapType(NRCAN_TOPO_TILES);
	map.addMapType(NRCAN_TOPO_NAMES_TILES);
	map.addMapType(LANDSAT_TILES);
	map.addMapType(BLUEMARBLE_TILES);
	map.addMapType(DAILY_TERRA_TILES);
	// map.addMapType(DAILY_TERRA_HYBRID_TILES);
	map.addMapType(DAILY_AQUA_TILES);
	// map.addMapType(DAILY_AQUA_HYBRID_TILES);
	map.addMapType(SRTM_COLOR_TILES);
	// map.addMapType(SRTM_COLOR_HYBRID_TILES);
}

function WMSCreateMap(layer_info,copyright,errorMessage,minResolution,maxResolution,tileSize,baseUrl) {
	// The old "GV_Marker" function had everything in a particular order; this new one uses more user-friendly named parameters.
	// If the second argment has a 'lat' item INSIDE of it, then it's the new version; otherwise that's just the latitude.
	var array_input = (layer_info[0] != undefined && layer_info[0]['name'] != undefined) ? 1 : 0;
	var layers = [];
	
	if (!array_input) {
		layers[0] = [];
		layers[0]['name'] = layer_info; layers[0]['copyright'] = copyright; layers[0]['errorMessage'] = errorMessage; layers[0]['minResolution'] = minResolution; layers[0]['maxResolution'] = maxResolution; layers[0]['tileSize'] = tileSize; layers[0]['baseUrl'] = baseUrl;
	} else {
		layers = layer_info; // everything's okay; there was only one parameter, and it's an array
	}
	
	var tileLayers = [];
	for (j=0; j<layers.length; j++) {
		var mi = layers[j]; // mi stands for "map info"
		var tileLayer = new GTileLayer(new GCopyrightCollection(mi['copyright']),mi['minResolution'],mi['maxResolution']);
		tileLayer.baseUrl = mi['baseUrl'];
		tileLayer.tileSize = mi['tileSize'];
		tileLayer.getTileUrl = WMSGetTileUrl;
		tileLayer.getCopyright = function() { return { prefix:'',copyrightTexts:[mi['copyright']]}; };
		if (mi['opacity'] != undefined) { tileLayer.getOpacity = function() { return mi['opacity']; } }
		if (mi['background'] != undefined) {
			var bg_layers = eval(mi['background']+'.getTileLayers()');
			for(var i in bg_layers) {
				tileLayers.push(bg_layers[i]);
			}
		}
		tileLayers.push(tileLayer);
		if (mi['foreground'] != undefined) {
			var fg_layers = eval(mi['foreground']+'.getTileLayers()');
			for (var i=0; i<fg_layers.length; i++) {
				if (mi['foreground'] != 'G_HYBRID_MAP' || (mi['foreground'] == 'G_HYBRID_MAP' && i == (fg_layers.length-1))) { // if the foreground is Google hybrid, only use the last (transparent) layer
					tileLayers.push(fg_layers[i]);
				}
			}
		}
	}
	
	return new GMapType(tileLayers,G_SATELLITE_MAP.getProjection(),mi['name'],{errorMessage:mi['errorMessage'],tileSize:mi['tileSize']});
}

function WMSGetTileUrl(tile,zoom) {
	var southWestPixel = new GPoint(tile.x*this.tileSize,(tile.y+1)*this.tileSize);
	var northEastPixel = new GPoint((tile.x+1)*this.tileSize,tile.y*this.tileSize);
	var southWestCoords = G_NORMAL_MAP.getProjection().fromPixelToLatLng(southWestPixel,zoom);
	var northEastCoords = G_NORMAL_MAP.getProjection().fromPixelToLatLng(northEastPixel,zoom);
	var bbox = southWestCoords.lng()+','+southWestCoords.lat()+','+northEastCoords.lng()+','+northEastCoords.lat();
	return this.baseUrl+'&bbox='+bbox+'&width='+this.tileSize+'&height='+this.tileSize;
}


/**************************************************
 * Custom map-type control:
 * more or less from Google's own documentation
 **************************************************/
function GV_MapTypeControl() {}
if (gv_api_version >= 2) {
	GV_MapTypeControl.prototype = new GControl();
	GV_MapTypeControl.prototype.getDefaultPosition = function() {
		return new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(7,7));
	}
	GV_MapTypeControl.prototype.initialize = function(map) {
		GV_Add_Custom_Layers(map);
		var map_types = [
			{ label:'Map',type:'G_NORMAL_MAP',title:'Google street map',bounds:[-180,-90,180,90],excluded:[] }
			,{ label:'Satellite',type:'G_SATELLITE_MAP',title:'Google satellite map',bounds:[-180,-90,180,90],excluded:[] }
			,{ label:'Hybrid',type:'G_HYBRID_MAP',title:'Google "hybrid" map',bounds:[-180,-90,180,90],excluded:[] }
			,{ label:'USGS topo',type:'USGS_TOPO_TILES',title:'USGS topographic map',bounds:[-169,18,-66,72],excluded:[],country:'us' }
			,{ label:'USGS aerial',type:'USGS_AERIAL_TILES',title:'USGS aerial photos (black/white)',bounds:[-152,17,-65,65],excluded:[],country:'us' }
			,{ label:'USGS aerial+G.',type:'USGS_AERIAL_HYBRID_TILES',title:'USGS aerial photos (black/white) + Google street map',bounds:[-152,17,-65,65],excluded:[],country:'us' }
			,{ label:'U.S. Nexrad',type:'NEXRAD_TILES',title:'United States NEXRAD weather radar',bounds:[-152,17,-65,65],excluded:[],country:'us' }
			,{ label:'Canada topo',type:'NRCAN_TOPO_TILES',title:'NRCan/Toporama maps with contour lines',bounds:[-141,41.7,-52,85],excluded:[-141,41.7,-86,48],country:'ca' }
			,{ label:'Can. topo+names',type:'NRCAN_TOPO_NAMES_TILES',title:'NRCan/Toporama topo maps with feature names',bounds:[-141,41.7,-52,85],excluded:[-141,41.7,-86,48],country:'ca' }
			,{ label:'Landsat 30m',type:'LANDSAT_TILES',title:'NASA Landsat 30-meter imagery',bounds:[-180,-90,180,90],excluded:[] }
			,{ label:'Blue Marble',type:'BLUEMARBLE_TILES',title:'NASA "Visible Earth" image',bounds:[-180,-90,180,90],excluded:[] }
			,{ label:'Daily "Terra"',type:'DAILY_TERRA_TILES',title:'Daily imagery from "Terra" satellite',bounds:[-180,-90,180,90],excluded:[] }
			// ,{ label:'"Terra"+Google',type:'DAILY_TERRA_HYBRID_TILES',title:'Daily imagery from "Terra" satellite + Google street map',bounds:[-180,-90,180,90],excluded:[] }
			,{ label:'Daily "Aqua"',type:'DAILY_AQUA_TILES',title:'Daily imagery from "Aqua" satellite',bounds:[-180,-90,180,90],excluded:[] }
			// ,{ label:'"Aqua"+Google',type:'DAILY_AQUA_HYBRID_TILES',title:'Daily imagery from "Aqua" satellite + Google street map',bounds:[-180,-90,180,90],excluded:[] }
			,{ label:'SRTM elevation',type:'SRTM_COLOR_TILES',title:'SRTM elevation data, as color',bounds:[-180,-90,180,90],excluded:[] }
			// ,{ label:'SRTM elev.+G.',type:'SRTM_COLOR_HYBRID_TILES',title:'SRTM elevation data, as color + Google street map',bounds:[-180,-90,180,90],excluded:[] }
		];
		if (self.gv_custom_map_types && gv_custom_map_types.length > 0) {
			for (j=0; j<gv_custom_map_types.length; j++) { map_types.push(gv_custom_map_types[j]); }
		}
		var center_lat = map.getCenter().lat();
		var center_lng = map.getCenter().lng();
		
		var excluded_maps = new Array;
		if (self.gv_filter_map_types && gv_filter_map_types && self.gv_excluded_map_types && gv_excluded_map_types) {
			for (j=0; j<gv_excluded_map_types.length; j++) {
				excluded_maps[gv_excluded_map_types[j]] = true;
			}
		}
		for (j=0; j<map_types.length; j++) {
			if (self.gv_country && gv_country) {
				if (map_types[j]['country'] && map_types[j]['country'].indexOf(gv_country) < 0) {
					excluded_maps[map_types[j]['type']] = true;
				}
			} else {
				if (!(center_lng >= map_types[j]['bounds'][0] && center_lat >= map_types[j]['bounds'][1] && center_lng <= map_types[j]['bounds'][2] && center_lat <= map_types[j]['bounds'][3]) || (center_lng >= map_types[j]['excluded'][0] && center_lat >= map_types[j]['excluded'][1] && center_lng <= map_types[j]['excluded'][2] && center_lat <= map_types[j]['excluded'][3]) ) {
					excluded_maps[map_types[j]['type']] = true;
				}
			}
		}
		if (gv_maptypecontrol_style == 'menu') {
			var map_selector = document.createElement("select");
			map_selector.id = 'gv_map_selector';
			map_selector.style.font = '10px Verdana';
			map_selector.style.backgroundColor = '#FFFFFF';
			for (j=0; j<map_types.length; j++) {
				if (!gv_filter_map_types || !excluded_maps[map_types[j]['type']]) {
					var opt = document.createElement("option");
					opt.value = map_types[j]['type'];
					opt.appendChild(document.createTextNode(map_types[j]['label']));
					map_selector.appendChild(opt);
					if (map.getCurrentMapType() == eval(opt.value)) { map_selector.selectedIndex = map_selector.length - 1; }
				}
			}
			GEvent.addDomListener(map_selector, "change", function(){
				map.setMapType(eval(this.value));
				// if (self.gv_maptypecontrol) {
				// 	map.removeControl(gv_maptypecontrol);
				// 	map.addControl(gv_maptypecontrol);
				// }
			} );
			map.getContainer().appendChild(map_selector);
			return map_selector;
		} else { // 'list'
			var map_type_container = document.createElement("div");
			for (j=0; j<map_types.length; j++) {
				var map_ok = true;
				if (gv_filter_map_types && !(center_lng >= map_types[j]['bounds'][0] && center_lat >= map_types[j]['bounds'][1] && center_lng <= map_types[j]['bounds'][2] && center_lat <= map_types[j]['bounds'][3]) || (center_lng >= map_types[j]['excluded'][0] && center_lat >= map_types[j]['excluded'][1] && center_lng <= map_types[j]['excluded'][2] && center_lat <= map_types[j]['excluded'][3]) ) { map_ok = false; }
				if (self.gv_country && gv_country && map_types[j]['country'] && map_types[j]['country'].indexOf(gv_country) < 0) { map_ok = false; }
				if (excluded_maps[map_types[j]['type']]) { map_ok = false; }
				if (map_ok) {
					var maplink = document.createElement("div");
					maplink.className = 'gv_maptypelink';
					if (self.gv_maptypecontrol && map.getCurrentMapType() == eval(map_types[j]['type'])) {
						maplink.className = 'gv_maptypelink gv_maptypelink_selected';
					}
					maplink.title = map_types[j]['title'];
					maplink.type = map_types[j]['type'];
					map_type_container.appendChild(maplink);
					maplink.appendChild(document.createTextNode(map_types[j]['label']));
					GEvent.addDomListener(maplink, "click", function(){
						map.setMapType(eval(this.type));
						if (self.gv_maptypecontrol) {
							map.removeControl(gv_maptypecontrol);
							map.addControl(gv_maptypecontrol);
						}
					} );
				}
			}
			map.getContainer().appendChild(map_type_container);
			return map_type_container;
		}
	}
}

function FindGoogleAPIVersion() {
	var v = 2;
	var scripts = document.getElementsByTagName("script")
	for (var i=0; i<scripts.length; i++) {
		var pattern = /\/mapfiles\/([0-9]+)\/maps([0-9])?\.api\//;
		var m = pattern.exec(scripts[i].src);
		if (m != null && m[1] && m[2]) {
			v = parseFloat(m[2]+'.'+m[1]);
			break;
		}
	}
	return v;
}