
var MSMap = IMap.extend({
	init: function(id) {
		this.localMarkers = new Array();
		this.localDirections = null;
		this.localDirectionsS = null;
		this.localDirectionsE = null;
		this.currentMarkerId = null;
		this.currentMarkerContent = null;
		this._super(id);
	},
	load: function(params) {
		if (!this.map) {
			var _this = this;

			this.map = new VEMap(this.id);
			//this.map.SetClientToken();
			this.map.onLoadMap = MSExtend;
			var options = new VEMapOptions();
			options.EnableBirdseye = false;
			this.map.LoadMap(new VELatLong(0, 0), 2, null, null, null, null, null, options);
			this.map.ShowMiniMap();

			this.overview = this.container.find("#MSVE_minimap");
			var mm_glyph = $("<span id='MSVE_minimap_glyph'/>").click(function() {
				_this.setOverviewVisible(_this.overview.hasClass("collapsed"))
			});
			this.overview.find("#MSVE_minimap_resize").replaceWith(mm_glyph);
			
			this.map.AttachEvent("onmouseover", function(e){return (e.elementID ? true : false);});
			this.map.AttachEvent("onmouseout", function(e){return (e.elementID ? true : false);});
			this.map.AttachEvent("onclick", function(e){_this._eventHandler(e);});
			
			this.existsDraggable = false;
			this.dragged = false;
			this.dragMarker = null;
			this.dragLocalMarker = null;
			this.map.AttachEvent("onmousedown", function(e){_this._dragMouseDownHandler(e);});
			this.map.AttachEvent("onmousemove", function(e){_this._dragMouseMoveHandler(e);});
			this.map.AttachEvent("onmouseup", function(e){_this._dragMouseUpHandler(e);});
		}
		this._width = this.container.width();
		this._height = this.container.height();
		
		this.map.SetMapMode(VEMapMode.Mode2D);
		
		this._super(params);
	},
	hide: function() {
		this.map.HideInfoBox();
		this._super();
	},
	resize: function() {
		if (this.map && (this._width != this.container.width() || this._height != this.container.height())) {
			this.map.Resize();
			this._width = this.container.width();
			this._height = this.container.height();
		}
	},
	getPosition: function() {
		var latitude = 0;
		var longitude = 0;
		if (this.map) {
			var c = this.map.GetCenter();
			latitude = c.Latitude;
			longitude = c.Longitude;
		}
		return new MapPoint(latitude, longitude);
	},
	setPosition: function(point, zoom) {
		if (this.map) {
			point = point || this.getPosition();
			if (zoom) {
				this.map.SetCenterAndZoom(this._localPoint(point), zoom);
			} else {
				this.map.SetCenter(this._localPoint(point));
			}
		}
	},
	getZoom: function() {
		return this.map ? this.map.GetZoomLevel() : 2;
	},
	setZoom: function(zoom) {
		if (this.map && zoom) {
			this.map.SetZoomLevel(zoom);
		}
	},
	getMapType: function() {
		var type = MapTypes.Road;
		if (this.map) {
			switch (this.map.GetMapStyle()) {
				case VEMapStyle.Aerial:
				case VEMapStyle.Birdseye:
					type = MapTypes.Satellite;
					break;
				case VEMapStyle.Hybrid:
				case VEMapStyle.BirdseyeHybrid:
					type = MapTypes.Hybrid;
					break;
				case VEMapStyle.Road:
				default:
					type = MapTypes.Road;
					break;
			}
		}
		return type;
	},
	setMapType: function(type) {
		if (this.map) {
			switch (type) {
				case MapTypes.Road:
					this.map.SetMapStyle(VEMapStyle.Road);
					break;
				case MapTypes.Satellite:
					this.map.SetMapStyle(VEMapStyle.Aerial);
					break;
				case MapTypes.Hybrid:
					this.map.SetMapStyle(VEMapStyle.Hybrid);
					break;
			}
		}
	},
	setMapUnit: function(unit) {
		if (this.map) {
			switch (unit) {
				case MapUnits.Miles:
					this.map.SetScaleBarDistanceUnit(VEDistanceUnit.Miles);
					break;
				case MapUnits.Kilometers:
					this.map.SetScaleBarDistanceUnit(VEDistanceUnit.Kilometers);
					break;
			}
		}
		this._super(unit);
	},
	getOverviewVisible: function() {
		return (this.overview ? this.overview.hasClass("expanded") : null);
	},
	setOverviewVisible: function(visible) {
		if (this.overview) {
			if (visible) {
				this.overview.animate({height: "150px", width: "150px"}).removeClass("collapsed").addClass("expanded");
			} else {
				this.overview.animate({height: "15px", width: "15px"}).removeClass("expanded").addClass("collapsed");
			}
		}
	},
	getCursor: function() {
		var cursor = (this.container ? this.container.children(":first").css("cursor") : null);
		if (cursor == this.defaultCursor || cursor == "") {
			cursor = null;
		}
		return cursor;
	},
	setCursor: function(cursor) {
		if (this.container) {
			if (cursor == null) {
				cursor = this.defaultCursor;
			}
			this.container.children(":first").css("cursor", cursor);
		}
	},
	framePoints: function(points) {
		if (this.map && points && points.length) {
			var bounds = new Array();
			for (var i in points) {
				bounds.push(this._localPoint(points[i]));
			}
			this.map.SetMapView(bounds);
		}
	},
	mark: function(marker) {
		if (this.map && marker) {
			var m = new VEShape(VEShapeType.Pushpin, this._localPoint(marker.point));
			m.SetDescription(marker.content);
			if (marker.icon) {
				var icon = new VECustomIconSpecification();
				icon.Image = marker.icon.image;
				icon.ImageOffset = new VEPixel(parseInt(marker.icon.size.x / 2) - marker.icon.offset.x, marker.icon.size.y - marker.icon.offset.y);
				icon.TextContent = marker.icon.text || " ";
				icon.TextOffset = new VEPixel(marker.icon.textOffset.x, marker.icon.textOffset.y);

				var div = $("<div/>").addClass("mapper-icon").attr("title",marker.tooltip || "").css({left:parseInt(marker.icon.size.x / 2) - marker.icon.offset.x,top:parseInt(marker.icon.size.y / 2) - marker.icon.offset.y}).append(
					$("<img/>").attr("src", icon.Image)
				).append(
					$("<span/>").css({left:icon.TextOffset.x,top:icon.TextOffset.y}).text(icon.TextContent)
				);
				div.children("img").andSelf().css({height:marker.icon.size.y,width:marker.icon.size.x});
				if (marker.icon.textSize) {
					icon.TextSize = marker.icon.textSize;
					div.children("span").css({fontSize:marker.icon.textSize + "pt"});
				}
				if (marker.clickable) {
					div.css("cursor", "pointer");
				}
				if ($.browser.msie && parseInt($.browser.version) < 7 && icon.Image.search(/.png/i) > 0) {
					div.css({filter:"progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + icon.Image + "', sizingMethod='scale');"}).children("img").remove();
				}
				icon.CustomHTML = $.html(div);

				m.SetCustomIcon(icon);
			}
			if (!marker.visible) {
				m.Hide();
			}
			if (marker.draggable) {
				this.existsDraggable = true;
			}
			
			this.map.AddShape(m);
			this.localMarkers.push([marker.id, m.GetID()]);
		}
		this._super(marker);
	},
	unmark: function(id) {
		if (this.map && id) {
			for (var i in this.localMarkers) {
				if (this.localMarkers[i][0] == id) {
					this.map.DeleteShape(this.map.GetShapeByID(this.localMarkers[i][1]));
					this.localMarkers.splice(i, 1);
					break;
				}
			}
		}
		this._super(id);
		this._checkDraggables();
	},
	unmarkAll: function() {
		if (this.map) {
			this.map.DeleteAllShapes();
			this.localMarkers = new Array();
			this.existsDraggable = false;
		}
		this._super();
	},
	moveMarker: function(id, point) {
		if (this.map && id && point) {
			for (var i in this.localMarkers) {
				if (this.localMarkers[i][0] == id) {
					var m = this.map.GetShapeByID(this.localMarkers[i][1]);
					m.SetPoints(this._localPoint(point));
					break;
				}
			}
		}
		this._super(id, point);
	},
	updateMarkerContent: function(id, content) {
		if (this.map && id) {
			for (var i in this.localMarkers) {
				if (this.localMarkers[i][0] == id) {
					var m = this.map.GetShapeByID(this.localMarkers[i][1]);
					m.SetDescription(content);
				}
			}
		}
		this._super(id, content);
	},
	showMarkerContent: function(id, content) {
		if (this.map && id) {
			this.map.HideInfoBox();			
			var m = this.map.GetShapeByID(this._getLocalMarker(id, false)[1]);
			if (m) {
				var tmp = this.getMarker(id).content;
				var swap = (content && content != tmp);
				if (swap) {
					m.SetDescription(content);
				}
				this.currentMarkerId = m.GetID();
				this.currentMarkerContent = m.GetDescription();
				this._showMarkerContentHandler(m, 1250, swap ? tmp : null);
			}
		}
	},
	_showMarkerContentHandler: function(marker, duration, origContent) {
		var restore = true;
		if (marker.GetID() == this.currentMarkerId && marker.GetDescription() == this.currentMarkerContent) {
			this.map.ShowInfoBox(marker);
			if (duration > 0) {
				restore = false;
				var _this = this;
				setTimeout(function(){_this._showMarkerContentHandler(marker, duration > 250 ? duration - 250 : 0, origContent);}, 250);
			}
		}
		if (restore && origContent) {
			marker.SetDescription(origContent);
		}
	},
	hideMarkerContent: function() {
		if (this.map) {
			this.map.HideInfoBox();
		}
	},
	setMarkerVisibility: function(id, visible) {
		if (this.map && id) {
			for (var i in this.localMarkers) {
				if (this.localMarkers[i][0] == id) {
					var s = this.map.GetShapeByID(this.localMarkers[i][1]);
					if (visible) {
						s.Show();
					} else {
						this.map.HideInfoBox();
						s.Hide();
					}
					break;
				}
			}						
		}
		this._super(id, visible);
	},
	setDirections: function(ids, fn, visible) {
		visible = (visible == false) ? false : true;
		this.clearDirections();
		if (this.map && ids) {
			var wp = new Array();
			for (var i in ids) {
				var m = this.getMarker(ids[i]);
				if (m) {
					wp.push(new VELatLong(m.point.latitude,m.point.longitude));
				}
			}
			
			var options = new VERouteOptions();
/*			options.DrawRoute = false; //FOR TOKEN UPDATE */
			options.DrawRoute = visible;
			options.DistanceUnit = VERouteDistanceUnit.Kilometer;
			options.ShowErrorMessages = false;
			options.SetBestMapView = false;
			options.ShowDisambiguation = false;
			options.UseMWS = true;
       		var _this = this;
			options.RouteCallback = function(Route) {
        		_this.directions = new MapDirections(ids, Route.Distance*1000, Route.Time, visible);
        		
        		for (var i in Route.RouteLegs) {  // REMOVE WITH TOKEN UPDATE
        			var leg = Route.RouteLegs[i];
		       		for (var j in leg.Itinerary.Items) {
		       			var turn = leg.Itinerary.Items[j];
		       			
						if (i == 0 && j == 0) {
			       			_this.localDirectionsS = new VEShapeX(VEShapeType.Polyline, [wp[0],turn.LatLong]);
			       			_this.localDirectionsS.HideIcon();
			       			_this.localDirectionsS.SetLineColor(new VEColor(0, 169, 235, 0.7));
			       			_this.localDirectionsS.SetLineWidth(6);			       			
			       			_this.localDirectionsS.SetLineStyle("Dash");
			       			_this.map.AddShape(_this.localDirectionsS);
			       			var d = GetDistance(_this._mapPoint(wp[0]),_this._mapPoint(turn.LatLong));
			       			_this.directions.steps.push(new MapDirectionsStep(directionsDepart, d, 0, _this._mapPoint(wp[0])));
			       			_this.directions.distance += d;
						}

		       			_this.directions.steps.push(new MapDirectionsStep(turn.Text, turn.Distance ? turn.Distance*1000 : 0, turn.Time, _this._mapPoint(turn.LatLong)));
		       			if (turn.Shape) {
							_this.map.DeleteShape(turn.Shape);
						}

						if (i == Route.RouteLegs.length - 1 && j == leg.Itinerary.Items.length - 1) {
			       			_this.localDirectionsE = new VEShapeX(VEShapeType.Polyline, [turn.LatLong,wp[wp.length - 1]]);
			       			_this.localDirectionsE.HideIcon();
			       			_this.localDirectionsE.SetLineColor(new VEColor(0, 169, 235, 0.7));
			       			_this.localDirectionsE.SetLineWidth(6);			       			
			       			_this.localDirectionsE.SetLineStyle("Dash");
			       			_this.map.AddShape(_this.localDirectionsE);
			       			var d = GetDistance(_this._mapPoint(turn.LatLong),_this._mapPoint(wp[wp.length - 1]));
			       			_this.directions.steps[_this.directions.steps.length - 1].distance = d;
			       			_this.directions.distance += d;
						}
		       		}
        		}
        		

/*  FOR TOKEN UPDATE
				var point1 = wp[0];
				var point2 = Route.ShapePoints[0];
       			_this.localDirectionsS = new VEShapeX(VEShapeType.Polyline, [point1,point2]);
       			_this.localDirectionsS.HideIcon();
       			_this.localDirectionsS.SetLineStyle("Dash");
       			_this.map.AddShape(_this.localDirectionsS);
       			_this.directions.steps.push(new MapDirectionsStep("Depart", GetDistance(_this._mapPoint(point1),_this._mapPoint(point2)), 0, _this._mapPoint(point1)));

        		for (var i in Route.RouteLegs) {
        			var leg = Route.RouteLegs[i];
		       		for (var j in leg.Itinerary.Items) {
		       			var turn = leg.Itinerary.Items[j];
		       			_this.directions.steps.push(new MapDirectionsStep(turn.Text, turn.Distance ? turn.Distance*1000 : 0, turn.Time, _this._mapPoint(turn.LatLong)));
		       		}
        		} 

				point1 = Route.ShapePoints[Route.ShapePoints.length - 1];
				point2 = wp[wp.length - 1];
       			_this.localDirectionsE = new VEShapeX(VEShapeType.Polyline, [point1,point2]);
       			_this.localDirectionsE.HideIcon();
       			_this.localDirectionsE.SetLineStyle("Dash");
       			_this.map.AddShape(_this.localDirectionsE);
       			_this.directions.steps[_this.directions.steps.length - 1].distance = GetDistance(_this._mapPoint(point1),_this._mapPoint(point2));

       			_this.directions.distance += _this.directions.steps[0].distance + _this.directions.steps[_this.directions.steps.length - 1].distance;
				_this.localDirections = new VEShape(VEShapeType.Polyline, Route.ShapePoints);
				_this.localDirections.HideIcon();
				_this.map.AddShape(_this.localDirections);				

*/
				if (!Route.RouteLegs.length) {
        			_this.directions = new MapDirections(ids, GetDistance(_this._mapPoint(wp[0]),_this._mapPoint(wp[wp.length-1])), "?", visible);
					_this.localDirections = new VEShapeX(VEShapeType.Polyline, wp);
					_this.localDirections.HideIcon();
	       			_this.localDirections.SetLineStyle("Dash");
					_this.map.AddShape(_this.localDirections);				
				}
				
				if (!visible) {
					_this.setDirectionsVisibility(visible);
				}

		       	if (fn) {
		       		_this.directions.callback = fn;
	        		fn(_this.directions);
		 		}
  	    	};
			
			this.map.GetDirections(wp, options);
		}
	},
	clearDirections: function() {
		if (this.map) {
			this.map.DeleteRoute();  // REMOVE WITH TOKEN UPDATE
			if (this.localDirections) {
				this.map.DeleteShape(this.localDirections);
			}
			if (this.localDirectionsS) {
				this.map.DeleteShape(this.localDirectionsS);
			}
			if (this.localDirectionsE) {
				this.map.DeleteShape(this.localDirectionsE);
			}
		}
		this.localDirections = null;
		this.localDirectionsS = null;
		this.localDirectionsE = null;
		
		this._super();
	},
	setDirectionsVisibility: function(visible) {
		if (this.map && this.directions) {  // REMOVE WITH TOKEN UPDATE
			if (visible) {
				var wp = new Array();
				for (var i in this.directions.ids) {
					var m = this.getMarker(this.directions.ids[i]);
					if (m) {
						wp.push(this._localPoint(m.point));
					}
				}
				var options = new VERouteOptions();
				var _this = this;
				options.RouteCallback = function(Route) {
	        		for (var i in Route.RouteLegs) {
	        			var leg = Route.RouteLegs[i];
			       		for (var j in leg.Itinerary.Items) {
							_this.map.DeleteShape(leg.Itinerary.Items[j].Shape);
			       		}
	        		} 
	  	    	};
				options.SetBestMapView = false;
				options.ShowErrorMessages = false;
				options.ShowDisambiguation = false;
				options.UseMWS = true;				
				this.map.GetDirections(wp, options);
			} else {
				this.map.DeleteRoute();
			}
		}
	
		if (visible) {
			if (this.localDirections) {
				this.localDirections.Show();
			}
			if (this.localDirectionsS) {
				this.localDirectionsS.Show();
			}
			if (this.localDirectionsE) {
				this.localDirectionsE.Show();
			}
		} else {
			if (this.localDirections) {
				this.localDirections.Hide();
			}
			if (this.localDirectionsS) {
				this.localDirectionsS.Hide();
			}
			if (this.localDirectionsE) {
				this.localDirectionsE.Hide();
			}
		}
		
		this._super(visible);
	},
	_mapPoint: function(point) {
		if (point) {
			return new MapPoint(point.Latitude, point.Longitude);
		}
		return null;
	},
	_localPoint: function(point) {
		if (point) {
			return new VELatLong(point.latitude, point.longitude);
		}
		return null;
	},
	_getLocalMarker: function(id, byShape) {
		if (id) {
			var col = byShape ? 1 : 0;
			for (var i in this.localMarkers) {
				if (this.localMarkers[i][col] == id) {
					return this.localMarkers[i];
					break;
				}
			}
		}
		return null;		
	},
	_getEventPoint: function(e) {
		var point = null;
		if (this.map.GetMapMode() == VEMapMode.Mode2D) {
			var pixel = new VEPixel(e.mapX, e.mapY);
			if (this.map.GetMapStyle() == VEMapStyle.Birdseye || this.map.GetMapStyle() == VEMapStyle.BirdseyeHybrid) {
				point = (new _xy1()).Decode(this.map.GetBirdseyeScene().PixelToLatLong(pixel, this.map.GetZoomLevel()));
			} else {
				point = this.map.PixelToLatLong(pixel);
			}
		} else {
			point = e.latLong;
		}
		return point;
	},
	_eventHandler: function(e) {
		if (this.map) {
			if (e.elementID) {
				var s = this.map.GetShapeByID(e.elementID);
				var id = s.GetID();
				var lm = this._getLocalMarker(id, true);
				if (lm) {
					var m = this.getMarker(lm[0]);
					if (m) {
						if (m.content && e.eventName == "onclick") {
							this.showMarkerContent(m.id);
						}
						for (var j in m.events) {
							if ("on" + m.events[j][0] == e.eventName) {
								m.events[j][1]({marker:m});
							}
						}
					}
				}
			} else {
				for (var i in this.events) {
					if ("on" + this.events[i][0] == e.eventName) {
						this.events[i][1]({point:this._mapPoint(this._getEventPoint(e))});
						// perhaps try to stop bubbling up if fn returns false?
					}
				}
			}
		}
	},
	_dragMouseDownHandler: function(e) {
		if (this.existsDraggable && e.elementID && e.leftMouseButton && this.map && this.map.GetMapMode() == VEMapMode.Mode2D) {
			this.dragLocalMarker = this.map.GetShapeByID(e.elementID);
			this.dragMarker = this.getMarker(this._getLocalMarker(this.dragLocalMarker.GetID(),true)[0]);
			this.dragged = false;
			if (this.dragLocalMarker && this.dragMarker && this.dragMarker.draggable) {
				this.map.vemapcontrol.EnableGeoCommunity(true);
				this.setCursor("crosshair");				
				for (var i in this.dragMarker.events) {
					if (this.dragMarker.events[i][0] == "dragstart") {
						this.dragMarker.events[i][1]({marker:this.dragMarker});
					}
				}
			} else {
				this.dragMarker = null;
				this.dragLocalMarker = null;
			}			
		}
	},
	_dragMouseMoveHandler: function(e) {
		if (this.existsDraggable && this.dragLocalMarker && this.dragMarker && e.leftMouseButton && this.map && this.map.GetMapMode() == VEMapMode.Mode2D) {
			var point = this._getEventPoint(e);
			this.dragLocalMarker.SetPoints(point);
			this.dragMarker.point = this._mapPoint(point);
			this.dragged = true;
			for (var i in this.dragMarker.events) {
				if (this.dragMarker.events[i][0] == "drag") {
					this.dragMarker.events[i][1]({marker:this.dragMarker});
				}
			}
		}
	},
	_dragMouseUpHandler: function(e) {
		if (this.existsDraggable && this.dragLocalMarker && this.dragMarker && e.leftMouseButton && this.map && this.map.GetMapMode() == VEMapMode.Mode2D) {
			if (this.dragged) {
				this.dragMarker.point = this._mapPoint(this.dragLocalMarker.GetPoints()[0]);
				if (this.directions) {
					if ($.inArray(this.dragMarker.id, this.directions.ids) >= 0) {
						this.resetDirections();
					}
				}
				for (var i in this.dragMarker.events) {
					if (this.dragMarker.events[i][0] == "dragend") {
						this.dragMarker.events[i][1]({marker:this.dragMarker});
					}
				}
			}
			// cleanup
			this.dragMarker = null;
			this.dragLocalMarker = null;
			this.dragged = false;
			this.map.vemapcontrol.EnableGeoCommunity(false);
			this.setCursor();			
		}
	},
	_checkDraggables: function() {
		var exists = false;
		for (var i in this.markers) {
			if (this.markers.draggable && this.markers.visible) {
				exists = true;
				break;
			}
		}
		this.existsDraggable = exists;
	}
});

function VEShapeX(type, point) {
	this.ClearAllPrimitives();
	VEShape.apply(this, arguments);
}
function MSExtend() {
	VEShapeX.prototype = new VEShape(VEShapeType.Pushpin, new VELatLong(0,0));
	VEShapeX.prototype.UpdateUI = function(arg1, arg2, arg3, arg4) {
		VEShape.prototype.UpdateUI.apply(this, arguments);
		if (this.LineStyle && this.GetPrimitives().length) {
			this.GetPrimitive(0).symbol.stroke_dashstyle = this.LineStyle;
		}
	}
	VEShapeX.prototype.GetLineStyle = function() {
		return this.LineStyle || "Solid";
	}
	VEShapeX.prototype.SetLineStyle = function(style) {
		this.LineStyle = style;
		if (this.LineStyle && this.GetPrimitives().length) {
			this.GetPrimitive(0).symbol.stroke_dashstyle = this.LineStyle;
		}
	}
}
