doOnUnload(function() {
	GUnload();
});

var DynamicMap = Class.create({
	initialize: function(element, options) {
		options = options || {};

		this.element = $(element);
		this.highlightedIndex = -1;
		this._marker = null;
		this._markers = null;

		if (options.point) {
			this._marker = DynamicMap._createMarker(options.point);
		}
		if (options.points) {
			this._markers = options.points.collect(function(point, i) {
				return DynamicMap._createMarker(point, i + 1);
			});
		}

		this._map = new GMap2(this.element);

		var center = options.center;
		var zoomLevel = options.zoomLevel;

		var bounds = (this._markers) ? DynamicMap._createBoundsForMarkers(this._markers) : null;

		if (!center) {
			if (this._marker) {
				center = this._marker.getLatLng();
			} else if (this._markers) {
				center = bounds.getCenter();
			} else {
				center = new GLatLng(0, 0);
			}
		}

		if (!zoomLevel) {
			if (this._markers) {
				zoomLevel = this._map.getBoundsZoomLevel(bounds);
			} else {
				zoomLevel = 14;
			}
		}

		this._map.setCenter(center, zoomLevel);
		this._map.savePosition();

		this._setPanAndZoom(!(options.disallowPanAndZoom || false));

		if (this._marker) {
			this._map.addOverlay(this._marker);
		}

		if (this._markers) {
			this._markers.each((function(marker) { this._map.addOverlay(marker); }).bind(this));
		}
	},

	_setPanAndZoom: function(allowPanAndZoom) {
		if (allowPanAndZoom) {
			this._map.addControl(new GLargeMapControl3D());
			this._map.addControl(new GMapTypeControl());
		} else {
			this._map.disableDragging();
			this._map._recenterOnInfoWindowClose();
		}
	},

	_recenterOnInfoWindowClose: function() {
		var center = this._map.getCenter(); // Closure
		GEvent.addListener(this._map.getInfoWindow(), 'closeclick', function() {
			if (!this._map.getCenter().equals(center)) {
				this._map.setCenter(center);
			}
		});
	},

	centerOnLatLng: function(latLng, zoomLevel) {
		this._map.setCenter(new GLatLng(latLng.lat, latLng.lng), zoomLevel);
	},

	centerOnPoint: function(pointIndex, options) {
		options = options || {};
		var marker = this._markers[pointIndex];
		if (marker) {
			var zoomLevel = options.zoomLevel || this.getZoomLevel();
			if (options.minZoomLevel) {
				zoomLevel = Math.max(zoomLevel, options.minZoomLevel);
			}
			this._map.setCenter(marker.getLatLng(), zoomLevel);
		}
	},

	centerOnAndHighlightPoint: function(pointIndex, options) {
		this.centerOnPoint(pointIndex, options);
		this.highlightPoint(pointIndex);
	},

	clearHighlightedPoint: function() {
		if (this.highlightedIndex >= 0) {
			this._markers[this.highlightedIndex].setImage(DynamicMap._getNumberedIconUrl(this.highlightedIndex + 1));
		}
	},

	closeInfoWindow: function() {
		return this._map.closeInfoWindow();
	},

	getZoomLevel: function() {
		return this._map.getZoom();
	},

	highlightPoint: function(pointIndex) {
		this.clearHighlightedPoint();
		this._markers[pointIndex].setImage(DynamicMap._getHighlightedNumberedIconUrl(pointIndex + 1));
		this.highlightedIndex = pointIndex;
	},

	reset: function() {
		this.closeInfoWindow();
		this.clearHighlightedPoint();
		this._map.returnToSavedPosition();
	}
});

DynamicMap._createIcon = function(num) {
	return (num) ? (new GIcon(G_DEFAULT_ICON, DynamicMap._getNumberedIconUrl(num))) : G_DEFAULT_ICON;
};

DynamicMap._createMarker = function(point, num) {
	var marker = new GMarker(
		new GLatLng(point.lat, point.lng),
		{
			icon: DynamicMap._createIcon(num),
			title: (point.title) ? DynamicMap._getTitle(point.title, num) : null
		}
	);
	if (point.content) {
		marker.bindInfoWindowHtml(DynamicMap._getTitleContent(point, num) + point.content);
	}
	return marker;
};

DynamicMap._getHighlightedNumberedIconUrl = function(num) {
	return 'http://static.mltvacations.com/images/drc/destinationmap/icon/marker' + num + '_highlight.png';
};

DynamicMap._getNumberedIconUrl = function(num) {
	return 'http://static.mltvacations.com/images/drc/destinationmap/icon/marker' + num + '.png';
};

DynamicMap._getTitle = function(title, num) {
	return (num) ? (num + '. ' + title) : title;
};

DynamicMap._getTitleContent = function(point, num) {
	return '<div style="padding: 2px; background-color: #eee; font-weight: bold;">'
		+ DynamicMap._getTitle(point.title, num)
		+ '</div>';
},

DynamicMap._createBoundsForMarkers = function(markers) {
	var bounds = new GLatLngBounds();
	markers.each(function(marker) { bounds.extend(marker.getLatLng()); });
	return bounds;
};

// *** Specific Maps ***

var DestinationMap = Class.create(DynamicMap, {
	initialize: function($super, element, areaLatLngs, hotelPoints) {
		$super(element, { points: hotelPoints });
		this.areaLatLngs = areaLatLngs;
	},

	showArea: function(index) {
		var latLng = this.areaLatLngs[index];
		if (latLng) {
			this.closeInfoWindow();
			this.clearHighlightedPoint();
			this.centerOnLatLng(latLng, 13 /* zoom level */);
		}
	},

	showHotel: function(index) {
		this.closeInfoWindow();
		this.clearHighlightedPoint();
		this.centerOnAndHighlightPoint(index, { minZoomLevel: 14 });
	}
});

DestinationMap.create = function(element, areaLatLngs, hotelPoints) {
	return GBrowserIsCompatible() ? new DestinationMap(element, areaLatLngs, hotelPoints) : null;
};

var HotelMap = Class.create(DynamicMap, {
	initialize: function($super, element, hotelPoint) {
		$super(element, { point: hotelPoint, zoomLevel: 14 });
	}
});

HotelMap.create = function(element, hotelPoint) {
	return GBrowserIsCompatible() ? new HotelMap(element, hotelPoint) : null;
};

