
function ClusterManager()
{var mapStyle=null;var mapWidth=null;var mapHeight=null;var gridCells=new Array();var that=this;var emptyLatLong=new VELatLong(0,0).toString();var lastClusteredShapeType="";this.PoiPresent=false;this.ClusterLayer=new VEShapeLayer();this.ClusterLayersArray=new Array();this.ShapeArrays=new Array();this.ShapeTypes=new Array();this.MapInstance=null;this.Initialize=function(mapInstance)
{this.MapInstance=mapInstance;}
this.Update=function(e)
{if(!this.PoiPresent)
{return true;}
var currentStyle=mapManager.Map.GetMapStyle();if(mapStyle!=currentStyle)
{mapStyle=currentStyle;return true;}
if(mapWidth!=this.MapInstance.GetWidth()||mapHeight!=this.MapInstance.GetHeight())
{GenerateGrid();}
this.ClusterShapes();if(this.ShapeArrays.length==0)
{this.PoiPresent=false;}
HideLoading();return true;}
this.ClusterShapes=function(type)
{this.MapInstance.DeleteShapeLayer(this.ClusterLayer);var clusterOptions=new VEClusteringOptions();clusterOptions.Icon=new VECustomIconSpecification();clusterOptions.Icon.CustomHTML='<div class="clusterPin"><div class="clusterCount"></div></div>';this.ClusterLayer.DeleteAllShapes();this.ClusterLayer=new VEShapeLayer();var newClusterLayer=new VEShapeLayer();newClusterLayer.SetClusteringConfiguration(customCluster,clusterOptions);var shapes;for(var i=0;i<this.ShapeArrays.length;i++){shapes=new Array();shapes=this.ShapeArrays[i];for(var j=1;j<shapes.length;j++){newClusterLayer.AddShape(shapes[j],shapes[0]);}}
this.ClusterLayer=newClusterLayer;this.MapInstance.AddShapeLayer(this.ClusterLayer);HideLoading();}
this.DeleteClusterLayer=function(type){this.MapInstance.DeleteShapeLayer(this.ClusterLayer);}
this.GetClusterLayer=function(type){var clusterLayer=new VEShapeLayer();for(var i=0;i<this.ClusterLayers.length;i++){return clusterLayer[i];}}
function GetClusteredShapes(poiLayer)
{var clusterShapes=new Array();clusterShapes=poiLayer.GetClusteredShapes(VEClusteringType.Grid);return clusterShapes;}
function ValidateShape(shape)
{var result=true;if(shape==null||shape.Primitives.length<1||shape.GetPoints()[0].toString()==emptyLatLong)
{result=false;}
return result;}
this.SetShapes=function(shapes)
{this.ClearShapes();this.ShapeArrays=new Array();for(var i=0;i<shapes.length;i++)
{if(ValidateShape(shapes[i]))
{this.ShapeArrays[0].push(shapes[i]);}}}
this.AddShapes=function(shapes,type){if(shapes==null||shapes.length==0||this.typeDisplayed(type)){return;}
var shapeArray=new Array();shapeArray.push(type);var clusterOptions=new VEClusteringOptions();clusterOptions.Icon=new VECustomIconSpecification();clusterOptions.Icon.CustomHTML='<div class="clusterPin'+type+'"></div>';this.lastClusteredShapeType=type;clusterOptions.Callback=this.FormatClusterShapes;var clusterLayer=new VEShapeLayer();clusterLayer.SetClusteringConfiguration(customCluster,clusterOptions);for(var i=0;i<shapes.length;i++){if(ValidateShape(shapes[i])){shapeArray.push(shapes[i]);clusterLayer.AddShape(shapes[i]);}}
this.ShapeArrays.push(shapeArray);this.ShapeTypes.push(type);clusterLayerArray=new Array();clusterLayerArray.push(type);clusterLayerArray.push(clusterLayer);this.ClusterLayersArray.push(clusterLayerArray);this.MapInstance.AddShapeLayer(clusterLayer);HideLoading();}
this.FormatClusterShapes=function(clusters){var clusterShape;var clusterShapeSpec;var clusterShapeSpecHTML;var clusterLatLon;var clusterArray=new Array();var zoomLevel=mapManager.Map.GetZoomLevel();for(var i=0;i<clusters.length;i++){clusterArray=clusters[i].Shapes;clusterShape=clusters[i].GetClusterShape();clusterLatLon=clusters[i].LatLong;var descriptionArray=new Array();var descriptionKey=clusterArray[0].GetDescription();var descriptionAddressArray=new Array();var descriptionAddress;var descriptionImage=InfoBoxManager.GetImage(descriptionKey);var descriptionDirections;var description;var clusteredLatLonsArray=new Array();if(zoomLevel!=19){for(var j=0;j<clusterArray.length;j++){clusteredLatLonsArray.push('new VELatLong('+clusterArray[j].GetIconAnchor()+')');}
var clusteredLatLonsArrayString="new Array("+clusteredLatLonsArray.join(',')+")";for(var j=0;j<clusterArray.length;j++){descriptionKey=clusterArray[j].GetDescription();descriptionAddress=InfoBoxManager.GetAddress(descriptionKey);descriptionAddressArray=descriptionAddress.split('<br>');descriptionAddress=descriptionAddressArray[0];shapeID=clusterArray[j].GetID();descriptionArray.push(shapeID+'\')">'+descriptionImage+'</td><td style="padding-left:7px;"><span>'+InfoBoxManager.GetName(descriptionKey)+'</span><span>'+descriptionAddress);}
clusterShape.SetDescription('<div class="clusterDescription"><div style="font-weight: bold; font: 12px/14px Arial;"><table><tr><td style="cursor:pointer;" onclick="ShowNewEro(\''+(descriptionArray.join('</span></td></tr></table></div><br/><div style="font-weight: bold; font: 12px/14px Arial;"><table><tr><td style="cursor:pointer;" onclick="ShowNewEro(\''))+'</span></td></tr></table></div></div>');}else{for(var j=1;j<clusterArray.length;j++){descriptionArray.push(clusterArray[j].GetDescription().split('||')[1]);}
clusterShape.SetDescription(clusterArray[0].GetDescription()+'||'+(descriptionArray.join('||')));}
clusterShape.SetTitle('cluster');}}
this.GenerateDescription=function(key){var divHeight="170px";var topMargin="8px";var keys=key.split('||');var descriptionArray=new Array();var descriptionKey=(keys[0]+'||'+keys[1]);var descriptionAddressArray=new Array();var descriptionAddress;var descriptionImage=InfoBoxManager.GetImage(descriptionKey);for(var j=0;j<keys.length-1;j++){descriptionAddress=InfoBoxManager.GetAddress(descriptionKey);descriptionAddressArray=descriptionAddress.split('<br>');descriptionAddress=descriptionAddressArray[0];descriptionArray.push('<div style="font-weight: bold; font: 12px/14px Arial;"><table><tr><td>'+descriptionImage+'</td><td style="padding-left:7px;"><span>'+InfoBoxManager.GetName(descriptionKey)+'</span><span>'+descriptionAddress+'</span></td></tr></table></div>');descriptionKey=(keys[0]+'||'+keys[j+1]);}
key=descriptionKey;var poiImg=descriptionImage;var description='<div style="height: '+divHeight+';margin-top:'+topMargin+';">'
+'<div class="popupTop" style="overflow-y:auto; height:91%">'
+'<div class="popupTopLeft">'
+descriptionArray.join("<br/>")
+'</div>'
+'<div class="popupTopRight" style="width:53%">'
+'<div id=\"AP_ACTION_'+key+'\" class="popupActionArea" style="top:10px;">'
+'<div id=\"AP_EMPTY_'+key+'\" style="height:130px; width:100px;"></div>'
+'<div id=\"AP_TO_'+key+'\" style="height:130px;display:none;">'
+'<div class="popupHeader"><strong>'+resourceDD+':</strong></div><br/>'
+resourceToHere+':<br/>'
+'<input type="text" id="p_toAddress'+key+'" style="width:158px;" onkeydown="ExecuteFindFromInput(\'p_imgTo'+(key)+'\', event);"/><br/>'
+'<div><img id="p_imgTo'+key+'" src="'+images+'GetDD.gif" class="popupLink" style="left:100px; float: right;" onclick="POIManager.GDDForPOIPopup(\'TO\', \''+(key)+'\');" /></div>'
+'</div>'
+'<div id=\"AP_FROM_'+key+'\" style="height:130px;display:none;">'
+'<div class="popupHeader"><strong>'+resourceDD+': </strong></div><br/>'
+resourceFromHere+':<br/>'
+'<input type="text" id="p_fromAddress'+key+'" style="width:158px;" onkeydown="ExecuteFindFromInput(\'p_imgFrom'+(key)+'\', event);"/><br/>'
+'<div><img id="p_imgFrom'+(key)+'" src="'+images+'GetDD.gif" class="popupLink" style="left:100px; float: right;" onclick="POIManager.GDDForPOIPopup(\'FROM\', \''+(key)+'\');"/></div>'
+'</div>'
+'<div id=\"AP_NEAR_'+key+'\" style="height:130px;display:none;"><div class="popupHeader"><strong>'+resourceWhatsNearby+': </strong></div><br/>'
+'<div class="popupSubheader">'+resourceSearchForCategory+':<br/></div>'
+'<input type="text" id="p_nearby'+key+'" style="width:158px;" onkeydown="ExecuteFindFromInput(\'p_imgNear'+(key)+'\', event);"/><br/>'
+'<div style="float:left; width:110px">'+resourceWhatsNearbyExample+'</div>'
+'<div><img id="p_imgNear'+(key)+'" src="'+images+'GetDD.gif" class="popupLink" style="margin-top:11px; left:100px; float: right;" onclick="POIManager.GNBForPOIPopup(\''+(key)+'\');"/></div>'
+'</div>'
+'<div id=\"AP_MAP_'+key+'\" style="height:130px;display:none;">'
+'<div id=\"AP_MAP_SAVE_'+key+'\" style="display:none;">'
+'<div style="float:left;">'
+'<div class="popupHeader" style="width:110px"><strong>'+resourceSaveToAMap+': </strong></div><br />'
+'<div style="width:110px">'+resourceSaveToAMapPrompt+'</div>'
+'</div>'
+'<div><img src="Images/'+poiImg+'" class="popupLink" style="margin-right:10px; margin-top:10px; float: right; border: 1px solid black;" /></div>'
+'<div style="margin-top:10px;"><select id="mapSelect" style="width:158px;"></select><br/></div>'
+'<div><img id="p_imgAdd'+(key)+'" src="'+images+'doneButton.gif" class="popupLink" style="left:100px; float: right;" onclick="POIManager.SavePOIToCustomMap('+(key)+');"/></div>'
+'</div>'
+'<div id=\"AP_MAP_WARN_'+key+'\" style="float:left;display:none">'
+'<div class="popupHeader" style="width:110px"><strong>'+resourceSaveToAMap+': </strong></div><br />'
+'<div style="width:180px">'+resourceLoginNeeded+'</div>'
+'</div>'
+'</div>'
+'</div>'
+'</div>'
+'</div>'
+'<div class="popupBottom" style="padding-top:5px">'
+'<table><td><img src="images/drivingicon.gif" align="left" style="margin-right:3px;margin-left:3px"></img></td>'
+'<td>'+resourceDD.toUpperCase()
+'<div></div><span class="popupLink popupDrivingFunctionTo" onclick="YPSearchManager.ShowActionDiv(\'AP_\', \''+(key)+'\', \'FROM\');"><img src="images/tohereicon.gif"><span>'+resourceToHere.toUpperCase()+'</span></img></span> | '
+'<span class="popupLink popupDrivingFunctionFrom" onclick="YPSearchManager.ShowActionDiv(\'AP_\', \''+(key)+'\', \'TO\');"><img src="images/fromhereicon.gif"><span>'+resourceFromHere.toUpperCase()+'</span></img></span>'
+'</td>'
+'<td style="width:60px;margin-right:3px;"><span class="popupLink" onclick="YPSearchManager.ShowActionDiv(\'AP_\', \''+(key)+'\', \'NEAR\');"><img src="images/nearbyicon.gif" align="left" style="margin-right:3px"></img>'
+'<span class="popupLink">'+resourceWhatsNearby.toUpperCase()+'</div></span>'
+'</td>'
+'<td style="margin-right:3px; width:70px;"><span class="popupLink" onclick="YPSearchManager.ShowActionDiv(\'AP_\', \''+(key)+'\', \'MAP\');"><img src="images/savemapicon.gif" align="left" style="margin-right:3px;margin-left:3px"></img>'
+resourceAddToAMap.toUpperCase()+'</span>'
+'</td>'
+'</tr></table>'
+'</div>'
+'</div>';return description;}
this.DeleteShapes=function(type){if(this.typeDisplayed(type)){var newShapeArrays=new Array();var shapeArray=new Array();for(var i=0;i<this.ShapeArrays.length;i++){shapeArray=this.ShapeArrays[i];if(shapeArray[0]!=type){newShapeArrays.push(shapeArray);}}
var newClusterLayersArray=new Array();var clusterArray=new Array();for(var i=0;i<this.ClusterLayersArray.length;i++){clusterArray=this.ClusterLayersArray[i];if(clusterArray[0]!=type){newClusterLayersArray.push(clusterArray);}
else{this.MapInstance.DeleteShapeLayer(clusterArray[1]);}}
this.ShapeArrays=newShapeArrays;this.ClusterLayersArray=newClusterLayersArray;}
HideLoading();}
this.typeDisplayed=function(type)
{var shapeArray=new Array();for(var i=0;i<this.ShapeArrays.length;i++){shapeArray=this.ShapeArrays[i];if(shapeArray[0]==type){return true;}}
return false;}
this.DeleteAllShapes=function()
{this.ClearShapes();this.ShapeArrays=new Array();this.PoiPresent=false;}
this.ClearShapes=function()
{var gridSize=gridCells.length;this.ClusterLayer.DeleteAllShapes();gridCells=null;gridCells=new Array(gridSize)}
function GenerateLayer(shapes)
{var zoomLevel=that.MapInstance.GetZoomLevel();var xCells=parseInt(Math.ceil(mapWidth/gridSize));that.ClearShapes();for(var i=0;i<shapes.length;i++)
{var shape=shapes[i];var latLong=shape.GetPoints()[0];var pixel=that.MapInstance.LatLongToPixel(latLong);if(pixel.x<=mapWidth&&pixel.y<=mapWidth&&pixel.x>=0&&pixel.y>=0)
{var gridX=Math.floor(pixel.x/gridSize);var gridY=Math.floor(pixel.y/gridSize);var index=gridX+gridY*xCells;if(index<gridCells.length)
{if(gridCells[index]==null)
{gridCells[index]=new Array();}
gridCells[index].push(shape);}}}
for(var i=0;i<gridCells.length;i++)
{var cell=gridCells[i];var shape=null;if(cell!=null&&cell.length>1&&zoomLevel<minZoomLimit)
{var latLongs='';for(var shapeIndex=0;shapeIndex<cell.length;shapeIndex++)
{latLongs+=cell[shapeIndex].GetPoints()[0].toString().replace(' ','');latLongs+=(shapeIndex<=cell.length-2)?'|':'';}
shape=new VEShape(VEShapeType.Pushpin,cell[0].GetPoints()[0]);shape.SetTitle('cluster');shape.SetDescription(latLongs);shape.SetCustomIcon('<div class="clusterPin"><div class="clusterCount">'+cell.length+'</div></div>');this.ClusterLayer.AddShape(shape);}
else
{if(cell!=null&&cell.length>0)
{for(var shapeCount=0;shapeCount<cell.length;shapeCount++)
{this.ClusterLayer.AddShape(cell[shapeCount]);}}}}}
function GenerateGrid()
{mapWidth=that.MapInstance.GetWidth();mapHeight=that.MapInstance.GetHeight();var xCells=parseInt(Math.ceil(mapWidth/gridSize));var yCells=parseInt(Math.ceil(mapHeight/gridSize));gridCells=new Array(xCells*yCells);}
function ShapeToString(shape)
{var points=shape.GetPoints()[0];var result=points.Latitude+'|'+points.Longitude+'|'+shape.GetDescription()+'|'+shape.GetTitle+'|'+shape.GetCustomIcon();return result;}}
function deleteFromDist(distArray,allShapes,tmpIndex){var tmpx=Math.floor(allShapes[tmpIndex].x/10);var tmpy=Math.floor(allShapes[tmpIndex].y/10);for(var j=distArray[tmpx][tmpy].length-1;j>=0;j--){if(distArray[tmpx][tmpy][j]==tmpIndex){distArray[tmpx][tmpy].splice(j,1);j=-1;}}}
var totalx=0;var totaly=0;function customCluster(layer){var pins=new Array();var total=layer.GetShapeCount();var allShapes=new Array();totalx=Math.ceil(mapManager.Map.GetWidth()/10)+1;totaly=Math.ceil(mapManager.Map.GetHeight()/10)+1;var distArray=new Array(totalx);for(var i=totalx-1;i>=0;i--){distArray[i]=new Array(totaly);for(var j=totaly-1;j>=0;j--)
distArray[i][j]=new Array();}
for(var i=0;i<total;i++){allShapes[i]=layer.GetShapeByIndex(i);var tmp=mapManager.Map.LatLongToPixel(allShapes[i].GetPoints()[0]);allShapes[i].x=tmp.x;allShapes[i].y=tmp.y;var tmpArrayX=Math.floor(tmp.x/10);var tmpArrayY=Math.floor(tmp.y/10);if((tmpArrayX<0)||(tmpArrayX>=totalx)||(tmpArrayY<0)||(tmpArrayY>=totaly)){var tmpPin=new VEClusterSpecification();tmpPin.LatLong=new VELatLong(0,0);tmpPin.Shapes=new Array();while(total--){tmpPin.Shapes[total]=layer.GetShapeByIndex(total);}
pins.push(tmpPin);return pins;}
distArray[tmpArrayX][tmpArrayY].push(i);}
var maxValue=0;var maxShapes=new Array();var maxIndex=-1;var livingIndicesToAllShapes=new Array(total);var clusterValues=new Array(total);var tmpResult;for(var i=allShapes.length-1;i>=0;i--){livingIndicesToAllShapes[i]=i;tmpResult=singlePinCluster(i,distArray,allShapes);clusterValues[i]=[tmpResult[0],i,tmpResult[1]];}
while(clusterValues.length>0){clusterValues.sort(clusterValueSort);maxValue=-1;maxIndex=0;var i=0;var go=true;while(go){if(i>=clusterValues.length)
go=false;else{var tmp=singlePinCache(clusterValues[i][2],livingIndicesToAllShapes);if(tmp==1){clusterValues.splice(i,1);}else{if(tmp>maxValue){maxValue=tmp;maxIndex=i;}
if(tmp==clusterValues[i][0]){go=false;}
clusterValues[i][0]=tmp;i++;}}}
if(maxValue<=1)
return pins;maxShapes=clusterValues[maxIndex][2];var tmp=new VEClusterSpecification();tmp.LatLong=allShapes[clusterValues[maxIndex][1]].GetPoints()[0];livingIndicesToAllShapes=[];var i=clusterValues.length;while(i--){livingIndicesToAllShapes[clusterValues[i][1]]=i;}
var toDelete=new Array(maxShapes.length);i=maxShapes.length;while(i--){toDelete[i]=livingIndicesToAllShapes[maxShapes[i]];}
toDelete.sort(numSort);i=toDelete.length;while(i--){var tmpIndex=clusterValues[toDelete[i]][1];deleteFromDist(distArray,allShapes,tmpIndex);maxShapes[i]=allShapes[tmpIndex];clusterValues.splice(toDelete[i],1);livingIndicesToAllShapes[tmpIndex]=undefined;}
tmp.Shapes=maxShapes;pins.push(tmp);}
return pins;}
function clusterValueSort(a,b){return b[0]-a[0];}
function numSort(a,b){return a-b;};var clusterCompareDist=1600;function singlePinCluster(index,distArray,allShapes){var arrayX=Math.floor(allShapes[index].x/10);var arrayY=Math.floor(allShapes[index].y/10);var minX=(arrayX>4)?arrayX-4:0;var minY=(arrayY>4)?arrayY-4:0;var maxX=(arrayX<(totalx-4))?arrayX+4:totalx-1;var maxY=(arrayY<(totaly-4))?arrayY+4:totaly-1;var shapes=new Array();var value=0;var i=minX-1;while(i++<maxX){var j=minY-1;while(j++<maxY){if(((arrayX-i)*(arrayX-i))+((arrayY-j)*(arrayY-j))<=8){value+=distArray[i][j].length;Array.prototype.push.apply(shapes,distArray[i][j]);}else{for(var k=distArray[i][j].length-1;k>=0;k--){if(distBetween(allShapes[index],allShapes[distArray[i][j][k]])<=1600){value++;shapes.push(distArray[i][j][k]);}}}}}
return[value,shapes];}
function singlePinCache(cache,livingIndices){var value=0;for(var i=cache.length-1;i>=0;i--){if(livingIndices[cache[i]]==undefined){cache.splice(i,1);}else{value++;}}
return value;}
function singlePinCacheCluster(cache,livingIndices){var shapes=[];for(var i=cache.length-1;i>=0;i--){if(livingIndices[cache[i]]!=undefined)
shapes.push(cache[i]);}
return shapes;}
function singlePinValue(index,distArray,allShapes){var arrayX=Math.floor(allShapes[index].x/10);var arrayY=Math.floor(allShapes[index].y/10);var minX=(arrayX>4)?arrayX-4:0;var minY=(arrayY>4)?arrayY-4:0;var maxX=(arrayX<(distArray.length-4))?arrayX+4:distArray.length-1;var maxY=(arrayY<(distArray[arrayX].length-4))?arrayY+4:distArray[arrayX].length-1;var value=0;for(var i=minX;i<=maxX;i++){for(var j=minY;j<=maxY;j++){for(var k=distArray[i][j].length-1;k>=0;k--){if(distBetween(allShapes[index],allShapes[distArray[i][j][k]])<=clusterCompareDist)
value++;}}}
return value;}
function distBetween(shape1,shape2){var dx=shape1.x-shape2.x;var dy=shape1.y-shape2.y;return Math.floor((dx*dx)+(dy*dy));}