1/**
2 * Plugin google_maps: Generates embedded Google Maps frame or link to Google Maps.
3 *
4 * @license    GPLv2 (http://www.gnu.org/licenses/gpl.html)
5 * @author     Dmitry Katsubo <dma_k@mail.ru>
6 */
7
8(function() {
9// Globals:
10var GMAPS_MAX_RETRY_COUNT = 5;
11var GMAPS_RETRY_DELAY = 100;
12var GMAPS_MAX_GEO_RESULTS = 1;
13var GMAPS_GEOCODER = null;
14
15/*
16 * This function creates a new marker with a given HTML shown when a marker is clicked.
17 */
18function createMarker(point, desc)
19{
20	var marker = new GMarker(point);
21
22	// Note: Without wrapping into a function, listeners are added to the same objects!
23	GEvent.addListener(marker, "click", function()
24	{
25		marker.openInfoWindowHtml(desc);
26	});
27
28	return marker;
29}
30
31/*
32 * This recursive function sends an ansynchronous query to Google GeoCoder and marks results on the map.
33 */
34function queryGoogleGeo(map, bounds, locations, index, zoom, retry)
35{
36	if (GMAPS_GEOCODER == null)
37	{
38		// Can be initialized only at this point, as Google libraries should have been included:
39		GMAPS_GEOCODER = new GClientGeocoder();
40	}
41
42	GMAPS_GEOCODER.getLocations(locations[index],
43		function generateMarkersFromGoogleGeoResult(response)
44		{
45			// Was not able to locate any data:
46			if (response == null)
47			{
48				alert("No response from GeoCoder for location " + locations[index] + ". Giving up.");
49				return;
50			}
51			else if (response.Status.code == 602)
52			{
53				if (retry++ >= GMAPS_MAX_RETRY_COUNT)
54				{
55					alert("The maximum amount of retries (" + GMAPS_MAX_RETRY_COUNT + ") has been reached for location " + locations[index] + ". Giving up.");
56					return;
57				}
58
59				setTimeout(queryGoogleGeo, GMAPS_RETRY_DELAY, map, bounds, locations, index, zoom, retry);
60				return;
61			}
62			else if (response.Status.code != 200)
63			{
64				alert("Invalid response code (" + response.Status.code + ") from GeoCoder for location " + locations[index] + ". Giving up.");
65				return;
66			}
67
68			var places = response.Placemark;
69
70			for (var i = 0; i < places.length && i < GMAPS_MAX_GEO_RESULTS; i++)
71			{
72				var place = places[i];
73				var point = new GLatLng(place.Point.coordinates[1], place.Point.coordinates[0]);
74
75				bounds.extend(point);
76
77				map.addOverlay(createMarker(point, '<div class="gmaps_marker"><strong>' + place.address + '</strong><br/>'
78					+ place.AddressDetails.Country.CountryNameCode
79				));
80			}
81
82			if (index == locations.length - 1)
83			{
84				if (zoom == null)
85				{
86					if (!bounds.isEmpty())
87					{
88						// We select the best zoom for the boundary:
89						zoom = map.getBoundsZoomLevel(bounds);
90					}
91				}
92				else
93				{
94					// zoom is required to be an integer:
95					zoom = parseInt(zoom);
96				}
97
98				map.setCenter(bounds.getCenter(), zoom);
99			}
100			else
101			{
102				// Query recuresively other locations:
103				queryGoogleGeo(map, bounds, locations, index + 1, zoom, retry);
104			}
105		});
106}
107
108/**
109 * Initialisation function. Creates Gmap objects and loads Geo information.
110 */
111function loadMaps()
112{
113	jQuery('div.gmaps_frame').each(function() {
114		var attrs = this.attributes;
115
116		// Create a map:
117		var map = new GMap2(this);
118		map.setCenter(new GLatLng(34, 0), 1); // default point
119
120		// left-top navigator and zoomer
121		if (attrs.size.value == 'small')
122			map.addControl(new GSmallMapControl());
123		else if (attrs.size.value == 'large')
124			map.addControl(new GLargeMapControl());
125
126		// right-top map type switch buttons
127		if (attrs.control.value == 'hierarchical')
128			map.addControl(new GHierarchicalMapTypeControl());
129		else if (attrs.control.value == 'all')
130			map.addControl(new GMapTypeControl());
131
132		// mini-map in the bottom-right corner
133		if (attrs.overviewmap.value == 'true')
134		{
135			var overviewMap = new GOverviewMapControl();
136			map.addControl(overviewMap);
137			overviewMap.hide();
138		}
139
140		map.enableScrollWheelZoom();
141
142		var locations = new Array();
143
144		var n = 0;
145		while (true)
146		{
147			if (attrs['location' + n] == null)
148			{
149				break;
150			}
151
152			locations[n] = attrs['location' + n].value;
153			n++;
154		}
155
156		queryGoogleGeo(map, new GLatLngBounds(), locations, 0, attrs.zoom == null ? null : attrs.zoom.value, 0);
157	});
158}
159
160// A special Wiki-wide function, defined in lib/scripts/events.js:
161jQuery(loadMaps);
162})();