/**
 * @name YandexClusterer for Yandex Maps.
 * @version 1.0.0 [August 13, 2011]
 * @author Alexander Shabunevich [http://aether.ru]
 * http://beholder.bitbucket.org/yandex.clusterer/
 *
 * Based on MarkerClustererPlus for Google Maps V3 by Gary Little
 */
function YandexCluster(a){this.mc=a;this.om=a.om;this.map=a.map;this.center=null;this.markers=[];this.bounds=null;this.min_size=a.min_size;this.style=a.style;this.point=null}function YandexClusterer(a,b,c){this.map=a;this.bounds=null;this.clusters=[];this.markers=b||[];this.zoom=null;this.map.YandexClusterer=this;this.om=new YMaps.ObjectManager;this.map.addOverlay(this.om);c=c||{};this.max_zoom=c.max_zoom||0;this.grid=c.grid||60;this.min_size=c.min_size||2;this.centered=c.centered||false;this.batch=c.batch||400;this.style=c.style||{icon:"http://www.kanzas.net.ua/usr_img/dom.png",height:32,width:32,offset:[0,0],textColor:"#000000",textSize:11,printable:false};if(this.map._yandexClustererEvents){for(event in this.map._yandexClustererEvents){this.map._yandexClustererEvents[event].cleanup()}}this.map._yandexClustererEvents={};this.map._yandexClustererEvents["update"]=YMaps.Events.observe(this.map,this.map.Events.Update,function(){this.repaint()},this);this.map._yandexClustererEvents["move"]=YMaps.Events.observe(this.map,this.map.Events.MoveEnd,function(){this.redraw()},this);this.repaint()}YandexClusterer.prototype.setMarkers=function(a){this.markers=a};YandexClusterer.prototype.clearMarkers=function(){var a=this.markers.length;while(a--){var b=this.markers[a];b.isAdded=false;if(b.isOnMap){b.isOnMap=false}}this.om.removeAll();a=this.clusters.length;while(a--){this.clusters[a].remove()}this.clusters=[]};YandexClusterer.prototype.repaint=function(){this.clearMarkers();this.redraw()};YandexClusterer.prototype.redraw=function(){this.createClusters(0)};YandexClusterer.prototype.createClusters=function(a){var b=this,c=a,d=this.markers.length,e=Math.min(a+this.batch,d);if(a===0){this.bounds=this.extendBounds(this.map.getBounds());this.zoom=this.map.getZoom();if(typeof this.timerRefStatic!=="undefined"){clearTimeout(this.timerRefStatic);delete this.timerRefStatic}}for(c;c<e;c++){var f=this.markers[c];if(!f.isAdded&&this.bounds.contains(f.getCoordPoint())){this.addToCluster(f)}}if(e<d){this.timerRefStatic=setTimeout(function(){b.createClusters(e)},0)}else{delete this.timerRefStatic;setTimeout(function(){b.updateClusterIcons()},0)}};YandexClusterer.prototype.extendBounds=function(a){var b=this.map.converter,c,d,e,f;c=b.coordinatesToMapPixels(a.getRightTop());c.x+=this.grid;c.y-=this.grid;d=b.coordinatesToMapPixels(a.getLeftBottom());d.x-=this.grid;d.y+=this.grid;e=b.mapPixelsToCoordinates(c);f=b.mapPixelsToCoordinates(d);return new YMaps.GeoBounds(f,e)};YandexClusterer.prototype.addToCluster=function(a){var b,c,d,e=this.clusters.length;var f=4e4;var g=null;while(e--){c=this.clusters[e];if(c.center){b=this.distanceBetween(c.center,a.getCoordPoint());if(b<f){f=b;g=c}}}if(g&&g.isMarkerInBounds(a)){g.addMarker(a)}else{c=new YandexCluster(this);c.addMarker(a);this.clusters.push(c)}};YandexClusterer.prototype.distanceBetween=function(a,b){var c=6371;var d=(b.getLat()-a.getLat())*Math.PI/180;var e=(b.getLng()-a.getLng())*Math.PI/180;var f=Math.sin(d/2)*Math.sin(d/2)+Math.cos(a.getLat()*Math.PI/180)*Math.cos(b.getLat()*Math.PI/180)*Math.sin(e/2)*Math.sin(e/2);var g=2*Math.atan2(Math.sqrt(f),Math.sqrt(1-f));var h=c*g;return h};YandexClusterer.prototype.updateClusterIcons=function(){var a=this,b=this.clusters.length,c=this.getMaxZoom(),d=this.map.getZoom();while(b--){var e=this.clusters[b];count=e.markers.length;if(d>=c){var f=e.markers.length;while(f--){var g=e.markers[f];if(!g.isOnMap){this.om.add(g,this.zoom,this.zoom);g.isOnMap=true}}continue}else if(count<this.min_size){var f=e.markers.length;while(f--){var g=e.markers[f];if(!g.isOnMap){this.om.add(g,this.zoom,this.zoom);g.isOnMap=true}}continue}else{var f=e.markers.length;while(f--){var g=e.markers[f];this.map.removeOverlay(g);g.isOnMap=false}}e.showIcon()}};YandexClusterer.prototype.getMaxZoom=function(){return this.max_zoom||this.map.getMaxZoom()};YandexCluster.prototype.addMarker=function(a){var b,c,d=this.map.getZoom();if(a.isAdded)return false;if(!this.center){this.center=a.getCoordPoint();this.bounds=this.calculateBounds()}else if(this.mc.centered){var e=this.markers.length+1,f=a.getCoordPoint();var g=(this.center.getLat()*(e-1)+f.getLat())/e;var h=(this.center.getLng()*(e-1)+f.getLng())/e;this.center=new YMaps.GeoPoint(h,g);this.bounds=this.calculateBounds()}a.isAdded=true;this.markers.push(a);return true};YandexCluster.prototype.calculateBounds=function(){var a=new YMaps.GeoCollectionBounds(this.center);return this.mc.extendBounds(a)};YandexCluster.prototype.isMarkerInBounds=function(a){return this.bounds.contains(a.getCoordPoint())};YandexCluster.prototype.showIcon=function(){var a=this,b=new YMaps.GeoPoint(this.center.getLng(),this.center.getLat());if(this.point){this.om.remove(this.point)}if(this.style.printable){var c=new YMaps.Template('<div style="cursor:pointer;position:relative;line-height:$[style.iconStyle.size.y]px;height:$[style.iconStyle.size.y]px;width:$[style.iconStyle.size.x]px;text-align:center"><img src="$[style.iconStyle.href]" alt="" style="position:absolute;left:0;top:0"><span style="position:relative;font-weight:bold;font-size:$[textSize|12]px;color:$[textColor|#000]">$[markersCount|0]</span></div>')}else{var c=new YMaps.Template('<div style="cursor:pointer;position:relative;line-height:$[style.iconStyle.size.y]px;height:$[style.iconStyle.size.y]px;width:$[style.iconStyle.size.x]px;text-align:center;background:url($[style.iconStyle.href]) no-repeat;font-weight:bold;font-size:$[textSize|12]px;color:$[textColor|#000]">$[markersCount|0]</div>')}var d=new YMaps.Style;d.iconStyle=new YMaps.IconStyle(c);d.iconStyle.href=this.style.icon;d.iconStyle.size=new YMaps.Point(this.style.width,this.style.height);d.iconStyle.offset=new YMaps.Point(this.style.offset);this.point=new YMaps.Placemark(b,{style:d,hasBalloon:false});this.point.markersCount=this.markers.length;this.point.textSize=this.style.textSize;this.point.textColor=this.style.textColor;YMaps.Events.observe(this.point,this.point.Events.Click,function(){this.map.setBounds(this.bounds);if(this.mc.getMaxZoom()<this.map.getZoom()){this.map.setZoom(this.mc.getMaxZoom()+1)}},this);var e=this.map.getZoom();this.om.add(this.point,e,e)};YandexCluster.prototype.remove=function(){this.markers=[];if(this.point){this.point=null}}
