function BaseMap(element, width, height, exportPath, basetoolUpload, linkurl, clustered, lang, basetoolUser, showDirections, directionsElement)
{
	/* DECLARATION */
	var _Directions;
	var _DirectionsElement;
	var _ExportPath = exportPath;
	var _MarkersMax = 250;
	var _LoadingControl = new LoadingControl();
	var _BasetoolUpload = basetoolUpload;
	var _LinkUrl = linkurl;
	var _Lang = lang;
	var _BasetoolUser = basetoolUser;
	var _Geocoder = new GClientGeocoder();
	var _IsExpanded = true;	

	var _Icon = new GIcon();
	_Icon.image = "/googlemaps/images/marker.png";
	_Icon.shadow = "http://www.google.com/intl/en_ALL/mapfiles/shadow50.png";
	_Icon.iconSize = new GSize(20, 34);
	_Icon.shadowSize = new GSize(37, 34);
	_Icon.iconAnchor = new GPoint(9, 34);
	_Icon.infoWindowAnchor = new GPoint(9, 2);
	_Icon.infoShadowAnchor = new GPoint(18, 25);
		
	this.Translate = new Object();
	this.Clustered = clustered;
	this.ErrorControl = new ErrorControl();
	//this.WeatherControl = new WeatherControl();
	
	this.SetCenter = SetCenter;
	this.Search = Search;
	this.Mark = Mark;
	this.Geocode = Geocode;
	this.ShowError = ShowError;
	this.ShowWeather = ShowWeather;
	this.LoadDirections = LoadDirections;
	this.ClearDirections = ClearDirections;
	this.QueryDirections = QueryDirections;		
	
	/*--------------- CONSTRUCT ---------------------*/			
	this.Map = new GMap2(element);
	
	if (height <= 300)
	{
		this.Map.addControl( new GSmallZoomControl());
	}
	else
	{
		this.Map.addControl(new GLargeMapControl());	
	}
	
	if (this.Clustered)
	{
		this.Cluster = new Clusterer(this.Map);
		this.Cluster.SetMaxVisibleMarkers(2);
		this.Cluster.SetMinMarkersPerCluster(2);
	}
	
	if (showDirections)
	{
		_DirectionsElement = document.getElementById(directionsElement);
		_Directions = new GDirections(this.Map, _DirectionsElement);
		GEvent.addListener(_Directions, "load", CreateMethodReference(this, Directions_Load));		
		GEvent.addListener(_Directions, "error", CreateMethodReference(this, Directions_Error));
	}
	
	//this.Map.addControl( this.WeatherControl );
	//GEvent.addListener(this.WeatherControl, "timeset", CreateMethodReference(this, WeatherControl_Callback));
	/* ------------------ /CONSTRUCT ----------------- */

	/*------------------- LOAD LANG ------------------ */
	this.Map.addControl(_LoadingControl);
	
	var xmlLang = _Lang;
	if (xmlLang == "se")
		xmlLang = "sv";
	GDownloadUrl("/googlemaps/lang/" + xmlLang + ".xml", CreateMethodReference(this, Lang_Callback));
	
	function Lang_Callback(data, responseCode)
	{
		var xml;		
		if (responseCode == 200)
		{
			xml = GXml.parse(data);
			this.Translate.QueryDirections = xml.documentElement.getElementsByTagName("querydirections")[0].childNodes[0].data;
			this.Translate.WeatherError = xml.documentElement.getElementsByTagName("weathererror")[0].childNodes[0].data;
			this.Translate.GeocodeError = xml.documentElement.getElementsByTagName("geocodeerror")[0].childNodes[0].data;
			this.Translate.SearchError = xml.documentElement.getElementsByTagName("searcherror")[0].childNodes[0].data;
			this.Translate.SearchNoHits = xml.documentElement.getElementsByTagName("searchnohits")[0].childNodes[0].data;
			this.Translate.SearchToManyHits = xml.documentElement.getElementsByTagName("searchtomanyhits")[0].childNodes[0].data;
			this.Translate.ReadMore = xml.documentElement.getElementsByTagName("readmore")[0].childNodes[0].data;
			this.Translate.DirectionsHere = xml.documentElement.getElementsByTagName("directionshere")[0].childNodes[0].data;
			this.Translate.DirectionsUnknownAddress = xml.documentElement.getElementsByTagName("directionsunknownaddress")[0].childNodes[0].data;
			this.Translate.DirectionsError = xml.documentElement.getElementsByTagName("directionserror")[0].childNodes[0].data;
		}		
		this.Map.removeControl(_LoadingControl);
	}
	/*------------------- /LOAD LANG ----------------- */				
	
	/* PUBLIC METHODS */
	function SetCenter(lat, lng, zoom)
	{
		this.Map.setCenter(new GLatLng(lat, lng), zoom);
	}
	
	function Search(areaId, categoryId, siteId, nameNo, areaName, text, serviceId, stars, inBounds, count)
	{
		var lngN = '0', lngS = '0', latW = '0', latE = '0';
		
		if (inBounds)
		{
			bounds = this.Map.getBounds();
			lngN = bounds.getNorthEast().lng();
			lngS = bounds.getSouthWest().lng();
			latW = bounds.getSouthWest().lat();
			latE = bounds.getNorthEast().lat();
		}
		
		if (count == undefined || count == 0)
			count = _MarkersMax;
			
		this.Map.addControl(_LoadingControl);
		
		GDownloadUrl(_ExportPath + "/proxy.aspx?a=" + areaId + "&c=" + categoryId + "&s=" + siteId + "&n=" + nameNo + "&an=" + areaName + "&q=" + text + "&se=" + serviceId + "&r=" + stars + "&i=" + count + "&lngn=" + lngN + "&lngs=" + lngS + "&latw=" + latW + "&late=" + latE + "&l=" + _Lang + "&u=" + _BasetoolUser, CreateMethodReference(this, Search_Callback));	
	}
	
	function Mark(lat, lng, zoom, categoryId, clear)
	{		
		if (clear)
			this.Map.clearOverlays();			
		
		this.SetCenter(lat, lng, 8);

		var marker = new GMarker(new GLatLng(lat, lng))		
		this.Map.addOverlay(marker);
	}
	
	function Geocode(address)
	{
		_Geocoder.getLatLng(address, CreateMethodReference(this, Geocode_Callback));
	}
	
	function ClearDirections()
	{
		if (!_IsExpanded)
		{
			var width = parseInt(this.Map.getContainer().style.width);
			this.Map.getContainer().style.width = (width + 210) + "px";
			this.Map.checkResize();
			_IsExpanded = true;
		}
		_DirectionsElement.style.display = "none";
		_Directions.clear();
	}
	
	function QueryDirections(lat, lng)
	{
		var from = prompt(this.Translate.QueryDirections, "");
		if (from != null)
			this.LoadDirections('from: ' + from + ' to:' + lat + ' ' + lng);
	}
	
	function LoadDirections(query)
	{
		this.Map.addControl(_LoadingControl);
		_Directions.load(query, {"locale": _Lang});
	}
	
	function ShowWeather()
	{	
		this.Map.clearOverlays();		
		var d = 0;
		if (arguments.length > 0)
			d = parseInt(arguments[0]);
		this.Map.addControl(_LoadingControl);			
		GDownloadUrl("/smhi/weather.aspx?d=" + d, CreateMethodReference(this, ShowWeather_Callback));	
	}
	
	/* PRIVATE METHODS */		
	function Directions_Load()
	{
		this.Map.removeControl(_LoadingControl);
		if (_IsExpanded)
		{
			var width = parseInt(this.Map.getContainer().style.width);
			this.Map.getContainer().style.width = (width - 210) + "px";
			this.Map.checkResize();
			_IsExpanded = false;
		}
		_DirectionsElement.style.display = "block";
	}
	
	function Directions_Error()
	{
		this.Map.removeControl(_LoadingControl);
		if (_Directions.getStatus().code == G_GEO_UNKNOWN_ADDRESS)
			this.ShowError(this.Translate.DirectionsUnknownAddress);
		else
			this.ShowError(this.Translate.DirectionsError);
	}
	
	function WeatherControl_Callback()
	{
		this.ShowWeather(this.WeatherControl.ActiveTime / 4);
	}
	
	function ShowWeather_Callback(data, responseCode)
	{
		var xml, areas;
		
		if (responseCode == 200)
		{
			xml = GXml.parse(data);
			areas = xml.documentElement.getElementsByTagName("area");
		}
		else
		{
			this.Map.removeControl(_LoadingControl);
			this.ShowError(this.Translate.WeatherError);
			return;
		}
		
		var period = (this.WeatherControl.ActiveTime % 4);
		try
		{
			var time = areas[0].childNodes[period].getAttribute("time");
			this.ShowError(time);
		}
		catch (ex) {}
		
		for (var i = 0; i < areas.length; i++)
		{
			var lat = parseFloat(areas[i].getAttribute("lat"));
			var lng = parseFloat(areas[i].getAttribute("lng"));
			if (areas[i].childNodes.length <= period)
				period = areas[i].childNodes.length - 1;
			var icon = areas[i].childNodes[period].getElementsByTagName("icon")[0].getAttribute("url");
			var windspeed = areas[i].childNodes[period].getElementsByTagName("wind")[0].getAttribute("speed");
			var temp = areas[i].childNodes[period].getElementsByTagName("temp")[0].childNodes[0].data;
			this.Map.addOverlay(new WeatherOverlay(lat, lng, icon, temp, windspeed));			
		}
		
		this.Map.removeControl(_LoadingControl);		
	}
	
	function Geocode_Callback(point)
	{
		if (point)
		{
			this.Mark(point.lat(), point.lng(), 15, 0, false);
		}
		else
		{
			this.ShowError(this.Translate.GeocodeError)
		}
	}
	
	function Search_Callback(data, responseCode)
	{		
		var markers, xml;
		var latTot = 0, lngTot = 0;
		this.Map.clearOverlays();
		
		if (responseCode == 200)
		{
			xml = GXml.parse(data);
			markers = xml.documentElement.getElementsByTagName("marker");
		}
		else
		{
			this.Map.removeControl(_LoadingControl);
			this.ShowError(this.Translate.SearchError);
			return;		
		}
		
		if (markers.length <= 0)
		{
			this.Map.removeControl(_LoadingControl);
			this.ShowError(this.Translate.SearchNoHits);
			return;
		}
		
		if (markers.length <= _MarkersMax)
		{
			for (var i = 0; i < markers.length; i++)
			{
				var point = new GLatLng(parseFloat(markers[i].getAttribute("lng")), parseFloat(markers[i].getAttribute("lat")));
				latTot += point.lat()
				lngTot += point.lng();
				var prodId = parseInt(markers[i].getAttribute("prodid"));
				var nodeInfo = markers[i].getElementsByTagName("info")[0];
				var marker = GetMarker(point, prodId, nodeInfo);
				if (!this.Clustered)
					this.Map.addOverlay(marker);
				else
					this.Cluster.AddMarker(marker, "Test");
			}
		}
		else
		{
			this.Map.removeControl(_LoadingControl);
			this.ShowError(this.Translate.SearchToManyHits);
			return;
		}
		
		this.Map.removeControl(_LoadingControl);
		
		latMed = latTot / parseFloat(markers.length);
		lngMed = lngTot / parseFloat(markers.length);
			
		this.Map.panTo( new GLatLng(latMed, lngMed) );
	}
	
	function GetMarker(point, prodId, nodeInfo)
	{
		var marker = new GMarker(point, {icon:_Icon});
				
		if (nodeInfo != null)
		{
			var name = nodeInfo.childNodes[0].childNodes[0].data;
			var text = nodeInfo.childNodes[1].childNodes[0].data;
			var img = nodeInfo.childNodes[2].childNodes[0].data;
			if (!img || img == "")
				img = "/GoogleMaps/images/defaultItem.gif";
			else
				img = _BasetoolUpload + '/' + img;			
			marker.Title = name;
			marker.HTML = '<div class="InfoWindow"><div class="Name">' + name + '</div><div class="Row"><div class="Image"><img src="' + img + '" width="100" height="80"/></div><div class="Text">' + text + '</div></div>' + ((_LinkUrl != null) ? '<div class="Link"><a href="' + _LinkUrl + prodId + '" target="_blank">' + window.BaseMap.Translate.ReadMore + '</a></div></div>' : '</div>');
						
			GEvent.addListener(marker, "click", function() {
				marker.openInfoWindowHtml(marker.HTML);
			});
		}

		return marker;
	}	
	
	function ShowError(message)
	{
		this.ErrorControl.Message = message;
		this.Map.addControl(this.ErrorControl);		
		setTimeout("window.BaseMap.Map.removeControl(window.BaseMap.ErrorControl)", 10000);
	}
}


/* HELPER METHODS */
function CreateMethodReference(object, method)
{
    if (!(method instanceof Function))
        method = object[method];

    return function () {
        method.apply(object, arguments);
    }
}
