SG.namespace("SG.geo");

/***********************************************************************************************************************
 * @deprecated
 **********************************************************************************************************************/
SG.geo = function(id, geoConfig) {
	this.id = id;
	this.geoConfig = geoConfig;

	var key = this.geoConfig.geoMapKeys[window.location.host];
	var src = 'http://maps.google.com/maps?file=api&amp;v=2.x&amp;key=' + key;
	document.write('<' + 'script src="' + src + '"' + ' type="text/javascript"><' + '/script>');

	this.markerIds = [];
	this.markers = [];
};

SG.geo.prototype.id = null;
SG.geo.prototype.geoConfig = null;
SG.geo.prototype.map = null;
SG.geo.prototype.dynamicZoomBounds = null;
SG.geo.prototype.funcPtr = [];
SG.geo.prototype.reasons = [];

SG.geo.prototype.createGeoMap = function() {
	if (GBrowserIsCompatible()) {
		this.map = new GMap2(document.getElementById(this.geoConfig.id));

		var uiOptions = this.map.getDefaultUI();

		if (this.geoConfig.enableScrollWheelZoom != null) {
			uiOptions.zoom.scrollwheel = this.geoConfig.enableScrollWheelZoom;
		}
		if (this.geoConfig.doubleClickZoom != null) {
			uiOptions.zoom.doubleclick = this.geoConfig.doubleClickZoom;
		}
		if (this.geoConfig.typeControl != null) {
			uiOptions.controls.maptypecontrol = this.geoConfig.typeControl;
		}
		if (this.geoConfig.scaleControl != null) {
			uiOptions.controls.scalecontrol = this.geoConfig.scaleControl;
		}
		if (this.geoConfig.largeMapControl != null && this.geoConfig.largeMapControl == true) {
			uiOptions.controls.largemapcontrol3d = true;
		} else {
			uiOptions.controls.largemapcontrol3d = false;
		}
		if (this.geoConfig.smallZoomControl != null && this.geoConfig.smallZoomControl == true) {
			uiOptions.controls.smallzoomcontrol3d = true;
		} else {
			uiOptions.controls.smallzoomcontrol3d = false;
		}

		this.map.setUI(uiOptions);

		this.dynamicZoomBounds = new GLatLngBounds();

		// ====== Array for decoding the failure codes ======
		this.reasons[G_GEO_SUCCESS] = "Success";
		this.reasons[G_GEO_MISSING_ADDRESS] = "Missing Address: The address was either missing or had no value.";
		this.reasons[G_GEO_UNKNOWN_ADDRESS] = "Unknown Address:  No corresponding geographic location could be found for the specified address.";
		this.reasons[G_GEO_UNAVAILABLE_ADDRESS] = "Unavailable Address:  The geocode for the given address cannot be returned due to legal or contractual reasons.";
		this.reasons[G_GEO_BAD_KEY] = "Bad Key: The API key is either invalid or does not match the domain for which it was given";
		this.reasons[G_GEO_TOO_MANY_QUERIES] = "Too Many Queries: The daily geocoding quota for this site has been exceeded.";
		this.reasons[G_GEO_SERVER_ERROR] = "Server error: The geocoding request could not be successfully processed.";

		for ( var i = 0; i < this.geoConfig.geoMarkers.length; i++) {
			var geoMarker = this.geoConfig.geoMarkers[i];
			if (geoMarker.latitude == 0 && geoMarker.longitude == 0) {
				var geocoder = new GClientGeocoder();
				var address = this._formatAddress(geoMarker.street, geoMarker.postcode, geoMarker.city,
						geoMarker.country);
				var idstr = "" + this.id;
				this.funcPtr[i] = new Function("point", "SG.geo." + this.id + "._latLngCallback.call(SG.geo." + this.id
						+ ", point, " + i + ");");
				geocoder.getLocations(address, this.funcPtr[i]);
			} else {
				var point = new GLatLng(geoMarker.latitude, geoMarker.longitude);
				this.map.setCenter(point, this.geoConfig.zoom);

				var marker = this._createMarker(point, 0, geoMarker);

				this.map.addOverlay(marker);

				this.markerIds.push(geoMarker.markerId);
				this.markers.push(marker);

				this.dynamicZoomBounds.extend(point);
			}
		}

		if (this.map.getZoom() < 2) { // dynamic zoom
			var zoomLevel = this.map.getBoundsZoomLevel(this.dynamicZoomBounds);
			if (zoomLevel > 13) {
				zoomLevel = 13;
			}
			this.map.setZoom(zoomLevel);
		}
	}
};

SG.geo.prototype._formatAddress = function(street, postcode, city, country) {
	var address = "";
	if (street && street.length > 0) {
		address = street + ", ";
	}
	if (postcode && postcode.length > 0) {
		address += postcode + ", ";
	}
	if (city && city.length > 0) {
		address += city + ", ";
	}
	if (country && country.length > 0) {
		address += country;
	}
	return address;
};

SG.geo.prototype._createMarker = function(point, colorNr, name, description, link, iconUrl, iconAnchorWidth,
		iconAnchorHeight, isClickable, isDraggable, isBouncy, callbackMethod, size) {
	var config = {
		name : name,
		description : description,
		link : link,
		icon : iconUrl,
		iconAnchorWidth : iconAnchorWidth,
		iconAnchorHeight : iconAnchorHeight,
		clickable : isClickable,
		draggable : isDraggable,
		bouncy : isBouncy,
		callbackMethodDraggend : callbackMethod,
		iconWidth : size,
		iconHeight : size
	};
	return _createMarker(point, colorNr, config);
};

SG.geo._isDefined = function(o) {
	return o != undefined && o != "null" && o != 'undefined' && o != "";
}

SG.geo.prototype._createMarker = function(point, colorNr, geomarker) {
	var icon = new GIcon();
	if (SG.geo._isDefined(geomarker.icon)) {
		icon.image = geomarker.icon;
	} else {
		if (colorNr == 1) {
			icon.image = "http://labs.google.com/ridefinder/images/mm_20_yellow.png";
		} else {
			icon.image = "http://labs.google.com/ridefinder/images/mm_20_red.png";
		}
	}

	if (SG.geo._isDefined(geomarker.shadowIcon)) {
	icon.shadow = geomarker.shadowIcon;
	icon.shadowSize = new GSize(geomarker.shadowIconWidth, geomarker.shadowIconHeight);
	icon.iconAnchor = new GPoint(geomarker.iconAnchorWidth, geomarker.iconAnchorHeight);
	} else {
		icon.shadow = "http://labs.google.com/ridefinder/images/mm_20_shadow.png";
		icon.shadowSize = new GSize(22, 20);
		icon.iconAnchor = new GPoint(6, 20);
	}
	icon.infoWindowAnchor = new GPoint(5, 1);

	if (geomarker.iconWidth && geomarker.iconHeight) {
		icon.iconSize = new GSize(geomarker.iconWidth, geomarker.iconHeight);
	}

	/*
	 * Attention: even if isClickable is set to false, it should be set to true here. Non-clickable GMarkers don't
	 * support mouseover and mouseout eventlisteners. If the parameter isClickable is set to false, no eventlistener for
	 * 'click' will be registered.
	 */
	var options = {
		icon : icon,
		clickable : true,
		draggable : geomarker.draggable,
		bouncy : geomarker.bouncy,
		title : geomarker.title
	};

	var marker = new GMarker(point, options);

	if (geomarker.clickable) {
		GEvent.addListener(marker, "click", function() {
			var nameContent;
			var descriptionContent;

			if (SG.geo._isDefined(geomarker.description)) {
				descriptionContent = '<br><div style="font-size:10; text-decoration: none;" > ' + geomarker.description
						+ "</div>";
			} else {
				descriptionContent = "";
			}

			if (SG.geo._isDefined(geomarker.link)) {
				nameContent = '<a href="' + geomarker.link + '"> <b>' + geomarker.name + "</b>" + descriptionContent
						+ "</a>";
			} else if (SG.geo._isDefined(geomarker.name)) {
				nameContent = "<b>" + geomarker.name + "</b>" + descriptionContent;
			}

			marker.openInfoWindowHtml(nameContent);
		});
	} else if (SG.geo._isDefined(geomarker.link)) {
		GEvent.addListener(marker, "click", function() {
			window.location = geomarker.link;
		});
	}

	if (geomarker.draggable) {
		GEvent.addListener(marker, "dragend", function(p1) {
			marker = p1;
		});

		if (geomarker.callbackMethodDraggend != null) {
			GEvent.addListener(marker, "dragend", eval(geomarker.callbackMethodDraggend));
		}
	}

	if (geomarker.mouseoverFunction) {
		GEvent.addListener(marker, "mouseover", eval(geomarker.mouseoverFunction));
	}
	if (geomarker.mouseoutFunction) {
		GEvent.addListener(marker, "mouseout", eval(geomarker.mouseoutFunction));
	}

	return marker;
};

SG.geo.prototype._latLngCallback = function(result, id) {
	var geoMarker = this.geoConfig.geoMarkers[id];
	if (result.Status.code == G_GEO_SUCCESS) {
		this.funcPtr[id] = null;
		var p = result.Placemark[0].Point.coordinates;
		var point = new GLatLng(p[1], p[0]);
		this.map.setCenter(point, this.geoConfig.zoom);

		this.map.addOverlay(this._createMarker(point, 0, geoMarker));
	} else {
		var address = this._formatAddress(geoMarker.street, geoMarker.postcode, geoMarker.city, geoMarker.country);
		/*
		 * var reason="Code "+result.Status.code; if (this.reasons[result.Status.code]) { reason =
		 * this.reasons[result.Status.code] } alert('Could not find "' + address + '" ' + reason);
		 */

		if (result.Status.code != G_GEO_UNKNOWN_ADDRESS) {
			var geocoder = new GClientGeocoder();
			geocoder.getLocations(address, this.funcPtr[id]);
		}
	}
};

/***********************************************************************************************************************
 * Geo (NEW)
 **********************************************************************************************************************/

SG.geo.apis = {};
SG.geo.providers = {};

SG.geo.helper = {
	isDefined : function(o) {
		return !(typeof o === 'undefined');
	}
};

/**
 *
 *
 * @author cmd
 */
SG.geo.Provider = function(target, config, context) {
	this.init(target, config, context);
};

SG.geo.Provider.prototype = {
	api : 'google',
	src : 'http://maps.google.com/maps?file=api&amp;v=3.x',
	target : 'geo_map',
	map : null,
	key : null,

	config : {
		zoom : 4
	},

	init : function(target, config, context) {
		this.target = target;
		if (config.apiName) {
			this.api = config.apiName;
		}
		if (config.apiUrl) {
			this.src = config.apiUrl;
		}
		if (config.key) {
			this.key = config.key;
		} else {
			this.key = config.keys[window.location.host];
		}
		if(config.keyname) {
			this.keyname = config.keyname;
		}
		this.config = config;

		this.includeProvider(context);
	},

	includeProvider : function(context) {
		/*
		 * sg-geo.js depends on mapstraction and some of its modules. The
		 * mapstraction implementation consists of several files: core, geocode
		 * and navigation and the respective implementation for each api supported.
		 *
		 * The mapstractio js-files have to included manually in the page, e.g.
		 *
		 * <ui:staticFileInclude file="/javascript/mxn/mxn.js"></ui:staticFileInclude>
		 * <ui:staticFileInclude file="/javascript/mxn/mxn.core.js"></ui:staticFileInclude>
		 * <ui:staticFileInclude file="/javascript/mxn/mxn.geocode.js"></ui:staticFileInclude>
		 * <ui:staticFileInclude file="/javascript/mxn/mxn.navigation.js"></ui:staticFileInclude>
		 * <ui:staticFileInclude file="/javascript/mxn/mxn.googlev3.core.js"></ui:staticFileInclude>
		 * <ui:staticFileInclude file="/javascript/mxn/mxn.googlev3.geocode.js"></ui:staticFileInclude>
		 * <ui:staticFileInclude file="/javascript/mxn/mxn.googlev3.navigation.js"></ui:staticFileInclude>
		 */
		if (!SG.geo.apis[this.api]) {
			var url = this.src;
			if (this.key) {
				url += "&amp;" + this.keyname +"=" + this.key;
			}
			document.write('<script src="' + url + '" type="text/javascript"></script>');
			SG.geo.apis[this.api] = true;
		}
	}
};

SG.geo.Map = function(provider, config) {
	this.init(provider, config);
};

SG.geo.Map.prototype = {
	map : null,

	config : {},

	init : function(provider, config) {
		this.map = new mxn.Mapstraction(provider.target, provider.api);
		this.geocoder = new mxn.MapstractionGeocoder(provider.api);
		this.navigator = new mxn.MapstractionNavigator(this.map, provider.api);
		this.config = config;
		this.setUpUI();
		if (this.config["markers"] && this.config.markers.length > 0) {
			this.addMarkers(this.config.markers);
			if (this.config.enableDynamicZoom) {
				this.map.autoCenterAndZoom();
			} else {
				this._setCenterAndZoom(this.lastPoint);
			}
		} else {
			this._setDefaultCenterAndZoom();
		}
	},

	setUpUI : function() {
		if (this.config["mapType"]) {
			try {
				this.map.setMapType(this.config.mapType);
			} catch (e) {
			}
		}
		if (SG.geo.helper.isDefined(this.config["enableDragging"])) {
			this.map.setOption("enableDragging", this.config.enableDragging);
		}
		if (SG.geo.helper.isDefined(this.config["enableScrollWheelZoom"])) {
			this.map.setOption("enableScrollWheelZoom", this.config.enableScrollWheelZoom);
		}
		 if(SG.geo.helper.isDefined(this.config["enableDoubleClickZoom"])) {
			 this.map.setOption("enableDoubleClickZoom", this.config.enableDoubleClickZoom);
		 }
		if (this.config["controls"]) {
			this.map.addControls(this.config.controls);
		}
		this.map.setOptions(this.config);
	},

	addMarkers : function() {
		var point;
		for ( var i = 0; i < this.config.markers.length; i++) {
			point = this._createMarker(this.config.markers[i]);
		}
	},

	directions : function(from, to, options) {
		var map = this;
		var request = this._buildNavigationRequest(from, to);
		this.navigator.navigate(request, options);
	},

	_createMarker : function(markerConfig) {
		if (!markerConfig.latitude && !markerConfig.longitude) {
			this._createMarkerFromAddress(markerConfig);
		} else {
			this._createMarkerFromCoordinates(markerConfig);
		}
	},

	_createMarkerFromAddress : function(markerConfig) {
		var address = this._formatAddress(markerConfig);
		var map = this;
		this.geocoder.geocode(address, function(location) {
			map._createMarkerFromAddressCallback(markerConfig, location);
		});
	},

	_createMarkerFromAddressCallback : function(markerConfig, location) {
		this._updateMarkerConfig(markerConfig, location);
		this._createMarkerFromCoordinates(markerConfig);
	},

	_updateMarkerConfig : function(markerConfig, location) {
		if (location[0] && location[0].point) {
			markerConfig.latitude = location[0].point.lat;
			markerConfig.longitude = location[0].point.lng;
		}
	},

	_createMarkerFromCoordinates : function(markerConfig) {
		var point = new mxn.LatLonPoint(markerConfig.latitude, markerConfig.longitude);
		var data = this._buildMarkerData(markerConfig);
		var marker = new mxn.Marker(point);
		this.map.addMarkerWithData(marker, data);
		this.lastPoint = point;
	},

	_buildMarkerData : function(markerConfig) {
		var data = {};
		data.infoBubble = this._buildBubbleContent(markerConfig);
		data.multipleBubbles=false;
		data.label = markerConfig.name;
		data.clickable = markerConfig.clickable;
		data.draggable = markerConfig.draggable;
		data.hover = false;
		data.mouseoverFunction = markerConfig.mouseoverFunction;
		data.mouseoutFunction = markerConfig.mouseoutFunction;
		data.dragendFunction = markerConfig.dragendFunction;
		if (markerConfig.icon && markerConfig.icon.length > 0) {
			data.icon = markerConfig.icon;
		}
		if (markerConfig.iconWidth || markerConfig.iconHeight) {
			data.iconSize = [ markerConfig.iconWidth, markerConfig.iconHeight ];
		}
		if (markerConfig.iconAnchorWidth || markerConfig.iconAnchorHeight) {
			data.iconAnchor = [ markerConfig.iconAnchorWidth, markerConfig.iconAnchorHeight ];
		}
		if (markerConfig.shadowIcon && markerConfig.shadowIcon.length > 0) {
			data.iconShadow = markerConfig.iconShadow;
		}
		if (markerConfig.shadowIconWidth || markerConfig.shadowIconHeight) {
			data.iconShadowSize = [ markerConfig.shadowIconWidth, markerConfig.shadowIconHeight ];
		}
		return data;
	},

	_buildBubbleContent : function(markerConfig) {
		var bubbleContent = [];
		var description = [];
		if ((markerConfig.description && markerConfig.description.length > 0)
				|| (markerConfig.name && markerConfig.name.length > 0)) {
			description.push('<div style="font-size:10">');
			if (markerConfig.name && markerConfig.name.length > 0) {
				description.push( [ '<strong>', markerConfig.name, '</strong>', '<br />' ].join(''));
			}
			if (markerConfig.description && markerConfig.description.length > 0) {
				description.push(markerConfig.description);
			}
			description.push('</div>');
			description.push('<div>');
			if (markerConfig.link && markerConfig.link.length > 0) {
				bubbleContent.push('<a style="text-decoration:none" href="', markerConfig.link, '">', description
						.join(''), '</a>');
			} else {
				bubbleContent = description;
			}
		}
		return bubbleContent.join('');
	},

	_setDefaultCenterAndZoom : function() {
		var point = new mxn.LatLonPoint(48.303056, 14.290556);
		this.map.setCenterAndZoom(point, this.config.zoom);
	},

	_setCenterAndZoom : function(point) {
		if (point) {
			this.map.setCenterAndZoom(point, this.config.zoom);
		} else {
			this._setDefaultCenterAndZoom();
		}
	},

	_formatAddress : function(markerConfig) {
		var address = [];
		if (markerConfig.street && markerConfig.street.length > 0) {
			address.push( [ markerConfig.street, ", " ].join(""));
		}
		if (markerConfig.postcode && markerConfig.postcode.length > 0) {
			address.push( [ markerConfig.postcode, ", " ].join(""));
		}
		if (markerConfig.city && markerConfig.city.length > 0) {
			address.push( [ markerConfig.city, ", " ].join(""));
		}
		if (markerConfig.country && markerConfig.country.length > 0) {
			address.push(markerConfig.country);
		}
		return address.join("");
	},

	_buildNavigationRequest : function(from, to) {
		var request = {};
		request.from = from;
		request.to = to;
		return request;
	}
};
