/**
 * A simple Clusterer:
 * Cluster 2 markers, if their icon overlap.
 * 
 * openInfoWindow(id) can be used, to show the infowindow of a marker, even if 
 *                    it is in a cluster now.
 *
 * hasId(id)          returns true if this marker id is already in the manager
 */

function ClusterManager(map, clusterIcon) {
  this.map         = map;
  this.clusterIcon = clusterIcon;
  this.onMap       = $H();
  this.clustered   = $H();
  this.unClustered = $H();
  this.threshold   = 10;
}

ClusterManager.prototype.addMarker = function(marker) 
{
  // check if already there.
  if(this.onMap.get(marker.id)) return;   
  this.onMap.set(marker.id, true);
  
  // not clustered
  var isClustered = false;
  
  
  // cluster with unClustered?
  this.unClustered.each(function (p) {      
      var point  = this.map.fromLatLngToDivPixel(p.value.overlay.getLatLng());
      var bounds = new GBounds([new GPoint(point.x - 10, point.y - 15),
                                new GPoint(point.x + 10, point.y + 15)]);
      if(bounds.containsPoint(this.map.fromLatLngToDivPixel(marker.overlay.getLatLng()))) {
        // form a new cluster
        var cluster = new Cluster(p.value, this.map, this.clusterIcon);
        cluster.add(marker);
        this.clustered.set(cluster.getId(), cluster);
        // remove marker we clustered with;
        this.unClustered.unset(p.value.id);
        this.map.removeOverlay(p.value.overlay);
        isClustered = true;
        throw $break;
      }
  }, this);
  
  if(!isClustered) {
    // cluster with Clustered?
    this.clustered.each(function (p) {
        var point  = this.map.fromLatLngToDivPixel(p.value.getLatLng());
        var bounds = new GBounds([new GPoint(point.x - 10, point.y - 15),
                                  new GPoint(point.x + 10, point.y + 15)]);
        if(bounds.containsPoint(this.map.fromLatLngToDivPixel(marker.overlay.getLatLng()))) {
          // add to cluster
          this.clustered.get(p.value.id).add(marker);
          isClustered = true;
          throw $break;
        }
    }, this);
  }
  
  if(!isClustered) {
    this.unClustered.set(marker.id, marker);
    this.map.addOverlay(marker.overlay);
  }
}


ClusterManager.prototype.removeMarker = function() 
{
  if(!this.onMap.get(marker.id)) return; 
  this.onMap.unset(marker.id);  
  if(this.unClustered.get(marker.id)) {
    this.unClustered.unset(marker.id);
    this.map.removeOverlay(marker.overlay);
  }
}

ClusterManager.prototype.clearMarkers = function() 
{
  this.unClustered = $H();
  this.clustered   = $H();
  this.onMap       = $H();
  this.map.clearOverlays();
}


ClusterManager.prototype.openInfoWindow = function(id) 
{
  var marker = null;
  if(marker = this.unClustered.get(id)) {
    GEvent.trigger(marker.overlay, "mouseover");
  } else {
    this.clustered.each(function(c) {
        if(c.value.ids.indexOf(id) != -1) {
          c.value.openInfoWindow(id);          
          throw $break;
        }
    });
  }
}


ClusterManager.prototype.hasId = function(id) 
{
  return this.onMap.get(id);
}


ClusterManager.prototype.strip = function(bounds, callback) 
{  
  this.unClustered.each(function (p) {    
      if(!bounds.contains(p.value.overlay.getLatLng())) {
        var id = p.value.id;
        this.map.removeOverlay(this.unClustered.get(id).overlay);
        this.onMap.unset(id);
        this.unClustered.unset(id);
        callback(id);
      }
  }, this);
  this.clustered.each(function (p) {    
      if(!bounds.contains(p.value.getLatLng())) {
        // remove all articles in this cluster
        p.value.ids.each(function (id) {
            this.onMap.unset(id);
            callback(id);
        }, this);        
        this.clustered.unset(p.value.id);
        this.map.removeOverlay(p.value.overlay);        
      }
  }, this);
}