
/* reasons to update map */

var REASON_INIT = 1;
var REASON_DATA = 2;
var REASON_SWITCH = 3;
var REASON_ZOOM = 4;
var REASON_CAT_FILTER = 5;
var REASON_MOVE = 6;
var REASON_MARKER = 7;

var xmap;
var map;

var frontMarker = null;
var afterReloadMap = null;

function XMarker(info) {
	this.in_route = info.r;
	this.uid = info.uid;
	this.cat = info.cat;
	this.fcat = info.fcat;
	this.lng = info.lng;
	this.lat = info.lat;
	this.title = info.t;
	this.inv = info.inv;
	this.rid = info.rid;
	this.own = info.own;
	this.gcreated = false;
	this.visible = false;
}
XMarker.prototype.show = function(flag, map) {
	if (flag) {	
		// check whether icon needs to be switched and if so recreate marker from scratch
		var icon;
		if (this.inv || this.hiddenEnd) {
			if (this.end || this.hiddenEnd)
				icon = xmap.invisibleEndIcon;
			else
				icon = xmap.invisibleIcon;
		} else {
			icon = xmap.gicons[this.cat];
			if (!icon)
				icon = xmap.invisibleIcon;	
		}
		
		if (this.icon !== icon) {
			if (this.gcreated)
				map.removeOverlay(this.gmarker);
			this.visible = false;
			this.gcreated = false;				
		}

		if (! this.visible) {
			if (! this.gcreated) {
				var point = new GLatLng(this.lat, this.lng);
				this.icon = icon;
				var opts = {icon:icon};
				if (this.own)
					opts.draggable = true;
				var gmarker = new GxMarker(point, opts, this.getShowTitle());
				this.gmarker = gmarker;
				this.gcreated = true;

				GEvent.addListener(gmarker, "click", function() {
					if (xmap.rm)
						xmap.rm.selectObject(null);
					xmap.openInfoWindow(this.getShowUid());
				}.bind(this));
				if (this.own) {
					GEvent.addListener(gmarker, "dragend", function() {
						if (this.uid) {
							xmap.markerMoved(this);
						}
					}.bind(this));					
				}
			}
			map.addOverlay(this.gmarker);
			this.visible = true;
		}
	} else {
		if (this.gmarker) {
			map.removeOverlay(this.gmarker);
			this.visible = false;
		}
	}
}
XMarker.prototype.getShowUid = function(){
	var uid;
	if (! this.own)
		uid = this.showUid;
	if (!uid) 
		uid = this.uid;
	return uid;
}
XMarker.prototype.getShowTitle = function(){
	var title;
	if (! this.own)
		title = this.showTitle;
	if (!title) 
		title = this.title;
	return title;
}

XMarker.prototype.setFront = function(flag) {
	if (! flag)
		frontMarker = null;
	else
		frontMarker = this;
}
XMarker.prototype.getCoord = function() {
	return new GLatLng(this.lat, this.lng);
}

//---------------------


function XMap(startWithRoutes) {
	map = new GMap2(document.getElementById(mapConf.mapDiv));
	this.map = map;
	map.addControl(new GSmallMapControl());
	map.addControl(new GMapTypeControl());
	//map.addControl(new GLargeMapControl());
	   
	map.setCenter(new GLatLng(mapConf.mapLat, mapConf.mapLng), mapConf.mapZoom);

	// GEvent.addListener(map, "moveend", function() { this.onMoveEnd(); }.bind(this));
	GEvent.addListener(map, "moveend", function() { this.refresh(REASON_MOVE); }.bind(this));
	GEvent.addListener(map, "zoomend", function() { this.refresh(REASON_ZOOM); }.bind(this));
	// GEvent.addListener(map, "zoomend", function() { this.refresh(); }.bind(this));

	// prepare classes
	ClusterManager.prototype.options = {
		width: 90,
		height: 90,
		bgImage: '/fileadmin/bikemap/i/cluster_bg.png',
		listenerJsref: 'xmap.cm',	
		minObjectsPerCluster: 4	
	};
	GCluster.createClass(); 
	GCluster.override({
		options : ClusterManager.prototype.options
	});

	RouteManager.prototype.getActiveCats = getActiveCats;
	RouteManager.prototype.getMarker = function(uid){
		return xmap.markerMap[uid];
	}

	RouteManager.prototype.onObjectSelect = function(uid) {
		this.openInfoWindow(uid);
		return true;
	}.bind(this);

	PolyHighlighter.prototype.getCatInfo = function(uid) {
		return catMap[uid];
	}
	
	GZoomer.createClass();

	this.showInvisibleMarkers = true;

	this.gicons_prefix = '/fileadmin/bikemap/i/marker/';
	this.prepareIcons();
	
	// display load progress
	if (loadProgressStart)
		loadProgressStart();	

	this.routesEnabled = -1;
	this.afterFetch = function(){
		xmap.enableRoutes(startWithRoutes);
	};
    this.loadData();
}

XMap.prototype.refresh = function(reason){
	if (! this.dataLoaded || this.rotesEnabled === -1)
		return;
	if (! reason)
		reason = REASON_INIT;
	if (this.routesEnabled) {
		this.refreshRoutes(reason);
		this.refreshMarkersNoClusters(reason);
	} else { 
		this.refreshMarkers(reason);
	}
}

XMap.prototype.refreshMarkers = function(reason){
	var rebuild = true;
	if (reason == REASON_MOVE)
		rebuild = false 

	var zoom = this.map.getZoom();
	var cm = this.cm;

	if (rebuild) {
		// rebuild clusters, recalc coords
		cm.clear();
		this.adjustMarkerProjectionCoord(zoom);
		this.iterateMarkers(function(m) {
			if (! m.in_route)
				cm.assignCluster(m); // .cluster needs only assigned once upon zoom
		});
	} else {
		cm.clearCounts(); // only nead to clear counts if custers not rebuilt	
	}

	var activeCats = getActiveCats();
	this.resetCatCount();
	var ir = this.routesEnabled ? 1 : 0;
	var pBounds = this.getSmartProjectionBounds(zoom);
	var map = this.map;

	var showInvisible = this.showInvisibleMarkers;
	var _this = this;
	this.iterateMarkers(function(m) {
		var displayable = (! m.deleted) && (ir == m.in_route); // for filter counts

		if (displayable) // accountable in cat filter counts
			_this.addCatCount(m.fcat, 1);

		var visibleForClusters = displayable && (
			m.inv ? (showInvisible && m.own) : activeCats[m.fcat]
		);
		// counting markers in clusters
		if (visibleForClusters)
			m.cluster.count++;

		var showOnScreen = (
			(visibleForClusters || (m === frontMarker)) &&
			pBounds.containsPoint(new GPoint(m.px, m.py))
		);
		// temporarily remember that it's visible for now
		// final visibility will be affected by cluster validity (obj count)
		m._v = showOnScreen;	
	});

	// show/hide markers finally
	this.iterateMarkers(function(m){
		var show = (m._v && (! m.cluster.isValid())); // if cluster contains less that the minimum of markers necessary for clusteringg
		delete m._v;
		m.show(show, map);
	});

	// show/hide clusters
	for (var key in cm.clusters) {
		var c = cm.clusters[key];
		var show = c.isValid() && pBounds.containsPoint(new GPoint(c.px, c.py));
		c.display(show, this.map);
	}
	this.updateCatCount();
}


XMap.prototype.refreshMarkersNoClusters = function(reason) {
	if (! this.dataLoaded)
		return;
// debugger;
	var zoom = this.map.getZoom();
	if (reason != REASON_MOVE) {
		this.adjustMarkerProjectionCoord(zoom);
	}

	var activeCats = getActiveCats();

	var ir = this.routesEnabled ? 1 : 0;
	
	var markerInfos = this.markerInfos;
	var rm = this.rm;
	function checkFilter(m){
		delete m.hiddenEnd;
		delete m.showUid;
		delete m.showTitle;

		// calculate if it's hidden end
		var info = markerInfos[m.uid];
		var visibleSegCount = 0;
		var visibleSegUid;
		var visibleSegTitle;
		if (info && info.segs) {
			for (var seguid in info.segs) {
				var seg = rm.segMap[seguid];
				if (activeCats[seg.cat]) {
					visibleSegCount++;
					visibleSegUid = seguid;
					visibleSegTitle = seg.t;
				}
			}
		}

		if (m.inv) { // check whether this inv. point belongs to a visible seg
			if (visibleSegCount) {
				m.showUid = visibleSegUid;
				m.showTitle = visibleSegTitle;
			}	
			if (!visibleSegCount) 
				return false;
		} else { 
			var visible = activeCats[m.fcat];
			if (!visible && visibleSegCount > 0) {
				m.hiddenEnd = true;
				m.showUid = visibleSegUid;
				m.showTitle = visibleSegTitle;
				return true;
			}
			return visible;
		}
			
		if (m.end || m.hiddenEnd)
			return true;
		return (showInvisible && m.own);
	}

	var pBounds = this.getSmartProjectionBounds(zoom);
	var map = this.map;
	var showInvisible = this.showInvisibleMarkers;
	this.iterateMarkers(function(m) {
		var displayable = (! m.deleted) && (ir == m.in_route); // for filter counts

		var filterOK = displayable && checkFilter(m);

		var showOnScreen = (
			(filterOK || (m === frontMarker)) &&
			pBounds.containsPoint(new GPoint(m.px, m.py))
		);
		m.show(showOnScreen, map);
	});
}

XMap.prototype.refreshRoutes = function(reason) {
	this.rm.refresh(reason);
}

// switches mode of operation;
XMap.prototype.enableRoutes = function(flag, force) {
	if (! this.dataLoaded)
		return;

	if (this.routesEnabled == flag && ! force)
		return;

	this.routesEnabled = flag;
	
	this.map.clearOverlays();
	
	/* initialize route mode */
	if (this.routesEnabled) {
		// destroy clustering
		if (this.cm) { // need to destroy gracefully
			this.iterateMarkers(function(m) {
				delete m.cluster;
			});
			this.cm.destroy();
			delete this.cm;
		}
		
		this.rm = new RouteManager();
		this.rm.setMap(this.map);
		this.rm.setRoutes(this.data.routes)
	} else {
		// no destroy method
		delete this.rm;
		this.cm = new ClusterManager();
		this.cm.setMap(this.map);
	}
	this.refresh(REASON_SWITCH); // display markers or routes
}

XMap.prototype.toggleInvisibleMarkers = function() {
	this.showInvisibleMarkers = ! this.showInvisibleMarkers;
	this.refresh(top.REASON_MARKER)
}

XMap.prototype.catFilterChanged = function(){
	xmap.refresh(REASON_CAT_FILTER);
}
XMap.prototype.resetCatCount = function(reason) {
	this.catCount = {};
	for (cuid in catMap)
		this.catCount[cuid] = 0;
}
XMap.prototype.addCatCount = function(cat, val) {
	this.catCount[cat] += val;
}
XMap.prototype.updateCatCount = function(){
	updateCatCount(this.catCount);
}

XMap.prototype.getSmartProjectionBounds = function(zoom) {
	var proj = G_NORMAL_MAP.getProjection();
	var bounds = map.getBounds();
	var ne = bounds.getNorthEast();
	var sw = bounds.getSouthWest();
	var nePoint = proj.fromLatLngToPixel(ne, zoom);
	var swPoint = proj.fromLatLngToPixel(sw, zoom);
	// extend upwards and to the left
	if (this.routesEnabled) {
		swPoint.x -=  10;
		nePoint.y -=  2;
	} else {
		swPoint.x -= this.cm.options.width + 2;
		nePoint.y -= this.cm.options.height + 2;
	}
	// extend downwards and to the right
	swPoint.y += 20;
	nePoint.x += 10;
	return new GBounds([nePoint, swPoint]);
}

XMap.prototype.adjustMarkerProjectionCoord = function(zoom) {
	var proj = G_NORMAL_MAP.getProjection();
	this.iterateMarkers(function(m) {
		var tilePoint = proj.fromLatLngToPixel(new GLatLng(m.lat, m.lng), zoom);
		m.px = tilePoint.x;
		m.py = tilePoint.y;
	});
}

XMap.prototype.reloadData = function(func) {
	this.dataLoaded = false;
	this.afterFetch = function(){
		this.enableRoutes(this.routesEnabled, true);
		if (func)
			func();
	};
	this.loadData();
}

XMap.prototype.loadData = function() {
  	var url = '/index.php?id='+ PID_AJAX_PLAIN_MARKERS + '&pid='+ PID_MARKERS + '&slt='+Math.random();
	new Ajax.Request(url, {
		method:'get',
		onSuccess: function(transport) {
			var response = transport.responseText;
			xmap.processData(response);
		},
		onFailure: function(){ alert('Unable to fetch data') }
	});
}

XMap.prototype.processData = function (text) {
// debugger;
	this.markerMap = {};
	this.uidTypeMap = {};
	this.routeMap = {};

	var data;
	try {
		eval('data = '+text);
	} catch (e) {
		alert(3);
		return;
	}
	this.data = data;

	var i;
	
	this.resetCatCount();
	
	// putting routes to map
	if (data.routes) {
		for (i = 0; i < data.routes.length; i++) {
			var r = data.routes[i];
			this.routeMap[r.uid] = r;
			this.uidTypeMap[r.uid] = 'r';
			if (! r.segs)
				continue;
			// setting segment's filter cats to the cat of the containing route
			for (var j = 0; j < r.segs.length; j++) {
				var seg = r.segs[j];
				// seg.fcat = r.cat;
				seg.fcat = seg.cat;
				this.addCatCount(seg.cat, 1);
				this.uidTypeMap[seg.uid] = 's';
				/* don't put edges anywhere for now because uids overlap with tt_address
				if (seg.edges) {
					for (var k = 0; k < seg.edges.length; k++) {
						var edge = seg.edges[k];
						xuidTypeMap[edge.uid] = 'e';
					}
				}
				*/
			}
		}
	} else {
		data.routes = [];
	}

	// adding markers
	if (data.markers) {
		for (i = 0; i < data.markers.length; i++) {
			var m = data.markers[i];
			this.uidTypeMap[m.uid] = 'm';
			// setting marker's filter cat to the cat of the containing route
			/*
			if (m.r) { // in route
				var route = this.routeMap[m.rid];
				if (route)
					m.fcat = route.cat;
				else
					m.fcat = m.cat;
			} else {
				m.fcat = m.cat;
			}
			*/
			m.fcat  = m.cat;
			if (! m.inv)
				this.addCatCount(m.cat, 1);
			this.addMarker(m);
		}
	} else {
		data.markers = [];
	}
	this.updateCatCount();

	this.postProcessData();

	this.dataLoaded = true;

	// hide load progress
	if (loadProgressFinish) {
		loadProgressFinish();
	}
	if (this.afterFetch) {
		this.afterFetch();
		afteFetch = null;
	}
}

XMap.prototype.postProcessData = function(){
	var markerInfos = {};

	// counting how many segs and edges go through every marker	
	function addMarkerInfo(puid, seg, edge) {
		var info = markerInfos[puid];
		if (! info) {
			info = {
				segs : {},
				uniqueSegCount : 0,
				edgeCount : 0
			}
			markerInfos[puid] = info;
		}
		if (!info.segs[seg.uid]) {
			info.segs[seg.uid] = seg;
			info.uniqueSegCount++;
		}
		info.edgeCount++;
	}
	
	// filling markerInfos
	var routes = this.data.routes;
	for (var i = 0; i < routes.length; i++) {
		var route = routes[i];
		if (! route.segs)
			continue;
		for (var j = 0; j < route.segs.length; j++) {
			var seg = route.segs[j];
			if (! seg.edges)
				continue;
			for (var k = 0; k < seg.edges.length; k++) {
				var edge = seg.edges[k];
				addMarkerInfo(edge.p1, seg, edge);
				addMarkerInfo(edge.p2, seg, edge);
			}
		}
	}

	// finding invisible end markers
	for (var puid in markerInfos) {
		var info = markerInfos[puid];
		var m = this.markerMap[puid];
		if (m.inv && info.edgeCount < 2)
			m.end = true;
	}
	
	this.markerInfos = markerInfos;
	
	/* not needed because visibility correct in DB
	// correcting visibility
	for (var puid in markerInfos) {
		var info = markerInfos[puid];
		var invisible = (info.uniqueSegCount == 1 && info.edgeCount == 2);
		this.markerMap[puid].inv = invisible;
	}
	*/
}

// manage marker
XMap.prototype.addMarker = function(info) {
	var xmarker = new XMarker(info);
	this.markerMap[info.uid] = xmarker;
}

// once map is rendered following methods are to handle markers:
XMap.prototype.addNewMarker = function(info) {
	this.addMarker(info);
	this.adjustToZoom(map.getZoom());
	this.refresh(REASON_MARKER);
}
XMap.prototype.removeMarker = function(uid) {
	var m = this.markerMap[uid];
	m.hidden = true;
	this.adjustToZoom(map.getZoom());
	this.refresh(REASON_MARKER);
}


/* *** info window *** */

XMap.prototype.openInfoWindow = function(uid) {
	var url = '/index.php?id='+PID_AJAX_MARKER_BUBBLE+'&uid='+ uid +'&slt='+Math.random();
	new Ajax.Request(url, {
		method:'get',
		onSuccess: function(transport) {
			this.processMarkerXML(uid, transport.responseXML);
			showDetails(uid);
		}.bind(this),
		onFailure: function(){ alert('Unable to fetch content') }
	});
}

XMap.prototype.processMarkerXML = function(uid, dom) {
	dom = dom.documentElement;
	var tabLabels = [
		'Info',
		'Bilder',
		'Extra',
		'Plus'
	];
	var labels = [];
	var htmls = [];
	for (var i = 1; i <= tabLabels.length; i++) {
		var html;
		var tag = (i == 1) ? 'html' : 'html'+i;
		var node = dom.getElementsByTagName(tag)[0];
		if (node) {
			labels.push(tabLabels[i - 1]);
			htmls.push(GXml.value(node));
		}
	}

	// adjust the width so that the info window is large enough for this many tabs
	if (htmls.length > 2) {
		htmls[0] = '<div style="color: #000000; width:'+htmls.length*88+'px">xxx' + htmls[0] + '</div>';
	}

	var tabs = [];
	for (var i=0; i<htmls.length; i++) {
		tabs.push(new GInfoWindowTab(labels[i],htmls[i]));
	}
	if (this.markerMap[uid]) {
		this.markerMap[uid].gmarker.openInfoWindowTabsHtml(tabs);
	} else if (this.routesEnabled) {
		xmap.rm.selectObject(uid);

		var type = this.uidTypeMap[uid];
		var coord; 
		switch (type) {
			case 's' : {
				try {
					coord = this.rm.getSegCoord(uid);
					break;
				} catch (e) {return;}
			}
			case 'r' : {
				try {
					coord = this.rm.getRouteCoord(uid);
					break;
				} catch (e) {return;}
			}
		}
		map.openInfoWindowTabsHtml(coord, tabs);
	}
}

XMap.prototype.prepareIcons = function() {
	this.gicons = {};
	this.baseIcon = new GIcon();

	this.baseIcon.shadow = this.gicons_prefix + 'shadow.png';
/*
	this.baseIcon.iconSize = new GSize(22, 35);
	this.baseIcon.shadowSize = new GSize(43, 35);
	this.baseIcon.iconAnchor = new GPoint(9, 30); // offset from top left corner
*/ // new blue icons
	if (typeof(IS_HOTSHIT) != 'undefined') {
		this.baseIcon.iconSize = new GSize(17, 23);
		this.baseIcon.iconAnchor = new GPoint(12, 39); // offset from top left corner
		this.baseIcon.shadowSize = new GSize(43, 15);
	} else {
		this.baseIcon.iconSize = new GSize(24, 39);
		this.baseIcon.iconAnchor = new GPoint(12, 39); // offset from top left corner
		this.baseIcon.shadowSize = new GSize(43, 35);
	}


	this.baseIcon.infoWindowAnchor = new GPoint(12, 5);

	// this.baseIcon.imageMap = [4,0,0,4,0,7,3,11,4,19,7,19,8,11,11,7,11,4,7,0];

	for (var key in all_cats) {
		var cats = all_cats[key];	
		for (var i = 0; i < cats.length; i++) {
			var cat = cats[i];
			this.addCatIcon(cat.uid, cat.icon);
			
			// build map also
			catMap[cat.uid] = cat;
		}
	}

	// creating invisible markers
	var icon;

	// normal invisible
    icon = new GIcon(this.baseIcon);
	icon.image = this.gicons_prefix + 'marker_invisible.png';
	icon.iconSize = new GSize(18, 31);
	icon.iconAnchor = new GPoint(9, 29);
	icon.infoWindowAnchor = new GPoint(9, 5);	
	delete icon.shadow;
	delete icon.shadowSize;
	this.invisibleIcon = icon;


	// end point invisible
	icon = new GIcon(this.baseIcon)	
    icon.image = this.gicons_prefix + 'marker_end_invisible.png';
	icon.iconSize = new GSize(25, 25);
	icon.iconAnchor = new GPoint(12, 12);
	icon.infoWindowAnchor = new GPoint(12, 5);	
	delete icon.shadow;
	delete icon.shadowSize;
	this.invisibleEndIcon = icon;
}

XMap.prototype.addCatIcon = function(cat, img) {
    var icon = new GIcon(this.baseIcon);
    icon.image = this.gicons_prefix + img;
	this.gicons[cat] = icon;
}

XMap.prototype.iterateMarkers = function(func) {
	for (var key in this.markerMap)
		func(this.markerMap[key]);
}


XMap.prototype.initSegSelect = function (puid) {
	// finding segs including the point
	var segs = {};
	
	var routes = this.data.routes;
	for (var i = 0; i < routes.length; i++) {
		var route = routes[i];
		if (! route.segs)
			continue;
		for (var j = 0; j < route.segs.length; j++) {
			var seg = route.segs[j];
			if (! seg.edges)
				continue;
			for (var k = 0; k < seg.edges.length; k++) {
				var edge = seg.edges[k];
				if (edge.p1 == puid || edge.p2 == puid)
					segs[seg.uid] = true;
			}
		}
	}
	
	this.limitSelectionToSegs(segs, function(suid){
		try {
		 	document.getElementById('marker_frame').contentWindow.segSelected(suid);
		} catch (e){}
	});
}

XMap.prototype.limitSelectionToSegs = function(segs, func) {
	this.limitedSegs = segs;
	this.limitedSegSelectFunc = func;

	this.rm.onObjectOver = function(uid) {
		return this.limitedSegs[uid] ? true : false;
	}.bind(this);
	this.rm.onObjectOut = function(uid) {
		return this.limitedSegs[uid] ? true : false;
	}.bind(this);
	this.rm.onObjectSelect = function(uid){
		if (this.limitedSegs[uid]) {
			this.limitedSegSelectFunc(uid);
			return true;
		} else {
			return false;
		}
	}.bind(this);
}
XMap.prototype.cancelSelectionLimit = function() {
	this.limitedSegs = null;
	this.limitedSegSelectFunc = null;
	this.rm.onObjectOver = function(uid) {
		return true;
	}.bind(this);
	this.rm.onObjectOut = function(uid) {
		return true;
	}.bind(this);
	this.rm.onObjectSelect = function(uid){
		this.openInfoWindow(uid);
		return true;
	}.bind(this);
}

XMap.prototype.markerMoved = function(m) {
	var coord = m.gmarker.getLatLng();
	m.lat = coord.lat();
	m.lng = coord.lng();

	editor.moveMarker(m.uid, m.lng, m.lat);
	xmap.refresh(REASON_DATA);
}

/* ********* moved from rg_googlemaps ************ */
function getAbsElementPosition(el) {
	var x = 0;
	var y = 0;
	while (el)
	{
		x += el.offsetLeft;
		y += el.offsetTop;
		el = el.offsetParent;
	}
	return [x, y];
}

function loadProgressStart() {
	var splash = document.getElementById("load_splash");
	if (! splash)
		return;
	var div = document.getElementById(mapConf.mapDiv);
	
	var mapPos = getAbsElementPosition(div);
	var mapW = parseInt(div.style.width);
	var mapH = parseInt(div.style.height);
	
	var splashW = parseInt(splash.style.width);
	var splashH = parseInt(splash.style.height);
	var splashX = mapPos[0] + (mapW - splashW) / 2;
	var splashY = mapPos[1] + (mapH - splashH) / 2;
	
	splash.style.left = splashX;
	splash.style.top = splashY;
	splash.style.display = "block";
}

var loadProgressTimer;

function loadProgressFinish() {
    loadProgressTimer = setTimeout("loadProgressFinishReal()", 500);
}
function loadProgressFinishReal()
{
    clearTimeout(loadProgressTimer);
    loadProgressTimer = null;
    var splash = document.getElementById("load_splash");
    if (! splash)
        return;
    splash.style.display = "none";
}

// ------------- movable marker stuff -----------------

function addMovableMarker(lat, lng, uid) {
	if (uid) {
		window.editMarkerUid = uid;
		if (xmap.markerMap[uid]) {
			xmap.markerMap[uid].deleted = true;
			xmap.refresh(REASON_MARKER);
		}
	}
	map.closeInfoWindow();
	if (window.movableMarker)
		return;

	var point;
	if (lng && lat)
		point = new GLatLng(lat, lng);
	else
		point = map.getCenter();

	var marker = new GMarker(point, {draggable: true});
	
	GEvent.addListener(marker, "dragstart", function() {
		map.closeInfoWindow();
	});
	
	map.addOverlay(marker);
	window.movableMarker = marker;
}
    
function removeMovableMarker(markerSaved) {
	if (! markerSaved && window.editMarkerUid) { // show marker again
		var m = xmap.markerMap[window.editMarkerUid];
		if (m) {
		 	delete(m.deleted);
			xmap.refresh(REASON_MARKER);
		}
	}
	window.editMarkerUid = null;
	if (window.movableMarker) {
		map.removeOverlay(window.movableMarker); 
		window.movableMarker = null;
	}
}

