<!—-
 *
 * Styles used in cluster marker
 *
—->
<style>

/* style for small view*/

.smallThumb
{
    width:89px;
    height:76px;
	padding-top: 8px;
    padding-left: 6px;
    background-repeat: no-repeat;
    position:relative;
	z-index: -1;
}

.normalThumbDiv
{
	position:relative;
	width:73px;
	height:49px;
	overflow:hidden;
}

.normalImageDiv
{
	position:absolute;
    left: -100%;
    right: -100%;
    top: -100%;
    bottom: -100%;
    margin: auto; 
    min-height: 100%;
    min-width: 100%;

}
.smallThumbNormal
{
   background-image: url("http://markers-storage/Cluster_Pin_Normal.png");
    
}

.smallThumbSelected
{
	background-image: url("http://markers-storage/Cluster_Pin_Selected.png");

}


.smallTextSums
{
   width:30px;
   height:20px;
   position:absolute;
   right:15px;
   top:5px;
   color:white;
   text-align: center;
   vertical-align: middle;
   line-height: 20px;
   z-index: -1;
}

.smallTextSumsNormal
{
   background-color: #333333;
}

.smallTextSumsSelected
{
	background-color: #3DAFDC;
}


/*  style for hovered view*/

/* main div*/

.hovered
{
   	z-index: 2;

}


/* location name div*/

.addLocationFieldHover
{
height:36px;
/*make sure to update the variable widthOfLocationText if changing this width*/
width:190px;
position:relative;
top:10px;
left:10px;
}

.addLocationTextHover
{


  display: block;
  max-width: 100%;
  height: 32px;
 /* margin: 0 auto;*/
  font-size: 13px;
  overflow: hidden;
  fontFamily: "Tahoma, Geneva, sans-serif";
  position:relative;
  top:-32px;
  left:0px;
}


.getLocationNameIconHover
{
}
/* edit field */

.editFieldHover:hover
{
background-image: url("http://markers-storage/Edit_button.png");
}

.editFieldHover
{
height:25px;
width:70px;
position:relative;
left:13px;
top:116px;
}


.editPencilHover
{	
position:relative;
top:4px;
left:8px;

}

.editTextHover
{
color:#222222;
font-size:13px;
//font-weight:600;
position:relative;
left:30px;
top:-15px;
/*update the value of editWidth in markerClusterer.js if changing the width*/
width:50px;
}



/* thumbnail shown in hovered view*/
.thumbnailHoverDiv
{
	height:100px;
	width:180px;
	overflow: hidden;
	border-style: solid;
	border-width: 1px;
	border-color: black;
}


.thumbnailHoverDivGrid
{
	position:relative;
	top:  -15px;
	left:14px;

}

.thumbnailHoverDivDialog
{
	position:relative;
	top:  15px;
	left:14px;

}

.thumbnailHover
{
   position:absolute;
    left: -100%;
    right: -100%;
    top: -100%;
    bottom: -100%;
    margin: auto; 
    min-height: 100%;
    min-width: 100%;
    pointer-events: none;     //to make this transparent for mouse pointer events

}




/* navigation icons*/

.navigateLeftHover
{
position:relative;
left:8px;

}

.navigateRightHover
{
position:relative;
left:153px;
}


.navigateHoverGrid
{
top: -70px;
}
.navigateHoverDialog
{
top: -50px;
}





/* delete marker icon*/

.trashFieldHover
{
	position:relative;
	left : 88px;
	top  : -18px;
	width : 50px;
	height : 20px;
	visibility:hidden;
}

.trashIconHover:hover
{
	background-image: url("http://markers-storage/TrashIconHover.png");
}	

.trashIconHover
{
	
	background-image: url("http://markers-storage/TrashIconNormal.png");
	
}

/* see all icons*/


.seeAllFieldHover:hover
{
background-image: url("http://markers-storage/Edit_button.png");

}
.seeAllFieldHover
{
height:25px;
width:70px;
position:relative;
left:126px;
top:-57px;
}


.seeAllTextHover
{
color:#222222;
font-size:13px;
//font-weight:600;
position:relative;
left:-25px;
top:5px;
text-align: right;

}

.seeAllIconHover
{
position:relative;
left:52px;
top:-9px;

}


/* background image for hover in grid*/
.backgroundHoverGrid
{
	height:200px;
    width:210px;
	background-image: url("http://markers-storage/Hover_Pin_Grid.png");
	z-index: 2;
	margin-top: -130px;
	margin-left: -60px;
}


/*background image for hover in dialog*/
.backgroundHoverDiaog
{
	height:180px;
    width:210px;
	background-image: url("http://markers-storage/Hover_Pin_Dialog.png");
	z-index: 2;
	margin-top: -100px;
	margin-left: -58px;
}

/*  show hide for dialog handling */

.showForGridView
{

}

.hideForDialogView
{
  display:none;
}


</style>


<!—-
 * Main script
 *
—->
<script type="text/javascript">
	if ( window && window.nativeWindow && window.nativeWindow.stage ) {
		window.nativeWindow.stage.frameRate = 60;
		//alert( "set!" );
	}
	
	var map = null;
	var overlay = null;
	var searchCalloutOverlay = null;
	var markerClusterer = null;
	var clickedCluster = null;
	var mapClickActive = true;
	var dragDropTargetCluster = null;
	var bouncingMarker = null;
	var searchMarker = null;
	var currentMarkersMap = new Object();
	var markersMap = new Object();
	var previousAvailableSet = new Object();
	var previousSelectedSet = new Object();
	var addedMarkers = [];
	var deletedMarkers = [];
	var selectedMarkers = [];
	var searchMarkerImage;
	var viewTxt = "View: ";
	var lightMapTxt = "Light";
	var darkMapTxt = "Dark";
	var addLocationText = "Add a Location";
	var editText = "Edit";
	var seeAllText = "See all";
	var editLocationToolTip = "Edit location information for selected media";
	var clickedPin = null;
	var waitingTimeOut = null;				//To prevent panning of map due to media selection while dragging a single media from filmstrip to map
	var searchCallout = null;
	var draggedPin = null;
	var disableDragging = false;
	var timerActive = false;
	var baseUrl = "http://markers-storage/";
	var currCatalogVersion = 1;
	var smallIconString = "small/";
    var baseThumbUrl = "http://markers-storage/thumb/";
	var noImageAvailableHoverUrl = baseUrl + "generic_thumb_hover.png";
	var noImageAvailableNormalUrl = baseUrl + "generic_thumb_normal.png";
	
	
	

	
	
	var defaultMapStyle = "hybrid";
	var defaultLat  = 37.09024;					//US
	var defaultLng = -95.712891 ;
	var defaultZoom = 4;

	var lastDragTime = 0;
	var dragTimeout = 300;

	
	var geocoder;
	
	Object.size = function(obj) {
		var size = 0, key;
		for (key in obj) {
			if (obj.hasOwnProperty(key)) size++;
		}
		return size;
	};
	
	var callCallback = function() {
		var funcName = arguments[0];
		var javascript = "";
		var j = arguments.length;
		var c = j - 1;
		for( var i = 1; i < j; i++ ) {
			var arg = arguments[ i ];
			if( typeof( arg ) == 'string' ) {
				arg = arg.replace( /"/g, '\\"' );
				javascript = javascript + '"' + arg + '"';
			}
			else if( typeof( arg ) == 'number' ) {
				javascript = javascript + arg;
			}
			else if( typeof( arg ) == 'boolean' ) {
				javascript = javascript + arg;
			}
			else if( arg == null || typeof( arg ) == 'undefined' ) {
				javascript = javascript + 'undefined';
			}
			else {
				javascript = javascript + 'undefined';
			}
			if( i < c ) {
				javascript = javascript + ", ";
			}
		}
		
		apeeval( funcName, javascript );
	};
	
	
	function viewLabel(controlDiv, txt) {

	  controlDiv.style.padding = '5px';

	  var textLabel = document.createElement('div');
	  textLabel.style.fontFamily = '"myriad pro",Arial,sans-serif';
	  textLabel.style.fontSize = '14px';
	  textLabel.style.paddingLeft = '2px';
	  textLabel.style.paddingTop = '2px';
	  textLabel.innerHTML = txt;
	  controlDiv.appendChild(textLabel);

	}

	
	
	var MAX_LATITUDE = 85.5;
    var kMapTypeIds;
	
	function initialize() {
		if ( google.maps.MaxZoomService )
			maxZoomService = new google.maps.MaxZoomService();

		geocoder = new google.maps.Geocoder();
		
		var latlng = new google.maps.LatLng( defaultLat, defaultLng );

		kMapTypeIds = [
			google.maps.MapTypeId.ROADMAP, 
			google.maps.MapTypeId.HYBRID, 
			google.maps.MapTypeId.TERRAIN, 
			"lrLight",
			"lrDark"
		];
		
		var mapOptions = {
			zoom: defaultZoom,
            center: latlng,
            mapTypeId: defaultMapStyle,
        	backgroundColor: '#707070',
			zoomControl: true,
			zoomControlOptions: {
				style: google.maps.ZoomControlStyle.LARGE
			},
			panControl: true,
			scaleControl: true,		
			navigationControl: true,
			overviewMapControl: true,
			streetViewControl: false,
			mapTypeControl: true,
			tilt: 0,
			minZoom: 3,
			mapTypeControlOptions: {
				mapTypeIds: kMapTypeIds,
				style: google.maps.MapTypeControlStyle.DROPDOWN_MENU
			}
		};
		
		map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
		callCallback("getLocalizedMapStrings");	  
			
		searchMarkerImage = new google.maps.MarkerImage( baseUrl + "O_Search_Pin.png",
			new google.maps.Size( 50, 30 ),
			new google.maps.Point( 0, 0 ),
			new google.maps.Point( 25, 29 ) );
			
		
	
		var textAnchorX = 5;				//top padding
		var textAnchorY = 0;               //left padding (0 => align center)
		var groupOffsetY = 0;

		var hoverIconString = {
		
			addLocationFieldText : addLocationText,
			editFieldText : editText,
			seeAllFieldText : seeAllText
		
		};
		
		
		var clusterOptions = {
			gridSize: 89,
			maxZoom: 21,
			zoomOnClick: false,
			hoverIconStrings : hoverIconString,
			styles: [{
					height: 70,
					url: baseUrl + "O_Cluster_Pin.png",
					url_selected: baseUrl + "O_Cluster_Pin_S.png",
					width: 100,
					opt_anchor: [textAnchorX + 3, textAnchorY],
                    opt_offset_y: groupOffsetY,
					opt_textColor: 'white'
					},
					{
					height: 70,
					url: baseUrl + "O_Red_Pin.png",
					url_normal: baseUrl + "O_Red_Pin.png",
					url_selected: baseUrl + "O_Blue_Pin.png",
					url_over: baseUrl + "O_Red_Pin_Drop.png",
					width: 100,
					opt_offset_y: groupOffsetY,
					opt_anchor: [textAnchorX, textAnchorY],
					opt_textColor: 'white'
					}]
			
		};
		
		markerClusterer = new MarkerClusterer( map, clusterOptions );
		google.maps.event.addListener( markerClusterer, 'clusterChanged',function() {

			callCallback("clusterRecreated");
		});
			
		
		google.maps.event.addListener( markerClusterer, 'clusterclick', function( clusters ) {
			//alert('clusterClicked');
			mapClickActive = false;
			if ( clusters == null || clusters.length == 0 )
				return;
			
			var cluster = clusters[ 0 ];
			var markers = cluster.markers_;
						
			clickedCluster = cluster;
			var count = getClickedClusterCount();
			var center = cluster.getCenter();
			clickedPin = cluster;
											
			if ( count && count > 0 ) {
				selectedMarkers = [];
				for ( var i = 0, marker; marker = markers[ i ]; i++ ) {			
					if ( marker.id ) {
						//marker.selected = true;
						var markerInfo = new Object();	
						markerInfo.id = marker.id;
						markerInfo.lat = marker.getPosition().lat();
						markerInfo.lng = marker.getPosition().lng();
						selectedMarkers.push(markerInfo);
					}
				}
				// all the details are in selected markers array
				
				updateMarkers();
			
				var mediaIdList = createMediaList(selectedMarkers);	

				//here we will pass the tagId of leaf node to ensure custom tag feature working 
				// if no leaf node (states separated) then 0
				var tagId = 0;
				if(cluster.hasCommonTags())
				{
					tagId = cluster.getFirstTagId();
				}
				
				var firstTagAndMediaIdList = String(tagId) + "," + mediaIdList ;
				
	//			alert(mediaIdList);
				//no call back is required as of now
				callCallback( "onClusterMarkersClick", firstTagAndMediaIdList );
			}								

	
		} );
		

		google.maps.event.addListener( markerClusterer, 'clusterdoubleclick', function( clusters ) {
			mapClickActive = true;							//in click event mapclickactive get false.
			var selectedCluster = clusters[0];
			if(!clusters[0]) return;
			
 			showSelectedClusterMedia(selectedCluster);							//media gets selected in click event					
			callCallback( "onClusterDoubleClick" );
		} );

		google.maps.event.addListener( markerClusterer, 'clusterrightclick', function( clusters ) {
			var cluster = clusters[ 0 ];
			var markers = cluster.markers_;
			clickedCluster = cluster;
			var mediaIdList = createMediaList(markers);

			var tagId = 0;
			if(cluster.hasCommonTags())
			{
				tagId = cluster.getFirstTagId();
			}
			
			var firstTagAndMediaIdList = String(tagId) + "," + mediaIdList ;
				
			callCallback( "onClusterRightClick", firstTagAndMediaIdList );
				
		} );
	
		google.maps.event.addListener( markerClusterer, 'clustermousedown', function( event, clusters ) {
			if(event.button == 2) return;							//2 denotes right mouse button, 1- left, 3- middle
		} );
		
		google.maps.event.addListener( markerClusterer, 'clustermousemove', function( event, clusters ) {
			
		} );
		
		google.maps.event.addListener( markerClusterer, 'clustermouseup', function( clusters ) {
			
		} );
		
		google.maps.event.addListener( markerClusterer, 'clusterdragmove', function( draggedCluster ) {
			if(draggedCluster)
			{	
				if(draggedPin && draggedPin !== draggedCluster)
				{
					pinMoveCancelled(draggedPin);
				}
				draggedPin = draggedCluster;
				
				//alert("mainScript: drag move ");
				clearSearchCallout();
				//markerClusterer.clusterMoved(draggedCluster, event.latLng);
				var pos = draggedCluster.getCenter();
				dragDropTargetCluster = markerClusterer.canAcceptMarkerDropImp( pos, false, dragDropTargetCluster );
			}
			
		} );
		
		google.maps.event.addListener( markerClusterer, 'clusterdragend', function( draggedCluster ) {

			//alert("mainScript: drag end " + draggedCluster);
			if(draggedPin && draggedPin !== draggedCluster)
			{
				pinMoveCancelled(draggedPin);
			}
			
			clearSearchMarker();
			draggedPin = draggedCluster;
			var pos = draggedCluster.getCenter();
			var existingImageId = 0;

			//dragDropTargetCluster = markerClusterer.canAcceptMarkerDropImp( pos, false, dragDropTargetCluster );
			//alert("clusterDragEnd: " + dragDropTargetCluster.getCenter().lat() + "," + dragDropTargetCluster.getCenter().lng());
			if(dragDropTargetCluster)
			{	
				existingImageId = dragDropTargetCluster.markers_[0].id;
				pos = dragDropTargetCluster.getCenter();
				markerClusterer.clusterMoved(draggedCluster, pos);
			}
			
			var clusterMarkers = draggedCluster.markers_;
			var mediaListStr = createMediaList(clusterMarkers);
			callCallback("onClusterDragEnd", pos.lat(), pos.lng(), existingImageId, mediaListStr);
		} );
		
		
			
		google.maps.event.addListener( markerClusterer, 'trashIconClicked', function(clusters) {
		
			mapClickActive = false;
		
			if ( clusters == null || clusters.length == 0 )
				return;
		
			var cluster = clusters[ 0 ];
			var markers = cluster.markers_;
			
			var mediaIdList = createMediaList(markers);	
			callCallback("onTrashIconClick",mediaIdList);	
		
		
		}
		);
		google.maps.event.addListener( markerClusterer, 'seeAllClicked', function(clusters) {
			
			mapClickActive = false;
			if ( clusters == null || clusters.length == 0 )
				return;
			var cluster = clusters[ 0 ];
			showSelectedClusterMedia(cluster);
		
		
		
		}
		);
		google.maps.event.addListener( markerClusterer, 'editClusterClicked', function(clusters) {
			
			mapClickActive = false;
			
			if ( clusters == null || clusters.length == 0 )
				return;
		
			var cluster = clusters[ 0 ];
			var markers = cluster.markers_;
			
				var mediaIdList = createMediaList(markers);	
				callCallback("onEditClusterClicked",mediaIdList);
		
		
		}
		);
	
		google.maps.event.addListener( markerClusterer, 'requestReverseGeocodeLocation', function(clusters) {
		
			if ( clusters == null || clusters.length == 0 )
				return;
				
			var cluster = clusters[ 0 ];
			var markers = cluster.markers_;
			
			var mediaIdList = createMediaList(markers);	
			var center = cluster.getCenter();
			var arg = center.lat() + "," + center.lng() + "," + mediaIdList ;
			//alert("requesting reverse");
			callCallback("requestReverseGeocodeLocation",arg);
		}
		);

		google.maps.event.addListener( markerClusterer, 'getLocationNameForClusterViaMediaList', function(clusters) {
		
			if ( clusters == null || clusters.length == 0 )
				return;
			var cluster = clusters[ 0 ];
			var markers = cluster.markers_;
			
			var mediaIdList = createMediaList(markers);	
			var bound = cluster.getCenter();
			var arg = bound.lat() + "," + bound.lng() + "," + mediaIdList ;
			callCallback("getLocationNameForClusterViaMediaList",arg);
		}
		);
		
		overlay = new google.maps.OverlayView();
		overlay.draw = function() {};
		overlay.setMap( map );
			
		var linkExternalUrl = function(url) {
									function listener() { callCallback("onLoadMapExternalURL", url); }
									return listener;
								};
				
		google.maps.event.addListenerOnce(map, 'idle', setTimeout(function() {
			callCallback("OnMapLoaded");
			var mapExternalLinks = document.links;
			for (i = 0; i < mapExternalLinks.length; ++i)
			{
				var link = mapExternalLinks.item(i);
				var linkHref = link.href;
				var listener = linkExternalUrl(linkHref);
				link.addEventListener('click', listener);
			}
		}, 1000));
			
		google.maps.event.addListener( map, 'click', function( event ) {
			var now = new Date().getTime();
			if(!mapClickActive) {														//click on cluster also results in map click 
				mapClickActive = true;
				return;
			}
			//this condition not needed as of now since cluster dragged functionality has been rewritten . Modify it as per need.	
			//if ( now - lastDragTime > dragTimeout ) {
			
			selectedMarkers = [];
			updateMarkers();
			callCallback( "onMapClick", event.latLng.lat(), event.latLng.lng() );

		} );
		
		
		google.maps.event.addListener( map, 'mousedown', function( event ) {
			callCallback( "onMapMouseDown", event.latLng.lat(), event.latLng.lng() );
		} );

		google.maps.event.addListener( map, 'mousemove', function( event ) {
			callCallback( "onMapMouseMove", event.latLng.lat(), event.latLng.lng() );
		} );

		google.maps.event.addListener( map, 'mouseup', function( event ) {
			callCallback( "onMapMouseUp", event.latLng.lat(), event.latLng.lng());
		} );

		google.maps.event.addListener( map, 'mouseout', function( event ) {
			if(draggedPin && draggedPin.isClusterDragged())
			{
				pinMoveCancelled(draggedPin);
			}
			callCallback( "onMapMouseOut", event.latLng.lat(), event.latLng.lng() );
		} );

		google.maps.event.addListener( map, 'rightclick', function( event ) {
			callCallback( "onMapRightClick", event.latLng.lat(), event.latLng.lng() );
		} );

		google.maps.event.addListener( map, 'dblclick', function( event ) {
			callCallback( "onMapDoubleClick", event.latLng.lat(), event.latLng.lng() );
		} );
		
		google.maps.event.addListener( map, 'zoom_changed', function() {
			if(draggedPin) {
				draggedPin = null;
				clearSearchCallout();
			}
			/*if(draggedPin && isClusterPin(draggedPin)) {
				clearSearchCallout();
				draggedCluster = null;
				draggedPin = null;
				clusterDragState = dragStates.NODRAG;	
			}	*/										//new clusters might be formed.

			// we are not retaining selection in zoom in/out cases 
			//in order to have single cluster selection for honoring custom tag
			selectedMarkers = [];
			updateMarkers();

			callCallback( "onZoomChanged", map.getZoom() );
		} );

		google.maps.event.addListener( map, 'center_changed', function() {
			var center = map.getCenter();
			callCallback( "onCenterChanged", center.lat(), center.lng() );
		} );

		google.maps.event.addListener( map, 'bounds_changed', function() {
			var bounds = map.getBounds();
			var ne = bounds.getNorthEast();
			var sw = bounds.getSouthWest();
			callCallback( "onBoundsChanged", ne.lat(), ne.lng(), sw.lat(), sw.lng() );
		} );
		
		google.maps.event.addListener( map, 'maptypeid_changed', function() {
			var mapTypeId = map.getMapTypeId();
			callCallback( "onMapTypeChanged", mapTypeId );
		} );
		
		var lightStyle = [
			{ featureType: "all", elementType: "geometry", stylers: [ { visibility: "simplified" }, { saturation: -90 }, { hue: "#ffe500" }, { lightness: 20 }, { gamma: 0.7 } ] },
			{ featureType: "water", elementType: "geometry", stylers: [ { lightness: -10 }, { saturation: -30 }, { hue: "#ffd500" }, { gamma: 0.34 } ] },
			{ featureType: "all", elementType: "labels", stylers: [ { visibility: "on" }, { lightness: 23 }, { gamma: 0.87 }, { saturation: -83 } ] },
			{ featureType: "road.local", elementType: "labels", stylers: [ { lightness: 0 } ] },
			{ featureType: "road.arterial", elementType: "labels", stylers: [ { gamma: 1.63 }, { hue: "#ffbb00" }, { saturation: -93 }, { lightness: 0 } ] },
			{ featureType: "road.highway", elementType: "labels", stylers: [ { lightness: 20 }, { saturation: -13 }, { gamma: 0.84 }, { visibility: "on" } ] }
		];

		var darkStyle = [ 
			{ featureType: "landscape", elementType: "geometry", stylers: [ { saturation: -100 }, { lightness: -53 } ] },
			{ featureType: "road", elementType: "geometry", stylers: [ { saturation: -83 }, { lightness: -44 } ] },
			{ featureType: "poi", elementType: "geometry", stylers: [ { saturation: -96 }, { lightness: -50 } ] },
			{ featureType: "road.arterial", elementType: "labels", stylers: [ { lightness: -50 }, { saturation: -80 } ] },
			{ featureType: "road.local", elementType: "labels", stylers: [ { saturation: -80 }, { lightness: -50 } ] },
			{ featureType: "road.highway", elementType: "labels", stylers: [ { lightness: -54 } ] },
			{ featureType: "water", elementType: "all", stylers: [ { saturation: -39 }, { lightness: -62 } ] },
			{ featureType: "poi", elementType: "labels", stylers: [ { lightness: -30 } ] },
			{ featureType: "transit", elementType: "labels", stylers: [ { lightness: -7 }, { saturation: -66 } ] },
			{ featureType: "administrative", elementType: "geometry", stylers: [ { saturation: -79 }, { lightness: -56 } ] },
			{ featureType: "administrative.locality", elementType: "all", stylers: [ { gamma: 1.47 }, { lightness: -56 } ] },
			{ featureType: "administrative.province", elementType: "all", stylers: [ { lightness: -27 } ] },
			{ featureType: "administrative.neighborhood", elementType: "all", stylers: [ { lightness: -67 }, { gamma: 1.26 } ] } 
		];
		
		var lightMapType = new google.maps.StyledMapType( lightStyle, {name: lightMapTxt});
		var darkMapType = new google.maps.StyledMapType( darkStyle, {name: darkMapTxt} );

		map.mapTypes.set( "lrLight", lightMapType );
		map.mapTypes.set( "lrDark", darkMapType );
		
			//--------------------search callout code-------------------------------------------------------------
		searchCalloutOverlay = function(latLngPos, map, txt, anchorElementHeight) {  
			// Now initialize all properties.  
			//alert("initialize searchcalloutoverlay");
			this.pos_ = latLngPos;  
			this.map_ = map;  
			this.div_= null;  
			this.text_ = txt;
			this.bDivDrawn_ = false;
			this.offsetX_ = 0;        //offset from center point. Set when div is first drawn . 
			this.offsetY_ = anchorElementHeight - 7;     //7 is random .    
			// Explicitly call setMap() on this overlay  
			this.setMap(map);           
		} ;
		searchCalloutOverlay.prototype = new google.maps.OverlayView();
		
		//get gps location which is referred by this callout
		searchCalloutOverlay.prototype.getGeoLocation = function() { 
			return this.pos_;
		};
		
		searchCalloutOverlay.prototype.onAdd = function() {  
			// Create the DIV and set some basic attributes.  
			//alert("onAdd");
			var div = document.createElement('DIV');  
			div.style.borderStyle = "none";  
			div.style.borderWidth = "0px";  
			div.style.position = "relative"; 
			
			var textDiv = document.createElement('DIV'); 
			textDiv.id = "s_text"; 
			textDiv.style.borderStyle = "none";  
			textDiv.style.borderWidth = "0px"; 
			textDiv.style.position = "absolute"; 
			textDiv.style.color = "black";
			textDiv.style.fontSize = "13px";
			textDiv.style.fontFamily = "'Myriad Web Pro', 'Myriad Pro', sans-serif";			//TODO: need to localize it for japane
			textDiv.style.verticalAlign = "center";
			
			var preTag = document.createElement('PRE');
			preTag.style.display = "inline";
			preTag.style.fontFamily = "inherit";
			
			var text = document.createTextNode(this.text_);
			preTag.appendChild(text);
			textDiv.appendChild(preTag);
			
			var leftDiv = document.createElement('DIV');  
			leftDiv.id = "s_leftdiv";
			leftDiv.style.borderStyle = "none";  
			leftDiv.style.borderWidth = "0px";  
			leftDiv.style.position = "absolute"; 
		  
			leftDiv.style.backgroundImage = "url(" + baseUrl + "CallOut_Left.png)"; 
			leftDiv.style.width = "8px";													//width of image
			leftDiv.style.height = "35px";													//height of image
					 
			var centerDiv = document.createElement('DIV');  
			centerDiv.id = "s_centerdiv";
			centerDiv.style.borderStyle = "none";  
			centerDiv.style.borderWidth = "0px";  
			centerDiv.style.position = "absolute"; 
		  
			centerDiv.style.backgroundImage = "url(" + baseUrl + "CallOut_Center.png)"; 
			centerDiv.style.backgroundRepeat = "repeat-x";
			centerDiv.style.height = "35px"; 
			
			
			var rightDiv = document.createElement('DIV');  
			rightDiv.id = "s_rightdiv";
			rightDiv.style.borderStyle = "none";  
			rightDiv.style.borderWidth = "0px";  
			rightDiv.style.position = "absolute"; 
		  
			rightDiv.style.backgroundImage = "url(" + baseUrl + "CallOut_Right.png)"; 
			rightDiv.style.width = "8px";  
			rightDiv.style.height = "35px"; 
			
			
			var buttonDiv = document.createElement('DIV'); 
			buttonDiv.id = "s_button"; 
			buttonDiv.style.borderStyle = "none";  
			buttonDiv.style.borderWidth = "0px";  
			buttonDiv.style.position = "absolute";
			buttonDiv.style.verticalAlign = "center";
			buttonDiv.style.display = "inline-block";
			
			
			var acceptButton = document.createElement("input");
			acceptButton.type = "image";
			acceptButton.id = "acceptButton"
			acceptButton.src = baseUrl + "E_TeaserBody.png";
			acceptButton.style.width = "19px";
			acceptButton.style.height = "18px";
			acceptButton.style.position = "absolute";
			
			
			var rejectButton = document.createElement("input");
			rejectButton.type = "image";
			rejectButton.id = "rejectButton";
			rejectButton.src = baseUrl + "E_RemoveIcon.png";
			rejectButton.style.width = "18px";
			rejectButton.style.height = "18px";
			rejectButton.style.position = "absolute";
			
			buttonDiv.appendChild(acceptButton);
			buttonDiv.appendChild(rejectButton);
			
			
			div.appendChild(leftDiv);
			div.appendChild(centerDiv);
			div.appendChild(rightDiv);
			div.appendChild(buttonDiv);
			div.appendChild(textDiv);
			
			var that = this;
			google.maps.event.addDomListener(acceptButton, "click", function(evt) {
								evt.stopPropagation();
								if(!draggedPin)
								{
									//alert("will assign: " + that.pos_);
									assignSearchLocation(that.pos_);
								}
								else
								{
									movePin(draggedPin);
									clearSearchMarker();
								}
							});
			google.maps.event.addDomListener(rejectButton, "click", function(evt) {
								evt.stopPropagation();
								clearSearchMarker();
								if(draggedPin)
								{
									pinMoveCancelled(draggedPin);
								}
							});
			
		  
			// Set the overlay's div_ property to this DIV  
			this.div_ = div;  
		  
			// We add an overlay to a map via one of the map's panes.  
			// We'll add this overlay to the overlayImage pane.  
			var panes = this.getPanes();  
			panes.overlayImage.appendChild(div);  
		}  
	  
			//drawing overlay on map  
		searchCalloutOverlay.prototype.draw = function() { 
			var overlayProjection = this.getProjection();  
			var centerX = (overlayProjection.fromLatLngToDivPixel(this.pos_)).x;  
			var centerY = (overlayProjection.fromLatLngToDivPixel(this.pos_)).y;  
			//alert("draw");
			var div = this.div_;  
			if(this.bDivDrawn_) {
       			//just reposition the parent div according to new overlayprojection
				var originX = centerX - this.offsetX_;
				var originY = centerY - this.offsetY_;
				div.style.left = originX + 'px';
				div.style.top = originY + 'px';
				
				return;
			} 
			
			//drawing for first time
			
			var textDiv = document.getElementById("s_text");
			var leftDiv = document.getElementById("s_leftdiv");
			var centerDiv = document.getElementById("s_centerdiv");
			var rightDiv = document.getElementById("s_rightdiv");
			var buttonDiv = document.getElementById("s_button");
			var acceptBtn = document.getElementById("acceptButton");
			var rejectBtn = document.getElementById("rejectButton");
			
			var textDivWidth = textDiv.clientWidth;
			var leftDivWidth = leftDiv.clientWidth;
			var buttonDivWidth = acceptBtn.clientWidth + rejectBtn.clientWidth;
			var rightDivWidth = rightDiv.clientWidth;
			
			var centerDivWidth = textDivWidth + 8 + buttonDivWidth + 3;               //8 space b/w text and button, 3 - space b/w both buttons
			
			this.offsetX_ += leftDivWidth +(centerDivWidth/2) - 1;  				// 1 for center alignment
			this.offsetY_ += 35;											// 35 - height of callout
			
			var originX = centerX - this.offsetX_;				
			var originY = centerY - this.offsetY_;										
			
			div.style.left = originX + 'px';
			div.style.top = originY + 'px';
			
			leftDiv.style.left = '0px';
			leftDiv.style.top = '0px';
			
			rightDiv.style.left = leftDivWidth + centerDivWidth + 'px';		
			rightDiv.style.top = '0px';
			
			centerDiv.style.width = centerDivWidth + "px";
			centerDiv.style.left = leftDivWidth + 'px';
			centerDiv.style.top = '0px';
			
			textDiv.style.left = leftDivWidth + 'px';
			textDiv.style.top =  10 + 'px';
					
			acceptBtn.style.left = (leftDivWidth + textDivWidth + 8) + 'px';
			acceptBtn.style.top =  10 + 'px';		
			
			rejectBtn.style.left = (leftDivWidth + textDivWidth + 8 + acceptBtn.clientWidth + 3) + 'px';
			rejectBtn.style.top = 10 + 'px';		

			this.bDivDrawn_ = true;
		}  
		
		searchCalloutOverlay.prototype.onRemove = function() {
			this.div_.parentNode.removeChild(this.div_);
			this.div_ = null;
		}
		
	}
	
	var setLocalizedStrings = function(str) {
		var strList = str.split(",");
				
		if(strList.length == 8) {
		
			calloutText = strList[0];
			viewTxt = strList[1];
			lightMapTxt = strList[2];
			darkMapTxt = strList[3];
			addLocationText = strList[4];
			editText  = strList[5];
			seeAllText = strList[6];
			editLocationToolTip = strList[7];
		}
		
		//to show 'View:' before maptype options
		var viewDiv = document.createElement('div');
		new viewLabel(viewDiv, viewTxt);
		viewDiv.index = 1;
		map.controls[google.maps.ControlPosition.TOP_RIGHT].push(viewDiv);
		
	}
	
	var createMediaList = function (markers){
		
		if(markers.length)
		{
			var mediaIdList = "" + String(markers[0].id);
			for(var i=1; i < markers.length; i++)
			{
			
				mediaIdList = mediaIdList + "," + String(markers[i].id);
			}	
			return mediaIdList;
		}
	}
		
		
	var assignSearchLocation = function(position) {
		//alert("in assign");
		if(!position) return;

		var searchMarkerDragged = false;
		if(searchMarker)
			searchMarkerDragged = searchMarker.dragged;
			
		callCallback('onAssignSearchLocation', position.lat(), position.lng(), searchMarkerDragged);
		clearSearchMarker();
	}
	
	var movePin = function(dragPin) {
		//alert("moving pin" + dragPin);
		if(!dragPin) return;
		
		var mediaIdListString = "";
		var pinPos;	
		if(isClusterPin(dragPin))
		{	
			//alert("cluster drag");
			var markers = dragPin.markers_;
			mediaIdListString = createMediaList(markers);
			dragDropTargetCluster = markerClusterer.canAcceptMarkerDropImp( dragPin.getCenter(), false, dragDropTargetCluster );
			//alert("movePin: " + dragDropTargetCluster.getCenter().lat() + "," + dragDropTargetCluster.getCenter().lng());
			if(dragDropTargetCluster)
			{
				pinPos = dragDropTargetCluster.getCenter();
			}
			else
				pinPos = dragPin.getCenter();
		}
		else
		{
			mediaIdListString = "" + String(dragPin.id);
			dragDropTargetCluster = markerClusterer.canAcceptMarkerDropImp( dragPin.getPosition(), false, dragDropTargetCluster );
			//alert("movePin: " + dragDropTargetCluster.getCenter().lat() + "," + dragDropTargetCluster.getCenter().lng());
			if(dragDropTargetCluster)
			{
				pinPos = dragDropTargetCluster.getCenter();
			}
			else
				pinPos = dragPin.getPosition();
		}
		
		callCallback("onPinRelocated", pinPos.lat(), pinPos.lng(), mediaIdListString);
	}
	
	var pinMoveCancelled = function(dragPin) {
		//alert(dragPin);
		if(!dragPin) return;
		
		if(isClusterPin(dragPin))
		{
			//alert("cluster drag cancel");
			var originalPos = currentMarkersMap[dragPin.markers_[0].id].getPosition();
			markerClusterer.clusterMoved(dragPin, originalPos);
		}
		else
		{
			//alert(dragPin.id);
			callCallback("restoreMarkerPosition", dragPin.id);
		}
		draggedPin = null;
		callCallback("onPinMoveCancelled");
	}
	
	var restoreMarkerPosition = function(imageId, lat, lng) {
		if(currentMarkersMap[imageId])
			currentMarkersMap[imageId].setPosition(new google.maps.LatLng(lat, lng));
	}
	
	var setMapStyle = function(style) {
		var mapTypeId;
		switch(style)
		{
		case "roadmap":
			mapTypeId = google.maps.MapTypeId.ROADMAP;
			break;
		case "hybrid":
			mapTypeId = google.maps.MapTypeId.HYBRID;
			break;
		case "lrLight":
			mapTypeId = "lrLight";
			break;
		case "lrDark":
			mapTypeId = "lrDark";
			break;
		default:
			mapTypeId = google.maps.MapTypeId.ROADMAP;
		}	
		map.setMapTypeId(mapTypeId);
	}



	var showHoverTip = function(str)
	{
				callCallback("onShowLocationHoverTip", str);

	}
	
	var hideHoverTip = function()
	{
				var str = "";
				callCallback("onHideLocationHoverTip", str);
	}






	
	var isClusterPin = function(pin) {
		if(pin instanceof google.maps.Marker)
			return false;
		else
			return true;
	}
	
	//masingha: Either this method name seems ambiguous with its implementation. 
	var forceShowMarkersForMedia = function(imageIdList) {
			if(imageIdList.length <= 0 ) return;
		
			var mediaList = imageIdList.split(',');
			var imageId = mediaList[0];
			for ( var i = 0, cluster; i < markerClusterer.getTotalClusters() ; i++ ) {
				cluster = markerClusterer.clusters_[i];
				var imageIdLista;
				for ( var j = 0, marker; marker = cluster.markers_[ j ]; j++ ) {
					if(imageId == marker.id){
						showSelectedClusterMedia(cluster);
						break;
					}
				}
			}
	}	

	
	var showSelectedClusterMedia =  function(selectedCluster){
		var pinBounds = new google.maps.LatLngBounds();
		
		if(selectedCluster)
		{
			if(selectedCluster.isGroupCluster)
				pinBounds.extend(selectedCluster.getCenter());
			else
			{
				var markers = selectedCluster.markers_;
				for(var i = 0; i < markers.length; ++i)
				{
					pinBounds.extend(markers[i].getPosition());
				}
				
			}
		}
	
		if( pinBounds != null ) {
			var ne = pinBounds.getNorthEast();
			var sw = pinBounds.getSouthWest();
			callCallback("onSeeAllMediaClick", ne.lat(), ne.lng(), sw.lat(), sw.lng());
		}
		mapClickActive = false;
	}	
		
		
	//bOnExistingPin: will be used for positioning the callout above element
	var showSearchCallout = function(txt, lat, lng, bOnExistingPin) {
		//alert("search callout to b shon");
		clearSearchCallout();
		var latLng = new google.maps.LatLng(lat, lng);  
		var anchorElementHeight = bOnExistingPin ? 76 : 30;                 //76 - height of smallThumbNormal, 30- height of search pin
		searchCallout = new searchCalloutOverlay(latLng, map, txt, anchorElementHeight);  
	};

	var clearSearchCallout = function() {
		if(searchCallout) {
			searchCallout.setMap(null);
		}
	};		
	
	var updateSearchCalloutText =  function(txt) {
		if(searchCallout)
		calloutText = txt;
		if(searchMarker)
			showSearchCallout(txt, searchCallout.getGeoLocation().lat(), searchCallout.getGeoLocation().lng(), false);
	}
	
	var clearMarkerSelection = function() {
		if(selectedMarkers.length) {
			selectedMarkers = [];
			updateMarkers();
		}
	}
	
	var getClusters = function() {

			var imageIdList = "";
			for ( var i = 0, cluster; i < markerClusterer.getTotalClusters() ; i++ ) {
				cluster = markerClusterer.clusters_[i];
				imageIdList = imageIdList + "new cluster";
				for ( var j = 0, marker; marker = cluster.markers_[ j ]; j++ ) {
					imageIdList = imageIdList + "," + marker.id;
				}
				if( i+1 < markerClusterer.getTotalClusters())
					imageIdList = imageIdList + ",";
			}
			return imageIdList ;
	}	


	var getClustersInView = function() {

			var imageIdList = "";
			var bFirstCluster = true;
			for ( var i = 0, cluster; i < markerClusterer.getTotalClusters() ; i++ ) {
				cluster = markerClusterer.clusters_[i];
				var pos = cluster.getCenter();
				if(map.getBounds().contains(pos))
				{
					if(!bFirstCluster)
						imageIdList = imageIdList + ",";
					else
						bFirstCluster = false;
					imageIdList = imageIdList + "new cluster";
					for ( var j = 0, marker; marker = cluster.markers_[ j ]; j++ ) {
						imageIdList = imageIdList + "," +marker.id;;
					}
				}
				
			}
			return imageIdList ;
	}		

	var getSelectedImageIds = function() {
		if(!selectedMarkers.length || !selectedMarkers[0]) return "";
		
		var imageIdList = "" + selectedMarkers[0].id;
		for(var i = 1; i < selectedMarkers.length; ++i)
		{
			imageIdList = imageIdList + "," + selectedMarkers[i].id;
		}
		return imageIdList;
	}	
	
	var fitMarkersToBounds = function () {
		var bounds = new google.maps.LatLngBounds();
		var boundsChanged = false;
		// Create bounds from markers
		for( var imageId in currentMarkersMap ) {
			if(currentMarkersMap[imageId]) {
				boundsChanged = true;
				var latlng = currentMarkersMap[imageId].getPosition();
				bounds.extend(latlng);
			}
		}
    
		if(!boundsChanged) return;

		// Don't zoom in too far on only one marker
		if (bounds.getNorthEast().equals(bounds.getSouthWest())) {
		   var extendPoint1 = new google.maps.LatLng(bounds.getNorthEast().lat() + 0.01, bounds.getNorthEast().lng() + 0.01);
		   var extendPoint2 = new google.maps.LatLng(bounds.getNorthEast().lat() - 0.01, bounds.getNorthEast().lng() - 0.01);
		   bounds.extend(extendPoint1);
		   bounds.extend(extendPoint2);
		}

		map.fitBounds(bounds);

	};
	
	var showMarkersForMedia = function (mediaListStr) {

		var bounds = new google.maps.LatLngBounds();
		var mediaList = mediaListStr.split(',');
		
		// Create bounds from markers
		for( var i = 0; i < mediaList.length; i++) {
			var imageId = mediaList[i];
			if(currentMarkersMap[imageId]) {
				var latlng = currentMarkersMap[imageId].getPosition();
				bounds.extend(latlng);
			}
		}

		// Don't zoom in too far on only one marker
		if (bounds.getNorthEast().equals(bounds.getSouthWest())) {
		   var extendPoint1 = new google.maps.LatLng(bounds.getNorthEast().lat() + 0.01, bounds.getNorthEast().lng() + 0.01);
		   var extendPoint2 = new google.maps.LatLng(bounds.getNorthEast().lat() - 0.01, bounds.getNorthEast().lng() - 0.01);
		   bounds.extend(extendPoint1);
		   bounds.extend(extendPoint2);
		}

		map.fitBounds(bounds);

	};
	
	var bringMarkerInView = function(mediaId) {
		if(!mediaId) return;
		var marker = currentMarkersMap[mediaId];
		if(marker)
		{
			var pos = marker.getPosition();
			if(!map.getBounds().contains(pos))
				setCenter(pos.lat(), pos.lng());
				
		}
	}
			
	var locationToViewPoint = function( location ) {
		if ( location == null ) return;
		if ( overlay == null ) return;
		var projection = overlay.getProjection();
		if ( projection == null ) return;
		return projection.fromLatLngToContainerPixel( location );
	}
	
	var viewPointToLocation = function( point ) {
		if ( location == null ) return;
		if ( overlay == null ) return;
		var projection = overlay.getProjection();
		if ( projection == null ) return;
		return projection.fromContainerPixelToLatLng( point );
	}
   
    function getZoom() {
		return map.getZoom();
	}
	
	function getBounds() {
		if ( map != null ) {
			var result = map.getBounds();
			if( result != null ) {
				var ne = result.getNorthEast();
				var sw = result.getSouthWest();
				
				return ne.lat() + "," + ne.lng() + "," + sw.lat() + "," + sw.lng();
			}
		}
	}
	
	var getCenter = function() {
		if ( map != null ) {
			var result = map.getCenter();
			if(result != null ) {
				return result.lat() + "," + result.lng();
			}
		}
	}
	
	var loadMarkersForMedia = function(mediaListStr) {
		var mediaList = mediaListStr.split(',');
		var mediaNotInCache = "0";
		clearMarkers();
		for(var i = 0; i < mediaList.length; i++)
		{
			var imageId = mediaList[i];
			if(markersMap[imageId])
			{
				var marker = markersMap[imageId];
				if(marker != null)
				{
					var markerInfo = new Object();
					markerInfo.id = imageId;	
					markerInfo.lat = marker.getPosition().lat();
					markerInfo.lng = marker.getPosition().lng();
					addedMarkers.push( markerInfo );
				}
			}
			else
			{
				mediaNotInCache += "," + String(imageId);
			}
		}
		
		updateMarkers();
		if(mediaNotInCache.length > 1)
			callCallback("getGPSForMedia", mediaNotInCache);
	}
				
	
	var clearMarkers = function() {
	
		//callCallback("startTimer", "clearMarkers");
		markerClusterer.clearMarkers();
		
		for( var imageId in currentMarkersMap ) {
			var marker = currentMarkersMap[ imageId ];
			if ( marker != null ) {
				// make sure it is invisible and garbage collected
				marker.setVisible( false );
				marker.setMap( null );
				delete marker;
			}
			currentMarkersMap[ imageId ] = null;
		}
		delete currentMarkersMap;
		currentMarkersMap = new Object();
		delete previousAvailableSet;
		previousAvailableSet = new Object();
		delete previousSelectedSet;
		previousSelectedSet = new Object();
		selectedMarkers = [];
		clickedCluster = null;
		dragDropTargetCluster = null;
		clearSearchCallout();
		draggedPin = null;
		//callCallback("endTimer", "clearMarkers");
	}
	
	var bounceMarker = function( markerId ) {
	
		if ( bouncingMarker ) {
			if ( bouncingMarker.setAnimation )
				bouncingMarker.setAnimation( null );
			bouncingMarker = null;
		}
	
		if ( markerId && markerId != "" && currentMarkersMap[ markerId ] ) {
			bouncingMarker = currentMarkersMap[ markerId ];
			if ( bouncingMarker && bouncingMarker.setAnimation && google.maps.Animation ) {
				bouncingMarker.setAnimation( google.maps.Animation.BOUNCE );
			}
		}
		
		setTimeout( function() { 
			if ( bouncingMarker ) {
				if ( bouncingMarker.setAnimation )
					bouncingMarker.setAnimation( null );
				bouncingMarker = null;
			}
		}, 20 );
	}
	
	var doMarkerDragEntered = function( lat, lng ) {
		if(waitingTimeOut)
			clearTimeout(waitingTimeOut);
		var pt = new google.maps.LatLng( lat, lng );
		dragDropTargetCluster = markerClusterer.canAcceptMarkerDropImp( pt, false, dragDropTargetCluster );
		//alert("dragEntered: " + dragDropTargetCluster.getCenter().lat() + "," + dragDropTargetCluster.getCenter().lng());
	}
	
	var doMarkerDrag = function( lat, lng ){
		var pt = new google.maps.LatLng( lat, lng );
		dragDropTargetCluster = markerClusterer.canAcceptMarkerDropImp( pt, false, dragDropTargetCluster );
		//alert("drag: " + dragDropTargetCluster.getCenter().lat() + "," + dragDropTargetCluster.getCenter().lng());
	}
	
	var doMarkerDragEnd = function( lat, lng ){
		var pt = new google.maps.LatLng( lat, lng );
		dragDropTargetCluster = markerClusterer.canAcceptMarkerDropImp( pt, false, dragDropTargetCluster );
		//alert("dragEnd: " + dragDropTargetCluster.getCenter().lat() + "," + dragDropTargetCluster.getCenter().lng());
	
		var success = false;
		if (dragDropTargetCluster) {
			var pos = dragDropTargetCluster.getCenter();
			var mediaId = dragDropTargetCluster.markers_[0].id;
			dragDropTargetCluster = null;
			if (pos) {
				return (pos.lat() + "," + pos.lng() + "," + mediaId);
			}
		}
	}
	
	var fitBounds = function( neLat, neLng, swLat, swLng ){
		var ne = new google.maps.LatLng( neLat, neLng );
		var sw = new google.maps.LatLng( swLat, swLng );
		var bounds = new google.maps.LatLngBounds( sw, ne );
		map.fitBounds( bounds );
	}
	
	var setZoom = function(zoom){
		map.setZoom(zoom);
	}
	
	var getLocationFromImageId = function( imageId ){
		
		var marker = currentMarkersMap[ imageId ];
	
		if ( marker ) {
			var pos = marker.getPosition();
			callCallback( "sendJSResults", pos.lat(), pos.lng() );
		}
	}
	
	var setClusterSize = function( size ){

		markerClusterer.setGridSize( size );
		markerClusterer.resetViewport();
		markerClusterer.redraw();
	}
	
	var getMaxZoom = function() {
		if ( map == null ) return;
		var mapTypeId = map.getMapTypeId();
		if ( mapTypeId == null ) return;

		if ( ( mapTypeId == google.maps.MapTypeId.SATELLITE
				|| mapTypeId == google.maps.MapTypeId.HYBRID )
			&& maxZoomOverride ) {

			return maxZoomOverride;
		}

		var mapType = map.mapTypes.get( mapTypeId );
		if ( mapType == null ) return;
		return mapType.maxZoom;
	}
	
	var maxZoomChanged = function( result ) {

		if ( result && result.status == google.maps.MaxZoomStatus.OK ) {
			if ( result.zoom != maxZoomOverride ) {
				maxZoomOverride = result.zoom;
				callCallback( "onMaxZoomChanged", result.zoom );
			}
		} else {
			maxZoomOverride = null;
		}
	}

	var checkMaxZoom = function() {
		if ( map == null ) return;
		if ( maxZoomService == null ) return;
		
		var mapTypeId = map.getMapTypeId();
		var center = map.getCenter();

		if ( mapTypeId == google.maps.MapTypeId.SATELLITE
			|| mapTypeId == google.maps.MapTypeId.HYBRID ) {

			maxZoomService.getMaxZoomAtLatLng( center, maxZoomChanged );
		}
	}
	
	var getClickedClusterCount = function() {
		if ( clickedCluster ) {
			return clickedCluster.markers_.length;
		} else {
			return null;
		}
	}

	var getClickedClusterImageId = function( index ) {	
		if ( clickedCluster == null ) return -1;
		if ( index < 0 || index >= clickedCluster.markers_.length ) return -1;
		return clickedCluster.markers_[ index ].id;
	}

	var selectAllPhotosInClickedCluster = function() {
		if ( clickedCluster ) {
			var count = getClickedClusterCount();
			if ( count && count > 0 ) {
				var clickedClusterIds = [];
				
					
				
				for ( var i = 0; i < count; ++i ) {
					var id = getClickedClusterImageId( i );
					if ( id ) {
						clickedClusterIds.push( id );
					}
				}		

				var jsonResults = JSON.stringify( clickedClusterIds );			
				callCallback( "onClusterMarkersClick", jsonResults );
			}
		}
	}
	
	var revealPhotosInClickedCluster = function() {
		if ( clickedCluster ) {
			map.fitBounds( clickedCluster.getBounds() );
			clickedCluster = null; 
		}
	}
	
	var highlightMarkers = function(imageIdListStr) {
		var imageIdList = imageIdListStr.split(',');
		if(imageIdList.length <= 0 ) return;
		
		var mapBounds = map.getBounds();
		var isAnyMarkerVisible = false;
		selectedMarkers = [];
		for (var i = 0; i < imageIdList.length; ++i) {
			var imageId = imageIdList[i];
			if(imageId in currentMarkersMap) {
				var marker = currentMarkersMap[imageId];
				if(marker) {
					var markerInfo = new Object();
					var markerPosition = marker.getPosition();
					markerInfo.id = marker.id;
					markerInfo.lat = markerPosition.lat();
					markerInfo.lng = markerPosition.lng();
					selectedMarkers.push(markerInfo);
					isAnyMarkerVisible = mapBounds.contains(markerPosition);
				}
			}
		}
		updateMarkers();
		if(!isAnyMarkerVisible)
			waitingTimeOut = setTimeout( function() { 
										setCenter(selectedMarkers[0].lat, selectedMarkers[0].lng);
							}, 1000);		//bring pin associated with first selected media to focus
	}
	
	var setCenter = function( lat, lng, jumpTo ) {
	
		var currentCenter = map.getCenter();
		var currentLat = currentCenter.lat();
		var currentLng = currentCenter.lng();
		
		if ( lat == null )
			lat = currentLat;
		if ( lng == null )
			lng = currentLng;
			
		if ( lat == currentLat && lng == currentLng )
			return;
	
		var point = new google.maps.LatLng( lat, lng );
		
		if ( jumpTo )
			map.setCenter( point );
		else
			map.panTo( point );
		
	}
	
	var dropMarker = function( lat, lng, calloutText, bOnExistingPin ){
	
		if(searchMarker)
			return;
	

		var latlng = new google.maps.LatLng( lat, lng );
		
		if(! bOnExistingPin) {
			var markerOptions = new Object();
			markerOptions.position = latlng;
			markerOptions.clickable = false;
			markerOptions.map = map;
			markerOptions.animation = google.maps.Animation.BOUNCE;
			markerOptions.icon = searchMarkerImage;
			markerOptions.draggable = true;
				
			searchMarker = new google.maps.Marker(markerOptions);
			searchMarker.dragged = 0;
			
			setTimeout( function() { 
						searchMarker.setAnimation( null );
			}, 2000 );
			
			google.maps.event.addListener( searchMarker, 'drag', function(mouseEvent) {
				searchMarker.dragged = 1;
				clearSearchCallout();			
			} );
			
		
			google.maps.event.addListener( searchMarker, 'dragend', function( mouseEvent ) {
				showSearchCallout(calloutText, searchMarker.getPosition().lat(), searchMarker.getPosition().lng(), false);
			} );
		}
		
		showSearchCallout(calloutText, latlng.lat(), latlng.lng(), bOnExistingPin);
							
	
	};
	
	var clearSearchMarker = function(){
		if(searchMarker){
			searchMarker.setVisible(false);
			searchMarker = null;	
		}
		clearSearchCallout();
	};
		
	var lockMarkers = function( locked ){
		disableDragging = locked;
		for( var imageId in currentMarkersMap ) {
			var marker = currentMarkersMap[ imageId ];
			if ( marker != null ) {
				marker.setDraggable( !locked );
			}
		}

		// lock/unlock all clusters. 
		markerClusterer.updateClustersAsNeeded( true );
		
	}
	
	
	var updateHoverViewIcons = function(bEnable)
	{		
		markerClusterer.updateEnableHoverIcons(bEnable);
		markerClusterer.updateClustersAsNeeded( true );
	
	}
	
	
	
	var selectClusterContainingImage = function( imageId ){
		var imageMarker = currentMarkersMap[ imageId ];
	
		if ( imageMarker ) {
			for ( var i = 0, cluster; cluster = markerClusterer.clusters_[ i ]; i++ ) {
				for ( var j = 0, marker; marker = cluster.markers_[ j ]; j++ ) {
					if ( marker == imageMarker ) {
						clickedCluster = cluster;
						return;
					}
				}
			}
		}
	}
	
	var clearClickedCluster = function() {
		clickedCluster = null;
	}
	
	var getClickedClusterType = function() {
		if ( getClickedClusterCount() > 1 ) {
			var isGroup = clickedCluster.isGroupCluster;
			if( isGroup == true ) {
				callCallback( "sendJSResults", "group" );
			} else {
				callCallback( "sendJSResults", "cluster" );
			}
		}
	}
	
	var getClickedClusterCenter = function() {
		if ( clickedCluster != null ) {
			var pos = clickedCluster.getCenter();
			if( pos != null ) {
				callCallback( "sendJSResults", pos.lat(), pos.lng() );
			}
		}
	}
	
	var panToBounds = function( neLat, neLng, swLat, swLng ){
		if ( map != null ) {
			var ne = new google.maps.LatLng( neLat, neLng );
			var sw = new google.maps.LatLng( swLat, swLng );
			var bounds = new google.maps.LatLngBounds( sw, ne );
			map.panToBounds(bounds);
		}
	}
	
	var panBy = function(x, y){
		if ( map != null ) {
			map.panBy( x, y );
		}
	}
	
	var getLocationToViewPoint = function( lat, lng ) {
		if ( map != null ) {
			var latlng = new google.maps.LatLng( lat, lng );
			var point = locationToViewPoint( latlng );
			return point.toString();
		}
	}
	
	var getViewPointToLocation = function( x, y ) {
		if ( map != null ) {
			var point = new google.maps.Point( x, y );
			var latlng = viewPointToLocation( point );
			return latlng.toString();
		}	
	}

	
//this will be called after alias is applied to any tag
//it will iterate for whole clusters and recompute the strings for tagIds present	
	var clustersCheckForAliasUpdate = function() {
	
	setTimeout( function() {
		var clusterArray = [];
		clusterArray = markerClusterer.getClusters();
		
		for (var i = 0, cluster; cluster = clusterArray[i]; i++) {
			
			var tagIdList = cluster.getTagIdList();
			var lat = cluster.getCenter().lat();
			var lng = cluster.getCenter().lng();
			
			var cmnTags = 0;
			if(cluster.hasCommonTags())
			 cmnTags = 1;
			
			var arg = cmnTags + "," + lat + "," + lng + "," + tagIdList ;
			
			callCallback("getLocationNameForClusterViaTagIdList",arg);
			
		}
	},0);
	
};
	
	var updateLocationOfCluster = function(strList, tagIdList, bHaveCommonTags, lat, lng) {
		var resultList = strList;
		var centerPt = new google.maps.LatLng( lat, lng );
		markerClusterer.updateClusterText( centerPt, resultList, bHaveCommonTags, tagIdList);
	
	}
	
	function element( name, content){
		var xml;
		if (!content){
			xml='<' + name + '/>';
		}
		else {
			xml='<'+ name + '>' + content + '</' + name + '>';
		}
		return xml;
	}
	
	var geoCode = function() {
		var isGeocode = true;
		var addressString = arguments[0];
		var lat = arguments[1];
		var lng = arguments[2];
		var latitude = lat;
		var longitude = lng;
		var addr = addressString;
		var language = arguments[3];
		
		var request = new Object();
	
		request.language = language;
	
		if ( lat != "" && lng != "" ) {
			var latLng = new google.maps.LatLng( parseFloat( lat ), parseFloat( lng ) );
			request.latLng = latLng;
			isGeocode = false;
		} else {
			request.bounds = map.getBounds();
		}
		
		if (	addressString !="NO_ADDRESS_FOUND" &&  addressString != "" ) {
			isGeocode = true;
			request.address = addressString;
		}
		geocoder.geocode( request, function( results, status ) {
			if( status == google.maps.GeocoderStatus.OK ) {
				var mappedResults = [];
				// transform the results into something more JSON-friendly
				for ( var i = 0; i < results.length; i++ ) {
					var result = results[ i ];
					var address = result.formatted_address;
					//alert(JSON.stringify(result));
					var components = [];
					//alert(result.types);
					
					if(result.types) {
						for( var j = 0; j < result.types.length; ++j) {
							var component = "";
							component = component + element("types", result.types[ j ]);
							//alert(component);
							components.push(element("component", component));
						}	
					}
					//alert("starting parsing");
					for( var comp = 0; comp < result.address_components.length; comp++ ) {
						component = "";
						for( var idx = 0; idx < result.address_components[ comp ].types.length; idx++ ) {
							switch ( result.address_components[ comp ].types[ idx ] ) {
								case "locality":
									component = component + element("locality", result.address_components[ comp ].long_name);
									break;
								case "sublocality":
									component = component + element("district", result.address_components[ comp ].long_name);
									break;
								case "route":
									component = component + element("route", result.address_components[ comp ].long_name);
									break;
								case "street_number":
									component = component + element("street_number", result.address_components[ comp ].long_name);
									break;
								case "political":
									component = component + element("political", result.address_components[ comp ].long_name);
									break;
								case "establishment":
									component = component + element("establishment", result.address_components[ comp ].long_name);
									break;
								case "neighborhood":
									component = component + element("neighborhood", result.address_components[ comp ].long_name);
									break;
								case "premise":
									component = component + element("premise", result.address_components[ comp ].long_name);
									break;
								case "natural_feature":
									component = component + element("natural_feature", result.address_components[ comp ].long_name);
									break;
								case "airport":
									component = component + element("airport", result.address_components[ comp ].long_name);
									break;	
								case "park":
									component = component + element("park", result.address_components[ comp ].long_name);
									break;	
								case "point_of_interest":
									component = component + element("point_of_interest", result.address_components[ comp ].long_name);
									break;	
								case "administrative_area_level_3":
									component = component + element("administrative_area_level_3", result.address_components[ comp ].long_name);
									break;
								case "administrative_area_level_2":
									component = component + element("administrative_area_level_2", result.address_components[ comp ].long_name);
									break;
								case "administrative_area_level_1":
									component = component + element("administrative_area_level_1", result.address_components[ comp ].long_name);
									break;
								case "country": 
									component = component + element("country", result.address_components[ comp ].long_name);
									break;
								default : 
									break;
							}
						}
						components.push(element("component", component));
					}
					//alert("end parsing");
					var componentResults = element("components", components);
									
					var geometry = result.geometry;
					var bounds = geometry.bounds;
					if ( bounds == null )
						bounds = geometry.viewport;
					var ne = bounds.getNorthEast();
					var sw = bounds.getSouthWest();

					var lat, lng;
	
					if ( geometry.location ) {
						lat = geometry.location.lat();
						lng = geometry.location.lng();
					}
	
					mappedResults.push(element("result", 
										element("title", address) + 
										element("location", element("lat", lat) + element("lng", lng)) +
										element("components", componentResults) +
										element("bounds", element("neLat", ne.lat()) + element("neLng", ne.lng()) + element("swLat", sw.lat()) + element("swLng", sw.lng()))));

				}

				var xmlResults = element("results", mappedResults);	
				if(isGeocode)
					callCallback( "geocodeCallback", status, xmlResults );
				else
					callCallback( "reverseGeocodeCallback", status, xmlResults );
			}
			else if(status == google.maps.GeocoderStatus.OVER_QUERY_LIMIT && addr != "NO_ADDRESS_FOUND"){
				var adr = "NO_ADDRESS_FOUND";
				setTimeout(function(){
				geoCode(adr,latitude,longitude);
				}, 2000);

			}
			else
			{
				if(isGeocode)
					callCallback( "geocodeCallback", status );
				else
					callCallback( "reverseGeocodeCallback", status );
			}
		} );
	}
	
	var processUIEvents = function() {
		if(!timerActive) return;
		callCallback("processUIEvents");
	}
	
	var stopProcessUITimer = function() {
		timerActive = false;
	}
	
	var notifyGPSTagSuccess = function (success) {
		if(!success)
		{
			pinMoveCancelled(draggedPin);
		}
		draggedPin = null;
	}	
	
	var initialMarkerLayout = function ( latList, lngList, idList){
		//callCallback("startTimer", "markerLayout");
		var latitudeList = latList.split(',');
		var longitudeList = lngList.split(',');
		var mediaList = idList.split(',');
			
		for(var i=0; i<mediaList.length; i++){
			var markerInfo = new Object();
			markerInfo.id = mediaList[i];	
			markerInfo.lat = latitudeList[i];
			markerInfo.lng = longitudeList[i];
			addedMarkers.push( markerInfo );
		}
		timerActive = true;
		//processUIEvents();
		
		updateMarkers();
		//callCallback("endTimer", "markerLayout");
		/*//alert(time.report());*/
		
		stopProcessUITimer();
	}
	
	var addImage = function ( idList, lat, lng ){
		
		//alert("add image");			
		var mediaList = idList.split(',');
		
		for(var i=0; i<mediaList.length; i++){
			var markerInfo = new Object();
			markerInfo.id = mediaList[i];	
			markerInfo.lat = lat;
			markerInfo.lng = lng;
			addedMarkers.push( markerInfo );
		}
		updateMarkers();
	}
	
	var removeImage = function ( idList ){
		//alert("remove image");	
		
		var mediaList = [];
		mediaList = idList.split(",");
		
		for(var i=0; i<mediaList.length; i++){
			var markerInfo = new Object();
			markerInfo.id = mediaList[i];
			deletedMarkers.push( markerInfo );
		}
		updateMarkers();
	}
	
	var updateMarkers = (function() {
	//alert("updateMarkers");
	
	//callCallback("startTimer", "Enter updateMarker");	
	/*
	if ( resetMarkers ) {	
			previousAvailableSet = null;
			previousSelectedSet = null;
			clearMarkers();
		}*/
	timerActive = true;
	//processUIEvents();		
	
	var availableSet = new Object();

	//callCallback("startTimer", "Iterating markerMap");
	for (var v in currentMarkersMap) {
		var markerInfo = new Object();
		markerInfo.id = currentMarkersMap[v].id;	
		markerInfo.lat = currentMarkersMap[v].getPosition().lat();
		markerInfo.lng = currentMarkersMap[v].getPosition().lng();
		availableSet[markerInfo.id] = markerInfo;
	}
	
	//callCallback("endTimer", "Iterating markerMap");
	//alert("availableSet: "+Object.size(availableSet));
	//alert("addedmarkers: "+addedMarkers.length);
 
	//callCallback("startTimer", "Iterating addedMarkers");	
	for (var i = 0; i < addedMarkers.length; ++i) {
		var id = addedMarkers[i].id;
		availableSet[id] = addedMarkers[i];
	}
	//callCallback("endTimer", "Iterating addedMarkers");
	//alert("availableSet: "+Object.size(availableSet));
	for ( i = 0; i < deletedMarkers.length; ++i) {
		var id = deletedMarkers[i].id;
		delete availableSet[id];
	}
	
	//alert("availableSet: "+Object.size(availableSet));
	var selectedSet = new Object();
	
	//callCallback("startTimer", "Iterating selectedmarkers");
	for ( i = 0; i < selectedMarkers.length; ++i) {
		var id = selectedMarkers[i].id;
		selectedSet[id] = selectedMarkers[i];
	}
	//callCallback("endTimer", "Iterating selectedmarkers");
//	alert("selectedSet: "+Object.size(selectedSet));

	var added = [];
	var addedSet = new Object();
	var removed = [];
	var moved = [];
	var selected = [];
	var deselected = [];

	//callCallback("startTimer", "Iterating availableSet");
	for(var id in availableSet) {
		var markerInfo = availableSet[id];
		if(previousAvailableSet[id]) {
			var previousMarker = previousAvailableSet[ id ];
			if (markerInfo.lat && markerInfo.lng && previousMarker.lat && previousMarker.lng && 
				  !identicalCoordinates( markerInfo.lat, markerInfo.lng, previousMarker.lat, previousMarker.lng )) {
				moved.push(markerInfo);
			}
		}
		else {
			added.push(markerInfo);
			addedSet[ markerInfo.id ] = markerInfo;
		}
			
		if (selectedSet[ id ] && !previousSelectedSet[ id ]) {
			selected.push(markerInfo.id );
		}
		else if (!selectedSet[ id ] && previousSelectedSet[ id ]) {
			deselected.push(markerInfo.id );
		}
	}
	
	//callCallback("endTimer", "Iterating availableSet");
	//alert("added: "+added.length + "moved: "+moved.length + "addedSet: "+Object.size(addedSet) + "selected: "+selected.length +"deselected: "+deselected.length );
	//callCallback("startTimer", "Iterating previousavailableSet");
	for(var id in previousAvailableSet) {
		var markerInfo = previousAvailableSet[id];
		if (!availableSet[ id ]) {
			removed.push(markerInfo );
		}
	}
	//callCallback("endTimer", "Iterating previousavailableSet");	
	//alert("removed: "+removed.length);
	
	if (added.length > 0 || removed.length > 0 || moved.length > 0 || selected.length > 0 || deselected.length > 0) {
		
		markerClusterer.setReady_( false );

		var clickedClusterIdSet = null;
		
		/*
			if ( clickedCluster && clickedCluster.markers_ ) {
						
						// this cluster may be deleted and recreated by the update, so we need to record 
						// which photos it contains and reselect the cluster that contains them after the 
						// update.
					
						clickedClusterIdSet = [];
						for ( var i = 0, marker; marker = clickedCluster.markers_[ i ]; i++ ) {			
							if ( marker.id ) {
								clickedClusterIdSet[ marker.id ] = true;
							}
						}
					}*/
			

		var selectedMarkerIdSet = [];
		var deselectedMarkerIdSet = [];
		var selectedMarkerCount = 0;
		var deselectedMarkerCount = deselected.length;
		
		//callCallback("startTimer", "Iterating deselected");

		for ( var i = 0, id; id = deselected[ i ]; ++i )
			deselectedMarkerIdSet[ id ] = true;

		//callCallback("endTimer", "Iterating deselected");
		//callCallback("startTimer", "Iterating selected");
		for ( var i = 0, id; id = selected[ i ]; ++i ) {
			if ( deselectedMarkerIdSet[ id ] != true ) {
				selectedMarkerIdSet[ id ] = true;
				selectedMarkerCount++;
			}
		}
		//callCallback("endTimer", "Iterating selected");
		//alert("selectedIdSet"+selectedMarkerIdSet.length + "deselectedIdSet"+deselectedMarkerIdSet.length	);	
		
		var removedCnt = 0;

		for (var i=0; i < removed.length; i++) {
			var theImageId = removed[ i ].id;
			//alert("removing");
			var marker = currentMarkersMap[ theImageId ];
			if ( marker ) {
			
				removedCnt = removedCnt + 1;
			
				markerClusterer.removeMarker( marker, true );
				
				// make sure it is invisible and garbage collected
				marker.setVisible( false );
				marker.setMap( null );
				delete marker;
			}
			
			currentMarkersMap[ theImageId ] = null;
			delete currentMarkersMap[theImageId];
			if(markersMap[theImageId])
			{
				//alert("we are good");
				markersMap[ theImageId ] = null;
				delete markersMap[theImageId];
			}
		}

		var needsRefresh = false;
		//callCallback("startTimer", "moving markers");
		for (var i=0; i < moved.length; i++) {
			var markerInfo = moved[ i ];
			var theImageId = markerInfo.id;

			//alert( "moved marker: " + theImageId );

			var marker = currentMarkersMap[ theImageId ];
			if ( marker ) {

				//alert( "found moved marker position: "  + marker.getPosition());

				// constrain the marker's location so it doesn't fall far outside of the map
				var lat = Math.max( -MAX_LATITUDE, Math.min( MAX_LATITUDE, markerInfo.lat ) );

				var myLatlng = new google.maps.LatLng( lat, markerInfo.lng );
				
				//callCallback("startTimer", "moving markers in markerclusterer");
				var wasRemoved = markerClusterer.removeMarkerFromClusters_( marker, true);
				
				marker.setPosition( myLatlng );
				
				var wasAdded = markerClusterer.addMarkerToClusters_( marker, true);
				//callCallback("endTimer", "moving markers in markerclusterer");
				needsRefresh = needsRefresh || wasRemoved || wasAdded;

				//alert( "wasRemoved? " + wasRemoved + ", wasAdded? " + wasAdded + ", needsRefresh? " + needsRefresh );
				
			}
		}
		//callCallback("endTimer", "moving markers");
		
//alert( "adding " + added.length + " new markers to clusterer..." );
		
		var noRedraw = added.length > 100;
		//callCallback("startTimer", "Iterating added");
		for (var i=0; i < added.length; i++) {
			if(!timerActive) break;									//there might be case when marker processing is ongoing and user leaves the room.
			
			var markerInfo = added[ i ];
			var theImageId = markerInfo.id;

			// constrain the marker's location so it doesn't fall far outside of the map
			var lat = Math.max( -MAX_LATITUDE, Math.min( MAX_LATITUDE, markerInfo.lat ) );
			var myLatLng = new google.maps.LatLng( lat, markerInfo.lng );
			
			if(markersMap[theImageId])
			{
				var marker = markersMap[theImageId];
				marker.setPosition(myLatLng);
			}
			
			else
			{
				var markerOptions = new Object();
				markerOptions.position = myLatLng;
				markerOptions.map = map;
				
				markerOptions.icon = baseThumbUrl + currCatalogVersion + "=" +  theImageId;    //associate media thumb with marker icon

				var marker = new google.maps.Marker( markerOptions );
				marker.smallIcon = baseThumbUrl + smallIconString + currCatalogVersion +  "=" + marker.id;
				
				//callCallback("startTimer", "adding eventlisteners");
				addMouseoverListener( marker);
				marker.hookup = function(marker) {
					addClickListener( marker);
					addDblClickListener(marker);
					addRightClickListener( marker);
					addMouseoutListener( marker);
					addDragStartListener( marker);
					addDragListener( marker);
					addDragEndListener( marker);
					marker.hookup = null;
				};
			//callCallback("endTimer", "adding eventlisteners");
			
				markersMap[theImageId] = marker;
			}

			marker.clickable = true;
			marker.setDraggable(!disableDragging); // = !disableDragging; // apparently, marker.draggable = true doesn't work, but marker.setDraggable(true) works.
			marker.raiseOnDrag = false;
			marker.id = theImageId;
			marker.icon = /*normalMarkerImage*/baseThumbUrl + currCatalogVersion + "=" + marker.id;
			marker.smallIcon = baseThumbUrl + smallIconString + currCatalogVersion +  "=" + marker.id;
			marker.visible = false;
			
			marker.selected = false;
			
			marker.normalIcon = baseThumbUrl + currCatalogVersion + "=" + marker.id;    //associate media thumb with marker icon
			if ( markerInfo.selected ) {
				marker.selected = true;			
			} 

			currentMarkersMap[ theImageId ] = marker;
		//callCallback("startTimer", "adding marker to markerclusterer");
			markerClusterer.addMarker( marker, noRedraw );
		//callCallback("endTimer", "adding marker to markerclusterer");
		}
		
		//callCallback("endTimer", "Iterating added");
		var selectionAddedCount = 0;
		var selectionRemovedCount = 0;
		//callCallback("startTimer", "Iterating clusters");
		for ( var i = 0, cluster; cluster = markerClusterer.clusters_[ i ]; i++ ) {
				var clusterChanged = false;
				for ( var j = 0, marker; marker = cluster.markers_[ j ]; j++ ) {
					if ( marker ) {
						if ( !marker.selected && selectedMarkerIdSet[ marker.id ] ) {
							marker.setIcon( /*selectedMarkerImage*/baseThumbUrl + currCatalogVersion + "=" + marker.id );
							marker.normalIcon = /*selectedMarkerImage*/baseThumbUrl + currCatalogVersion + "=" + marker.id;
							marker.smallIcon = baseThumbUrl + smallIconString + currCatalogVersion +  "=" + marker.id;

							marker.selected = true;
							clusterChanged = true; 
							selectionAddedCount++;
						} else if ( marker.selected && deselectedMarkerIdSet[ marker.id ] ) {
		//					//alert("deselecting");
							marker.setIcon( /*normalMarkerImage*/baseThumbUrl + currCatalogVersion + "=" + marker.id );
							marker.normalIcon = /*normalMarkerImage*/baseThumbUrl + currCatalogVersion + "=" + marker.id;
							marker.smallIcon = baseThumbUrl + smallIconString + currCatalogVersion +  "=" + marker.id;

							marker.selected = false;
							clusterChanged = true;
							selectionRemovedCount++;
						}
					}
				}
	
				if ( clusterChanged && cluster.markers_.length >= 1 )
					cluster.updateIcon();
		}
		//callCallback("endTimer", "Iterating clusters");

		// If we selected or deselected fewer markers than we were supposed to that means they do not yet have clusters. This
		// can happen if you click on a photo in the filmstrip that is has not yet been shown in the map at the current zoom level,
		// so it's not in any cluster yet. If that happens, take the hit of iterating over all markers in the clusterer to update
		// their selected state.
		//callCallback("startTimer", "Iterating allmarkers");
		if ( selectionAddedCount < selectedMarkerCount || selectionRemovedCount < deselectedMarkerCount ) {		
			for ( var i = 0, marker; marker = markerClusterer.markers_[ i ]; i++ ) {
				if ( !marker.selected && selectedMarkerIdSet[ marker.id ] ) {
					marker.setIcon( /*selectedMarkerImage*/baseThumbUrl + currCatalogVersion + "=" + marker.id );
					marker.normalIcon = /*selectedMarkerImage*/baseThumbUrl + currCatalogVersion + "=" + marker.id;
					marker.smallIcon = baseThumbUrl + smallIconString + currCatalogVersion +  "=" + marker.id;

					marker.selected = true;
				} else if ( marker.selected && deselectedMarkerIdSet[ marker.id ] ) {
					marker.setIcon( /*normalMarkerImage*/baseThumbUrl + currCatalogVersion + "=" + marker.id );
					marker.normalIcon = /*normalMarkerImage*/baseThumbUrl + currCatalogVersion + "=" + marker.id;
					marker.smallIcon = baseThumbUrl + smallIconString + currCatalogVersion +  "=" + marker.id;
					marker.selected = false;
				}
			}
		}
		
		//callCallback("endTimer", "Iterating allmarkers");
		//if ( needsRefresh || removed > 0 ) {
		
		//callCallback("startTimer", "updating markerclusterer");
		if ( removedCnt > 0 ) {
//no need of recreating clusters as currently one cluster is removed in total
//			markerClusterer.resetViewport();
		} else if ( moved.length > 0 ) {
			//markerClusterer.redraw();

			markerClusterer.updateClustersAsNeeded(); // updates selected vs. unselected state
		} else if ( selected.length > 0 || deselected.length > 0 ) {

			markerClusterer.updateClustersAsNeeded(); // updates selected vs. unselected state
		}

		markerClusterer.setReady_(false);
		markerClusterer.setReady_(true);
		markerClusterer.redraw();

		
		//markerClusterer.updateClustersAsNeeded();
		
		//callCallback("endTimer", "updating markerclusterer");
		
		/*
				if ( clickedClusterIdSet ) {
				
							// reselect the cluster that best matches the set of photos in the
							// clicked cluster before the update
						
							var bestMatchCount = 0;
							
							for ( var i = 0, cluster; cluster = markerClusterer.clusters_[ i ]; i++ ) {
								var matches = 0;
								for ( var j = 0, marker; marker = cluster.markers_[ j ]; j++ ) {
									if ( marker && clickedClusterIdSet[ marker.id ] )
										matches++;
								}
								if ( matches > bestMatchCount ) {
									clickedCluster = cluster;
									bestMatchCount = matches;
								}
							}*/		
	}	
	addedMarkers = [];
	deletedMarkers = [];
	//selectedMarkers = [];

	previousSelectedSet = selectedSet;
	previousAvailableSet = availableSet;
	//callCallback("endTimer", "Enter updateMarker");
	
	stopProcessUITimer();
	
	});
			
	var addClickListener = function( marker) {
				google.maps.event.addListener( marker, 'click', function() {	
				//alert('clusterclicked');
					var center = marker.getPosition();
					clickedPin = marker;
					var centerX, centerY;
					if ( center ) {
						center = locationToViewPoint( center );
						centerX = center.x;
						centerY = center.y;
					}
					
					if ( bouncingMarker ) {
						if ( bouncingMarker.setAnimation )
							bouncingMarker.setAnimation( null );
						bouncingMarker = null;
					}
					
					selectedMarkers = [];
					var markerInfo = new Object();
					markerInfo.id = marker.id;
					markerInfo.lat = marker.getPosition().lat();
					markerInfo.lng = marker.getPosition().lng();
					selectedMarkers.push(markerInfo);
					updateMarkers();
					
					callCallback( "onMarkerClick", marker.id, centerX, centerY);
				} );
			};
			
			
			var addDblClickListener = function( marker) {
				google.maps.event.addListener( marker, 'dblclick', function() {	
						showSelectedClusterMedia(marker);
				});
			};
			
			
			var addRightClickListener = function( marker) {
				
				google.maps.event.addListener( marker, 'rightclick', function() {		
					var center = marker.getPosition();
					var centerX, centerY;
					if ( center ) {
						center = locationToViewPoint( center );
						centerX = center.x;
						centerY = center.y;
					}
					callCallback( "onMarkerRightClick", marker.id );
				} );
			
			};
			
			var addMouseoverListener = function( marker) {
				google.maps.event.addListener( marker, 'mouseover', function() {
					//alert("mouse over");
					if(marker.hookup) {
						marker.hookup(marker);
						marker.hookup = null;
					}
					callCallback( "onMarkerMouseover", marker.id);
				} );
				
			};
	
			var addMouseoutListener = function( marker) {
				
				google.maps.event.addListener( marker, 'mouseout', function() {
					
					callCallback( "onMarkerMouseout", marker.id);
				} );
				
			};
	
			var addDragStartListener = function( marker) {
				//alert("drag start");
				google.maps.event.addListener( marker, 'dragstart', function( mouseEvent ) {
					callCallback( "onMarkerDragStart", mouseEvent.latLng.lat(), mouseEvent.latLng.lng(), marker.id);
					dragDropTargetCluster = markerClusterer.canAcceptMarkerDrop( marker, false, dragDropTargetCluster );
					//alert("dragStart: " + dragDropTargetCluster.getCenter().lat() + "," + dragDropTargetCluster.getCenter().lng());
				} );
			};
		
			var addDragListener = function( marker) {
				google.maps.event.addListener( marker, 'drag', function( mouseEvent ) {
					lastDragTime = new Date().getTime();
					clearSearchCallout();
					dragDropTargetCluster = markerClusterer.canAcceptMarkerDrop( marker, false, dragDropTargetCluster );
					//alert("dragMoveMarker: " + dragDropTargetCluster.getCenter().lat() + "," + dragDropTargetCluster.getCenter().lng());
					callCallback( "onMarkerDrag", mouseEvent.latLng.lat(), mouseEvent.latLng.lng(), marker.id);						
				} );
			};
		
			var addDragEndListener = function( marker) {
				google.maps.event.addListener( marker, 'dragend', function( mouseEvent ) {
					//alert("in dragendlistener");
					if(draggedPin && draggedPin !== marker)
					{
						//alert("clear existing drag");
						pinMoveCancelled(draggedPin);
					}
					//alert("clearing searchmarker");
					clearSearchMarker();
					draggedPin = marker;
					//alert("check for existing pin");
					dragDropTargetCluster = markerClusterer.canAcceptMarkerDrop( marker, false, dragDropTargetCluster );
					//alert("markerDragEnd: " + dragDropTargetCluster.getCenter().lat() + "," + dragDropTargetCluster.getCenter().lng());
					var success = false;
					var existingImageId = 0;
					if (dragDropTargetCluster) {
					//	alert("existing pin found");
						existingImageId = dragDropTargetCluster.markers_[0].id;
						var pos = dragDropTargetCluster.getCenter();
						if (pos) {
							success = true;
							marker.setPosition(pos);
							callCallback( "onMarkerDragEnd", pos.lat(), pos.lng(), existingImageId );
						}
					}
					
					if (!success) {
						callCallback( "onMarkerDragEnd", mouseEvent.latLng.lat(), mouseEvent.latLng.lng(), existingImageId );
					}
					
					dragDropTargetCluster = null;
				} );
			};

	function identicalCoordinates( lat1, lng1, lat2, lng2 ) {
		if (Math.abs( lat1 - lat2 ) <= 1.0e-10 && Math.abs( lng1 - lng2 ) <= 1.0e-10) {
			return true;
		}
		return false;
	}
	
	var setInitialMapParams = function(lat, lng, zoom, mapStyle)
	{
		if(lat && lng)
		{
			defaultLat = lat;
			defaultLng = lng;
		}
		if(zoom > 2)
			defaultZoom = zoom;
			
		if(mapStyle.length)
			defaultMapStyle = mapStyle;
	}
	
	
	
	var updateCurrVersion = function()
	{
		currCatalogVersion++;
	}
	
</script>
