
var ChangeMapMarker = Class.create();
ChangeMapMarker.prototype = 
{
	initialize: function(markerName, longitude, latitude, icon, click, infoWindow, permanent, map)
	{
		this.Name 		= markerName;
	    this.Longitude 	= longitude;
	    this.Latitude 	= latitude;
	    this.Icon 		= icon;
	    this.Click 		= click;
	    this.InfoWindow = infoWindow;
	    this.Map		= map;
	    this.Permanent  = permanent;
	    
	    this.Position	= new GLatLng(this.Latitude, this.Longitude);
	    this.Marker  	= new GMarker(this.Position, this.Icon);
	    this.Displayed  = false;
	    this.WithinBoundries = this.isMarkerWithinBoundries();
	    this.RemainHidden = false;
	    
		//if (this.Click)
	    //	GEvent.addListener(this.Marker, 'click', function() {eval(this.Click)});
	
		if (this.InfoWindow)
            GEvent.addListener(this.Marker, 'click', this.showInfoWindow.bind(this));
	},
	
	remove: function()
	{
		// remove the existing overlay
	    GEvent.clearListeners(this.Marker, 'click');
		this.Map.removeOverlay(this.Marker);
	    this.Marker = null;
	},

	show: function(showMarker, fromBoundryChange)
	{
		if (true == fromBoundryChange && true == this.RemainHidden && this.Displayed == false)
			return;
			
		if (showMarker)
		{
			if (false == this.Displayed)
			{
				this.Map.addOverlay(this.Marker);
				this.Displayed = true;
			}
		}
		else
		{
			this.Map.removeOverlay(this.Marker);
			this.Displayed = false;
		}
	},
	
	showInfoWindow: function()
	{
		if (null != this.Marker && null != this.InfoWindow) {
            this.Marker.openInfoWindowHtml(this.InfoWindow);
        }
	},
	
	isMarkerWithinBoundries: function()
	{
		var ne = this.Map.getBounds().getNorthEast();
		var sw = this.Map.getBounds().getSouthWest();

		var max_long = ne.lng();
		var min_long = sw.lng();
		if(min_long > max_long) {
			min_long = min_long -360;
		} 
	
	    return this.Longitude <= max_long && this.Longitude >= min_long && this.Latitude <= ne.lat() && this.Latitude >= sw.lat();
	}
};

var ChangeMap = Class.create();
ChangeMap.prototype = 
{
	initialize: function(map, maxMarkersToShow, updateMarkersUrl)
	{
		this.Markers 	= new Array(maxMarkersToShow);
		this.MarkerIds 	= new Array(maxMarkersToShow);
		this.MarkersInBounds = new Array(maxMarkersToShow);
		this.NextPosition = 0;
		this.MarkerCount = 0;
		this.Icons = new $H();
		this.Map 	 = map;
		
		this.LastAjaxCall = 0;
		this.AjaxUpdateInterval = 2000;
		
		this.OnAddMarker = null;
		this.OnAjaxComplete = null;
		
		if (null != updateMarkersUrl)
			this.setUpdateMarkersUrl(updateMarkersUrl);
	},

	addIcon: function(name, imageUrl, shadowUrl, width, height, shadowWidth, shadowHeight, anchorX, anchorY, infoAnchorX, infoAnchorY)
	{
		var newIcon				= new GIcon();
		newIcon.image			= imageUrl;
		newIcon.shadow			= shadowUrl;
		newIcon.iconSize        = new GSize(width, height);
		newIcon.shadowSize      = new GSize(shadowWidth, shadowHeight);
		newIcon.iconAnchor      = new GPoint(anchorX, anchorY);
		newIcon.infoWindowAnchor= new GPoint(infoAnchorX, infoAnchorY);
		
		this.Icons[name] = newIcon;
	},

	getIcon:  function(name)
	{
		return this.Icons[name];
	},

	addMarker: function(markerId, longitude, latitude, icon, click, infoWindow, permanent)
	{
		if ('string' == typeof(icon))
			icon = this.getIcon(icon)	 
			
		var newMarker = null;
		var newMarkerPos = 0;
		
		if (this.isFull())
		{
			newMarker = this.getNextUndisplayedMarker();
			if (null == newMarker)
				return null;
			
			newMarkerPos = this.NextPosition;
			newMarker.remove();
			newMarker.initialize(markerId, longitude, latitude, icon, click, infoWindow, permanent, this.Map);
			newMarker.show(true);
		}
		else
		{
			newMarker = new ChangeMapMarker(markerId, longitude, latitude, icon, click, infoWindow, permanent, this.Map);
			newMarkerPos = this.MarkerCount;
			this.Markers[this.MarkerCount++] = newMarker;
			newMarker.show(true);
		}
		
		if (this.OnAddMarker && 'function' == typeof(this.OnAddMarker))
			this.OnAddMarker(newMarker);
	
		this.MarkerIds[newMarkerPos] = newMarker.Name;
	},

	loadAjax: function(d)
	{
		if (null == d || null == d.responseText)
			return;
		
		var results = d.responseText;
			
		var ajaxDelim1 = '^^^';
		var ajaxDelim2 = '~~~';
		
		if (null == results)
			return false;
	            
	    var marks = results.split(ajaxDelim1);
	    if (marks != null && marks.length > 0)
	    {
	    	for (var i=0; i < marks.length; ++i)
	    	{
	    		var info = marks[i].split(ajaxDelim2);
	        	this.addMarkerFromAjax(info);
	    	}
	    }
	    
		if (this.OnAjaxComplete && 'function' == typeof(this.OnAjaxComplete))
			this.OnAjaxComplete(d);
	},
	
	getNextUndisplayedMarker: function()
	{
		if (this.isEmpty())
			return null;
			
		for (var i=this.NextPosition; i<this.Markers.length; ++i)
		{
			if (null != this.Markers[i] && this.Markers[i].WithinBoundries == false)
			{
				this.NextPosition = i;
				return this.Markers[i];
			}
		}
		
		for (var i=0; i<this.NextPosition; ++i)
		{
			if (null != this.Markers[i] && this.Markers[i].WithinBoundries == false)
			{
				this.NextPosition = i;
				return this.Markers[i];
			}
		}
		
		return null;
	},

	addMarkerFromAjax: function(data)
	{
		if (null == data || data.length < 5)
			return;
			
		var markerId = data[0];
	    var lat = data[1];
	    var lon = data[2];
	    var icon = this.getIcon(data[3]);
	    var infoWindow = data[4];
	    
	    if (null == markerId)
	    	return;
	    
	    this.addMarker(markerId, lon, lat, icon, null, infoWindow);
	},

	isFull: function()
	{
		return this.MarkerCount == this.Markers.length;
	},

	setUpdateMarkersUrl: function(url)
	{
		this.UpdateMarkersUrl = url;
		
		GEvent.clearListeners(this.Map, 'moveend');
		GEvent.clearListeners(this.Map, 'resize');
		
		GEvent.addListener(this.Map, 'moveend', this.coordinatesChanged.bind(this));
	  	GEvent.addListener(this.Map, 'resize', this.coordinatesChanged.bind(this));
	},
	
	refreshMarkersInBounds: function()
	{
		this.MarkersInBounds.clear();
		
		if (this.isEmpty())
			return;
			
		for (var i=0; i<this.MarkerCount; ++i)
		{
			this.Markers[i].WithinBoundries = this.Markers[i].isMarkerWithinBoundries();
			if (this.Markers[i].WithinBoundries)
				this.MarkersInBounds[this.MarkersInBounds.length] = this.Markers[i];
		}
		this.MarkersInBounds.compact();
	},
	
	showOnlyMarkersInBounds: function()
	{
		if (this.isEmpty())
			return;
			
		for (var i=0; i<this.MarkerCount; ++i)
			this.Markers[i].show(this.Markers[i].WithinBoundries, true);
	},
	
	isEmpty: function()
	{
		return null == this.Markers || null == this.Markers[0];
	},
	
	coordinatesChanged: function(e)
	{
		this.refreshMarkersInBounds();
		this.showOnlyMarkersInBounds();
		var curTime = (new Date()).getTime();
		
		if (this.LastAjaxCall == 0)
			this.LastAjaxCall = curTime;
		else
		{
			if ((curTime - this.LastAjaxCall) < this.AjaxUpdateInterval)
				return;

			this.LastAjaxCall = curTime;
		}
		
		var zoom = this.Map.getZoom();
		var ne = this.Map.getBounds().getNorthEast();
		var sw = this.Map.getBounds().getSouthWest();
	
	    var h = $H();
	    h.set('longitude_left', sw.lng());
	    h.set('longitude_right', ne.lng());
	    h.set('latitude_top', ne.lat());
	    h.set('latitude_bottom', sw.lat());
	    h.set('existing_markers', this.rtrim(this.MarkerIds.join(','), ','));
	    h.set('max_makers_to_get', this.Markers.length - this.MarkersInBounds.length);
		    
	    var url = this.UpdateMarkersUrl+'?'+h.toQueryString();

	    var p = new Ajax.Request(url, {asynchronous:true, onSuccess: this.loadAjax.bind(this)});
	},
	
	rtrim: function(s, c) 
	{
		if (null == s)
			return s;
			
		for(var i=s.length-1; i>=0 && c==s.charAt(i); i--);
		return s.substring(0, i+1);
	}
};