function fix(number, places)
{
	var multiplier = Math.pow(10, places);

	number = Math.round(number * multiplier) / multiplier;

	return number;
}


function Map()
{
	this.borderPadding	= 0.25;
	this.mapId 			= 'map';
	this.zoom 			= 10;
	this.lat			= 0;
	this.lng			= 0;
	this.getPlacesUrl 	= false;
	this.getLocationUrl	= false;
	this.iconPath 		= '';
	this.showTabs 		= false;
	this.loadOnMove		= true;
	this.canDrag		= true;
	this.showInfoBoxes	= true;
	this.showControl	= false;
	
	var markers			= [];
	var markerSets 		= [];
	var newMarkers	 	= [];
	var typeSettings	= [];
	var typeStatus		= [];
	var map				= false;
	var bounds			= false;
	var manager			= false;
	var lngSpan 		= 1;
	var latSpan 		= 1;
	
	var searchZoom		= null;
	var activeKey		= false;
	
	
	var that = this;
	
	this.load = function()
	{
	    if(GBrowserIsCompatible())
		{
			map = new GMap2(document.getElementById(that.mapId)); 
			map.setCenter(new GLatLng(that.lat, that.lng), this.zoom);
			manager = new GMarkerManager(map); 

			if (that.loadOnMove)
			{
				GEvent.addListener(map, "moveend", function() { 
			    	that.updatePosition();
				});
			}
			
			/*
			GEvent.addListener(manager, "changed", function() { 
			    that.updateTypes();
			});
			*/

			if (that.showControl)
			{
				map.addControl(new GLargeMapControl());
			}
			
			if (!that.canDrag)
			{
				map.disableDragging();
			}
			
			that.updatePosition();
		}
	}
	
	
	this.updatePosition = function ()
	{
		if (!that.getPlacesUrl)
		{
			return false;
		}
		
		bounds = map.getBounds();

		var southWest = bounds.getSouthWest();
		var northEast = bounds.getNorthEast();
		lngSpan = northEast.lng() - southWest.lng();
		latSpan = northEast.lat() - southWest.lat();

		southWest = new GLatLng(southWest.lat() - (latSpan *  this.borderPadding), southWest.lng() - (lngSpan *  this.borderPadding));
		northEast = new GLatLng(northEast.lat() + (latSpan *  this.borderPadding), northEast.lng() + (lngSpan *  this.borderPadding));
		
		bounds = new GLatLngBounds(southWest, northEast);
	
		
		url = 	that.getPlacesUrl
				+ '?sw_lat=' + fix(bounds.getSouthWest().lat(), 5)
				+ '&sw_lng=' + fix(bounds.getSouthWest().lng(), 5)
				+ '&ne_lat=' + fix(bounds.getNorthEast().lat(), 5)
				+ '&ne_lng=' + fix(bounds.getNorthEast().lng(), 5)
				+ '&zoom=' + map.getZoom();
	
		GDownloadUrl(url, that.processResponse);
						
	}
	
	this.processResponse = function (response)
	{
		var currentMarkers = [];
		
		var places = eval('(' + response + ')');
		
		if (places.message)
		{
		    places = places.message;
        }

		for (key in places) 
		{
			type = 'Default';
			place = places[key];
			place.key = key;
			
			if (null != place.type)
			{
				type = place.type;
			}
			
			if (!markers[key])
			{	
				marker = that.createMarker(place);
				
				if (!markerSets[type])
				{
					typeStatus[type] = true;
					markerSets[type] = new Array();
				}
				
				if (typeStatus[type])
				{
					markers[key] = marker;
					
					if (!newMarkers[type])
					{
						newMarkers[type] = new Array();
					}
					
					newMarkers[type].push(marker);
				}
				
				markerSets[type][key] = marker;
				
			}
			
			if (!currentMarkers[type])
			{
				currentMarkers[type] = new Array();
			}
			
			currentMarkers[type][key] = place.name;
			
		}

		if (that.showTabs)
		{
			updateContentTabs(currentMarkers);
		}
		
		that.addNewMarkers();
		if (activeKey)
		{
			showOverlay(activeKey);
		}
	}
	
	this.addNewMarkers = function ()
	{
		var addedMarkers = false;
		
		for (type in newMarkers)
		{	
			if ('function' != typeof newMarkers[type] && newMarkers[type].length > 0)
			{
				manager.addMarkers(newMarkers[type], that.getTypeValue(type, 'minZoom'), that.getTypeValue(type, 'maxZoom'));
				addedMarkers = true;
			}
		}
	
		if (addedMarkers)
		{
			manager.refresh();
		}
		
		newMarkers = [];
	}
	
	
	
	
	this.locationSearch = function (location, zoom)
	{
		searchZoom = zoom;
		GDownloadUrl(that.getLocationUrl + '?q=' + escape(location), that.locationResponse);
	}
	
	this.locationResponse = function (response)
	{
		var location = eval('(' + response + ')');
		
		if (location['result'])
		{
			var point = new GLatLng(location['lat'], location['long']);
			
			if (!searchZoom && location['zoom'])
			{
				searchZoom = location['zoom'];
			}
			
			if (location['key'])
			{
				activeKey = location['key'];
			}
			
			map.setCenter(point, searchZoom);
		}
		else
		{
			alert('Could not find location "' + location['name'] + '"');
		}
		
		searchZoom = null;
		
	}
    
	this.getTypeStatus = function (type)
	{
		return typeStatus[type];
	}
	
	this.updateTypes = function ()
	{
		for (type in typeStatus)
		{	
			if (false === typeStatus[type])
			{
				that.hideType(type);
			}
		}
	}
	
	this.toggleType = function (type)
	{
		if (typeStatus[type])
		{
			that.hideType(type);
		}
		else
		{
			that.showType(type);
		}
		return false;
	}
	

	
	this.showType = function (type)
	{	
		if (!markerSets[type])
		{
			return;
		}
		
		typeStatus[type] = true;
		
		for (key in markerSets[type])
		{
			marker = markerSets[type][key];
			
			if ('function' != typeof marker)
			{	
				marker.show();
			}
		}
	}
	
	this.hideType = function (type)
	{
	
		if (!markerSets[type])
		{
			return;
		}
		
		typeStatus[type] = false;
		
		for (key in markerSets[type])
		{
			marker = markerSets[type][key];
			
			if ('function' != typeof marker)
			{	
				marker.hide();
			}
		}
	}
	
	
	this.createMarker = function (place)
	{
		
		var marker = new GMarker(new GLatLng(place.lat, place.lng), { icon: this.getTypeValue(place.type, 'icon') });
		marker.place = place;
		
		if (that.showInfoBoxes)
		{
		    var evt = false;
		    if (this.getTypeValue(place.type, 'click')) {
		        evt = 'click';
            } else if (this.getTypeValue(place.type, 'mouseover')) {
                evt = 'mouseover';
            } else if (this.getTypeValue(place.type, 'mouseout')) {
                evt = 'mouseout';
            }
            
            if (false !== evt){
			    GEvent.addListener(marker, evt, this.getTypeValue(place.type, evt));
            }
		}
		
		return marker;
	}
	
	this.addMarker = function (lat, lng, type) {
		var place = new Object();
		place.lat = lat;
		place.lng = lng;
		place.type = type;
		var marker = that.createMarker(place);
		manager.addMarker(marker, 0, 17);
	}
	
	this.setTypeDefault = function (key, value)
	{
		this.setTypeValue('Default', key, value);
	}
	
	this.setTypeValue = function (type, key, value)
	{
		if (!typeSettings[type])
		{
			typeSettings[type] = [];
		}
		
		typeSettings[type][key] = value;
	}
	
	this.getTypeValue = function (type, key)
	{
		if (typeSettings[type] && null != typeSettings[type][key])
		{
			return typeSettings[type][key];
		}
		else if (typeSettings['Default'] && null != typeSettings['Default'][key])
		{
			return typeSettings['Default'][key]
		}
		
		return null;
	}
	
	this.addOverlay = function(overlay)
	{
		return map.addOverlay(overlay);
	}
	
	this.getMap = function()
	{
		return map;
	}
	
	this.getMarker = function(key)
	{
		return markers[key];
	}
	
	this.getMarkers = function()
	{
	    return markers;
    }
    
    this.getManager = function()
    {
        return manager;
    }
	
	this.getLngSpan = function()
	{
		return lngSpan;
	}
	
	this.getLatSpan = function()
	{
		return latSpan;
	}
	
	this.setCenter = function(lat, lng, zoom)
	{
		var point = new GLatLng(parseFloat(lat), parseFloat(lng));
		if (zoom)
		{
			zoom = parseInt(zoom);
		}
		map.setCenter(point, zoom);
	}
	
	this.setActiveKey = function (key)
	{
		activeKey = key;
	}
	
	this.addControl = function(control)
	{
	    map.addControl(control);
    }
	
}


