/**
 * Engine for outputing markers from input object
 */
HYSMaps.InputPlotter = function () {};

HYSMaps.InputPlotter.prototype.plot = function (map, markers) {

	var result = [];
	for (var i in markers) {
		// get marker coordinates
		var split = i.split(',');
		var coords = new HYSMaps.GeoCoords(split[0], split[1]);
		result.push(markers[i]);
	}
	return result;
};

HYSMaps.InputPlotter.prototype.onEndZoom = function (map) {};
HYSMaps.InputPlotter.prototype.onEndPan= function (map) {};

/**
 * Engine for outputing markers from marker object
 */
HYSMaps.MarkerPlotter = function () {};

HYSMaps.MarkerPlotter.prototype.plot = function (map, markers, bounds) {

	return markers;
};

HYSMaps.MarkerPlotter.prototype.onEndZoom = function (map) {};
HYSMaps.MarkerPlotter.prototype.onEndPan= function (map) { };


/**
 * Engine for outputing clustered markers from marker object
 */
HYSMaps.ClusterPlotter = function () {};

HYSMaps.ClusterPlotter.prototype.plot = function (map, markers, bounds, pixelsPerDegree) {
	
	// create grid
	var grid = 
	{
		occupied: { names: [], cells: [] }, // to hold non-empty grid cell objects
		unoccupied: new HYSMaps.ClusterGrid,
		factor: HYSMaps.clustering.grid / pixelsPerDegree // Scaling factor for cell size
	}
	
	// inspect marker positions and assign to grid cells
	for (var i in markers) 
	{	
		// delete if it's a cluster
		if (markers[i].HYSEvents.isCluster) {
			continue;
		}
		
		// Non-grouped markers are stored seperately
		// 24/7/08: At max zoom, clustering is disabled
		if (map.zoomLevel == HYSMaps.zoom.maximum || markers[i].HYSEvents.grouped == false)
		{
			// Assign this marker to the series pile
			grid.unoccupied.add(i, markers[i]);
			continue;
		}
		
		// get marker coordinates
		var split = i.split(',');
		var coords = new HYSMaps.GeoCoords(split[0], split[1]);
		
		// ensure it is within the visible bounds of the map
		if (bounds.contains(coords))
		{
			// Calculate grid coordinates based on lat/lon 
			var columns = Math.floor((coords.latitude / grid.factor));
			var rows = Math.floor((coords.longitude / grid.factor));

			// Generate a unique array key
			var szAddress = columns + "," + rows;

			// Make indexes as needed
			if (!grid.occupied.cells[szAddress])
			{
				grid.occupied.cells[szAddress] = new HYSMaps.ClusterGrid(); // setup grid cell arrays;	
				grid.occupied.names.push(szAddress);
			}
			
			// assign it to the grid cell
			grid.occupied.cells[szAddress].add(i, markers[i]);
		}
	}
	
	var clustered = {};
	
	for (var i = 0; i < grid.occupied.names.length; i++)
	{							
		for (var j in grid.occupied.cells[grid.occupied.names[i]].markers) 
		{
			if (grid.occupied.cells[grid.occupied.names[i]].length > HYSMaps.clustering.threshold) 
			{	
				var split = j.split(',');
				var coords = new HYSMaps.GeoCoords(split[0], parseFloat(split[1]) + 0.001);
				var cluster = map.makeMarker(coords, new HYSMaps.ClusterIcon('icon-cluster.png'));
				cluster.HYSEvents.isCluster = true;
				map.bind(cluster, 'mouseup', this, this.onClick);
				clustered[coords] = cluster;
				break;
			}
			clustered[j] = grid.occupied.cells[grid.occupied.names[i]].markers[j];
		}
	}
	
	
	// Add non-clustered  markers
	for (var j in grid.unoccupied.markers) 
	{
		clustered[j] = grid.unoccupied.markers[j];
	}
	
	
	return clustered;			
};

HYSMaps.ClusterPlotter.prototype.onClick = function (map, event) {
	
	map.setCentre(new HYSMaps.GeoCoords(event.latitude, event.longitude), '+1');
};

HYSMaps.ClusterPlotter.prototype.onEndZoom = function (map) {
	
	map.redraw();
};

HYSMaps.ClusterPlotter.prototype.onEndPan= function (map) {
	
	map.redraw();
};

HYSMaps.ClusterGrid = function () {
	
	this.markers = {};
	this.length = 0;
};

HYSMaps.ClusterGrid.prototype.add = function (id, marker) {
	
	this.markers[id] = marker;
	this.length++;
};