/*
	create a video player obj
*/

var Map = function(oSettings) {

	// setup public return value
	var pub = {};

	var currentZoomLevel = 1;

	var MOUSEDOWN = false;
	var TWEENING = false;

	var containerVelocityX = 0;
	var containerVelocityY = 0;

	var currentMarker = null;
	var bTileOpacityTween = null;
	var bForceTileLoad = null;
	var sDomain = '';
	var sLoadDataUrl = '';
	var oLoaderPosition = null;
	var bMapInputsPresent;

	/*
		constructor
	*/

	var init = function(oSettings) {

		// expand the oSettings argument

		var oParent = oSettings.oParent;
		var nWidth = oSettings.nWidth;
		var nHeight = oSettings.nHeight;
		var nZoomLevel = oSettings.nZoomLevel;
		var bControls = oSettings.bControls;
		var bMapPanning = oSettings.bMapPanning;
		var bMapPanningTween = oSettings.bMapPanningTween;
		var oZoomPosition = oSettings.oZoomPosition;
		var oMapPosition = oSettings.oMapPosition;
		var nExtraTopSpacing = oSettings.nExtraTopSpacing;
		var nPopupBottomSpacing = oSettings.nPopupBottomSpacing;
		var bShowCounter = oSettings.bShowCounter;
		bMapInputsPresent = oSettings.bMapInputsPresent;

		// set some class vars
		sLoadDataUrl = oSettings.sLoadDataUrl;
		bForceTileLoad = oSettings.bForceTileLoad;
		bTileOpacityTween = oSettings.bTileOpacityTween;
		sDomain = oSettings.sDomain;
		oLoaderPosition = oSettings.oLoaderPosition;

		$(document).ready(function() {

			// add the map element & its children to the dom
			appendDom(oParent, nWidth, nHeight, oMapPosition, bControls, oZoomPosition);

			// set the various event properties
			setEventHandlers(bMapPanning, bMapPanningTween, true, nExtraTopSpacing, nPopupBottomSpacing);

			// show initial loader
			showLoader(true, oLoaderPosition);

			// set the default zoomLevel (this also loads the data)
			setZoomLevel(nZoomLevel, bTileOpacityTween, bForceTileLoad, sLoadDataUrl, bShowCounter);

			if (bShowCounter == true) {
				showCounter();
			};

		});
	}


	/*
		private methods
	*/

	var showLoader = function(bBoolean, oLoaderPosition) {

		// clean up any markerInfo windows
		$('#markerInfoWrapper').remove();

		if (bBoolean == true) {

			$('#map').prepend('<div class="loader"></div>');
			$('#map > .loader').css('position', 'absolute');
			$('#map > .loader').css('z-index', '1');
			$('#map > .loader').css('width', '100%');
			$('#map > .loader').css('height', '100%');
			$('#map > .loader').css('background-color', 'white');
			$('#map > .loader').css('opacity', '0.00001');

			$('#map').prepend('<img class="spinner" src="'+sDomain+'img/map/controls/spinner.gif" />');
			$('#map > .spinner').css('position', 'absolute');
			$('#map > .spinner').css('z-index', '2');
			$('#map > .spinner').css('top', '50%');
			$('#map > .spinner').css('left', '50%');
			$('#map > .spinner').css('margin-top', oLoaderPosition.y+'px');
			$('#map > .spinner').css('margin-left', oLoaderPosition.x+'px');
			$('#map > .spinner').css('opacity', '0');

			$('#map > .spinner').animate({
					opacity : 1
				}, { 'queue' : false, 'duration' : 200, 'easing' : 'linear', 'complete' : function() {}
			});

			$('#mapviewer > .container .markers').animate({
					opacity : 0
				}, { 'queue' : false, 'duration' : 350, 'easing' : 'linear', 'complete' : function() {}
			});

		} else if (bBoolean == false) {

			setTimeout(function() {

				$('#map > .spinner').animate({
						opacity : 0
					}, { 'queue' : false, 'duration' : 200, 'easing' : 'linear', 'complete' : function() {

							$('#map > .spinner').remove();
							$('#map > .loader').remove();
						}
				});

				$('#mapviewer > .container .markers').animate({
						opacity : 1
					}, { 'queue' : false, 'duration' : 350, 'easing' : 'linear', 'complete' : function() {}
				});

			}, 1200);
		}
	};

	var appendDom = function(oParent, nWidth, nHeight, oMapPosition, bControls, oZoomPosition) {

		$(oParent).append('<div id="map"></div>');

		$('#map').append('<div id="mapviewer">\
							<div class="container">\
								<div class="map3"><div class="markers"></div></div>\
								<div class="map2"><div class="markers"></div></div>\
								<div class="map1"><div class="markers"></div></div>\
							</div>\
						  </div>');

		$('#map').css('position', 'relative');
		$('#map').css('width', nWidth);
		$('#map').css('height', nHeight);

		$('#mapviewer').css('position', 'relative');
		$('#mapviewer').css('width', nWidth);
		$('#mapviewer').css('height', nHeight);
		$('#mapviewer').css('overflow', 'hidden');
		$('#mapviewer').css('background-color', '#83d1a6');

		$('#mapviewer > .container').attr('style', 'position: relative; left: 50%; top: 50%; margin-top: '+oMapPosition.y+'px; margin-left: '+oMapPosition.x+'px;');
		$('#mapviewer > .container').css('cursor', 'pointer');

		$('#mapviewer > .container > .map1').attr('style', 'position: absolute; width: 2560px; height: 850px;');
		$('#mapviewer > .container > .map2').attr('style', 'position: absolute; width: 7680px; height: 2550px;');
		$('#mapviewer > .container > .map3').attr('style', 'position: absolute; width: 15360px; height: 5100px;');

		$('#mapviewer > .container .markers').css('opacity', 0);

		$(document).ready(function() {

			// TODO: clean this up, maybe by also making a threeway division for map 1 & 2
			$('#mapviewer > .container > .map1').append('<div class="middle" style="float: left;"></div>');
			$('#mapviewer > .container > .map2').append('<div class="middle" style="float: left;"></div>');

			$('#mapviewer > .container > .map3').append('<img class="left" style="float: left; width: 6144px; height: 5100px;" />');
			$('#mapviewer > .container > .map3').append('<div class="middle" style="float: left; width: 4096px; height: 5100px;"></div>');
			$('#mapviewer > .container > .map3').append('<img class="right" style="float: left; width: 5120px; height: 5100px;" />');

		});

		/*
			dis or enable the zoom controls
		*/

		if (bControls == true) {

			$('#mapviewer').append('<div class="controls">\
										<div class="zoom">\
											<img class="handle" src="'+sDomain+'img/map/controls/navigation_zoom_handle.png" />\
											<img class="plus" src="'+sDomain+'img/map/controls/navigation_zoom_plus.png" />\
											<img class="line" src="'+sDomain+'img/map/controls/navigation_zoom_line.png" />\
											<img class="minus" src="'+sDomain+'img/map/controls/navigation_zoom_minus.png" />\
										</div>\
									</div>');

			$('#mapviewer > .controls').attr('style', 'width: 930px; height: 701px;');
			$('#mapviewer > .controls > .zoom').attr('style', 'position: absolute; top: 50%; left: 50%; margin-left: '+oZoomPosition.x+'px; margin-top: '+oZoomPosition.y+'px; width:31px; line-height: 0px;');
			$('#mapviewer > .controls > .zoom > .handle').attr('style', 'position: absolute; margin-top: 128px; margin-left: 12px; cursor: pointer;');
			$('#mapviewer > .controls > .zoom > .plus').attr('style', 'cursor: pointer;');
			$('#mapviewer > .controls > .zoom > .line').attr('style', 'margin-left: 12px; margin-top: -1px;');
			$('#mapviewer > .controls > .zoom > .minus').attr('style', 'margin-top: -1px; cursor: pointer;');
		};
	}

	var setEventHandlers = function(bMapPanning, bMapPanningTween, bMarkerPopups, nExtraTopSpacing, nPopupBottomSpacing) {

		/*
			switch for switching easing methods
		*/

		switch(bMapPanningTween) {

			case true :

				var mouseX;
				var mouseY;

				// register the mousepos
				$("html").bind("mousemove", function(e) {
					 mouseX = e.pageX;
					 mouseY = e.pageY;
				});

				// combined panning events
				$("#mapviewer").bind("mousedown", function(e) {

					e.preventDefault();

					MOUSEDOWN = true;

					containerVelocityX = 0;
					containerVelocityY = 0;

					mouseX = e.pageX;
					mouseY = e.pageY;

					var currentMouseX = e.pageX - parseInt($("#mapviewer > .container").css("margin-left"));
					var currentMouseY = e.pageY - parseInt($("#mapviewer > .container").css("margin-top"));

					var timer = setInterval(function() {

						if (MOUSEDOWN == true) {

							var currentMouseXHandle = parseInt($("#mapviewer > .container").css("margin-left")) + currentMouseX;
							var currentMouseYHandle = parseInt($("#mapviewer > .container").css("margin-top")) + currentMouseY;

							var diffX = mouseX - currentMouseXHandle;
							var diffY = mouseY - currentMouseYHandle;

							containerVelocityX = diffX * 0.18;
							containerVelocityY = diffY * 0.18;

							// if present update the markerInfo position
							if (currentMarker != null) {
								updateMarkerInfoPosition();
							};

						} else {

							containerVelocityX = containerVelocityX * 0.92;
							containerVelocityY = containerVelocityY * 0.92;

							if (containerVelocityX < 5 && containerVelocityX > -5 && containerVelocityY < 5 && containerVelocityY > -5) {

								clearInterval(timer);

								containerVelocityX = 0;
								containerVelocityY = 0;

								// if present update the markerInfo position
								if (currentMarker != null) {
									updateMarkerInfoPosition();
								};
							}
						}

						$("#mapviewer > .container").css("margin-top", parseInt($("#mapviewer > .container").css("margin-top")) + containerVelocityY);

						$("#mapviewer > .container").css("margin-left", parseInt($("#mapviewer > .container").css("margin-left")) + containerVelocityX);


					}, 10)

				});

				break;

			case false :

				// TODO: rough duplicate of the mousedown / mousemovehandlers -> migrate into a single function

				/*
					TOUCH
				*/

				$("#mapviewer").bind("touchstart", function(e) {

					e.preventDefault();

					var touch = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];

					var currentMouseX = touch.pageX-parseInt($("#mapviewer > .container").css("margin-left"));
					var currentMouseY = touch.pageY-parseInt($("#mapviewer > .container").css("margin-top"));

					$("#mapviewer").bind("touchmove" , function(e) {

						e.preventDefault();

						var touch2 = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];

						var newMouseX = touch2.pageX;
						var newMouseY = touch2.pageY;

						var diffMouseX = -(currentMouseX - newMouseX);
						var diffMouseY = -(currentMouseY - newMouseY);

						$("#mapviewer > .container").css("margin-left", diffMouseX);
						$("#mapviewer > .container").css("margin-top", diffMouseY);

						// if present update the markerInfo position
						if (currentMarker != null) {
							updateMarkerInfoPosition();
						};
					});

				});

				$("#mapviewer").bind("touchend", function(e) {

					switch(currentZoomLevel) {

						case 1 :
							loadImageTiles('map1', 26, bTileOpacityTween);
							break;

						case 2 :
							loadImageTiles('map2', 226, bTileOpacityTween);
							break;

						case 3 :
							loadImageTiles('map3', 240, bTileOpacityTween);
							break;
					};
				});

				/*
					MOUSE
				*/

				// combined panning events
				$("#mapviewer").bind("mousedown", function(e) {

					e.preventDefault();

					var currentMouseX = e.pageX-parseInt($("#mapviewer > .container").css("margin-left"));
					var currentMouseY = e.pageY-parseInt($("#mapviewer > .container").css("margin-top"));

					$("html").bind("mousemove" , function(e) {

                        // check te see whether or not we're scrolling using the
                        // zoom handler

                        if (bHandleIsDragging == false) {


                            e.preventDefault();

                            var newMouseX = e.pageX;
                            var newMouseY = e.pageY;

                            var diffMouseX = -(currentMouseX - newMouseX);
                            var diffMouseY = -(currentMouseY - newMouseY);

                            var currentMap;

                            /*
                                neat calculation to prevent the map from scrolling too far.
                                this also prevents bugs when the markerInfo window goes beyond the oParent
                            */

                            switch(currentZoomLevel) {

                                case(1) :
                                    currentMap = 'map1';
                                    break;

                                case(2) :
                                    currentMap = 'map2';
                                    break;

                                case(3) :
                                    currentMap = 'map3';
                                    break;
                            }

                            $("#mapviewer > .container").css("margin-left", diffMouseX);
                            $("#mapviewer > .container").css("margin-top", diffMouseY);

                            // check to prevent going too high
                            if (parseInt($('#mapviewer > .container').css('margin-top')) > -((parseInt($('#mapviewer').height()/2)-nExtraTopSpacing))) {

                                $('#mapviewer > .container').css('margin-top', -((parseInt($('#mapviewer').height()/2)-nExtraTopSpacing)));

                            // check to prevent going too low
                            } else if(parseInt($('#mapviewer > .container').css('margin-top')) + parseInt($('#mapviewer > .container > .'+currentMap).height()) < parseInt($('#mapviewer').height()/2)) {

                                $('#mapviewer > .container').css('margin-top', parseInt($('#mapviewer').height()/2) - parseInt($('#mapviewer > .container > .'+currentMap).height()));
                            }

                            // check to prevent going too far left
                            if (parseInt($('#mapviewer > .container').css('margin-left')) > -(parseInt($('#mapviewer').width()/2))) {

                                $('#mapviewer > .container').css('margin-left', -(parseInt($('#mapviewer').width()/2)));

                            // check to prevent going too far right
                            } else if(parseInt($('#mapviewer > .container').css('margin-left')) + parseInt($('#mapviewer > .container > .'+currentMap).width()) < parseInt($('#mapviewer').width()/2)) {

                                $('#mapviewer > .container').css('margin-left', parseInt($('#mapviewer').width()/2) - parseInt($('#mapviewer > .container > .'+currentMap).width()));
                            }

                            // if present update the markerInfo position
                            if (currentMarker != null) {
                                updateMarkerInfoPosition();
                            };

                            // check if the markerInfo marker is inside the map container
                            isCurrentMarkerVisible(nPopupBottomSpacing);
                        }

					});
				});

				// clean them up
				$("#mapviewer").bind("mouseup", function(e) {
					e.preventDefault();

					MOUSEDOWN = false;

					$("html").unbind("mousemove");

					switch(currentZoomLevel) {

						case 1 :
							loadImageTiles('map1', 26, bTileOpacityTween);
							break;

						case 2 :
							loadImageTiles('map2', 226, bTileOpacityTween);
							break;

						case 3 :
							loadImageTiles('map3', 240, bTileOpacityTween);
							break;
					};
				});
				break;
		};

		/*
			/switch for switching easing methods
		*/

		// controls zoom

		 $('#mapviewer').dblclick(function(e) {

			 var currTileParentOffsetLeft = $(e.target).position().left;
 			 var currTileParentOffsetTop = $(e.target).position().top;

			 zoomToSpot(currTileParentOffsetLeft, currTileParentOffsetTop);
		 });


        // handle drag handling

        var bHandleIsDragging = false;

        $('.controls .zoom .handle').bind('mousedown', function(e) {

            bHandleIsDragging = true;

            var initialMousePos = e.pageY;
            var currentMargin = parseInt($(this).css('margin-top'));

            $('body').mousemove(function(e){

                var currentMousePos = e.pageY;
                var mouseOffset = initialMousePos - currentMousePos;

                var dragValue = currentMargin - mouseOffset;

                // constraints
                dragValue = (dragValue > 128) ? 128 : dragValue;
                dragValue = (dragValue < 40) ? 40 : dragValue;

                $('.controls .zoom .handle').css('margin-top', dragValue);
            });

        });

        $('body').bind('mouseup', function() {

            // check if handle is being dragged
            if (bHandleIsDragging) {

                bHandleIsDragging = false;

                $(this).unbind('mousemove');

                var currentMargin = parseInt($('.controls .zoom .handle').css('margin-top'));

                switch(true) {

                    case (currentMargin <= 64):

                        if (currentZoomLevel != 3) {
                            showLoader(true, oLoaderPosition);
                            setTimeout(function() {
                                setZoomLevel(3, bTileOpacityTween, bForceTileLoad, sLoadDataUrl);
                            }, 1000);
                        }

                        break;

                    case (currentMargin > 64 && currentMargin < 108):

                        if (currentZoomLevel != 2) {
                            showLoader(true, oLoaderPosition);
                            setTimeout(function() {
                                setZoomLevel(2, bTileOpacityTween, bForceTileLoad, sLoadDataUrl);
                            }, 1000);
                        }

                        break;

                    case (currentMargin >= 108):

                        if (currentZoomLevel != 1) {
                            showLoader(true, oLoaderPosition);
                            setTimeout(function() {
                                setZoomLevel(1, bTileOpacityTween, bForceTileLoad, sLoadDataUrl);
                            }, 1000);
                        }

                        break;

                }
            };
        });
    }

	var zoomToSpot = function(currTileParentOffsetLeft, currTileParentOffsetTop) {

		// TODO: implement a zoomToSpot method

	};

	var updateZoomControls = function(currentZoomLevel, bPlus, bMinus) {

		if (bPlus == true) {

			$('#mapviewer > .controls > .zoom > .plus').unbind();
			$('#mapviewer > .controls > .zoom > .plus').attr('src', sDomain+'img/map/controls/navigation_zoom_plus.png');

			$('#mapviewer > .controls > .zoom > .plus').bind('mouseenter', function() {
				$('#mapviewer > .controls > .zoom > .plus').attr('src', sDomain+'img/map/controls/navigation_zoom_plus_hover.png');
			});
			$('#mapviewer > .controls > .zoom > .plus').bind('mouseleave', function() {
				$('#mapviewer > .controls > .zoom > .plus').attr('src', sDomain+'img/map/controls/navigation_zoom_plus.png');
			});
			$('#mapviewer > .controls > .zoom > .plus').css('cursor', 'pointer');
			$('#mapviewer > .controls > .zoom > .plus').click(function() {

				showLoader(true, oLoaderPosition);

				setTimeout(function() {
					setZoomLevel(currentZoomLevel+1, bTileOpacityTween, bForceTileLoad, sLoadDataUrl);
				}, 1000);
			});

			$('#mapviewer > .controls > .zoom > .plus').bind('touchend', function() {

				showLoader(true, oLoaderPosition);

				setTimeout(function() {
					setZoomLevel(currentZoomLevel+1, bTileOpacityTween, bForceTileLoad, sLoadDataUrl);
				}, 1000);
			});
		} else {

			$('#mapviewer > .controls > .zoom > .plus').unbind();
			$('#mapviewer > .controls > .zoom > .plus').css('cursor', 'default');
		}

		if (bMinus == true) {

			$('#mapviewer > .controls > .zoom > .minus').unbind();
			$('#mapviewer > .controls > .zoom > .minus').attr('src', sDomain+'img/map/controls/navigation_zoom_minus.png');

			//setZoomLevel = function(newZoomLevel, bTileOpacityTween, bForceTileLoad, sLoadDataUrl)
			$('#mapviewer > .controls > .zoom > .minus').bind('mouseenter', function() {
				$('#mapviewer > .controls > .zoom > .minus').attr('src', sDomain+'img/map/controls/navigation_zoom_minus_hover.png');
			});
			$('#mapviewer > .controls > .zoom > .minus').bind('mouseleave', function() {
				$('#mapviewer > .controls > .zoom > .minus').attr('src', sDomain+'img/map/controls/navigation_zoom_minus.png');
			});
			$('#mapviewer > .controls > .zoom > .minus').css('cursor', 'pointer');
			$('#mapviewer > .controls > .zoom > .minus').click(function() {

				showLoader(true, oLoaderPosition);

				setTimeout(function() {
					setZoomLevel(currentZoomLevel-1, bTileOpacityTween, bForceTileLoad, sLoadDataUrl);
				}, 1000);
			});
			$('#mapviewer > .controls > .zoom > .minus').bind('touchend', function() {

				showLoader(true, oLoaderPosition);

				setTimeout(function() {
					setZoomLevel(currentZoomLevel-1, bTileOpacityTween, bForceTileLoad, sLoadDataUrl);
				}, 1000);
			});
		} else {

			$('#mapviewer > .controls > .zoom > .minus').unbind();
			$('#mapviewer > .controls > .zoom > .minus').css('cursor', 'default');
		}

	};


	var lngToPixels = function(lng) {

		/*
			longitude calc
		*/

		// compare pixel offset to the hague
		var tmpLng = lng - 4.293;

		// apply the longitude factor per pixel (this one's pretty close)
		tmpLng = tmpLng / 0.00117176258993;

		// add this pixel value to the offset of the hague
		return tmpLng + 7291;
	};

	var loadImageTiles = function(sContainer, nTileCount, bTileOpacityTween, bForceTileLoad) {

		/*
			Loads a whole bunch of images and appends them as floating elements
			to their container div.

		*/

		$(document).ready(function() {

			// quick 'hack' to prevent the bottom right tile from loading (nTileCount+1)
			for(i=1; i<nTileCount+1;i++) {

				// check if the empty img element exists OR it's attr has been set
				if($('#mapviewer > .container > .'+sContainer+' > .middle > .img'+i+'').length == 0) {

					// append the DOM with empty img elements
					if(bTileOpacityTween == true) {

						$('#mapviewer > .container > .'+sContainer+' > .middle').append('<img class="img'+i+' "style="float: left; width: 512px; height: 170px; opacity: 0;"></img>')
					} else if(bTileOpacityTween == false) {
						$('#mapviewer > .container > .'+sContainer+' > .middle').append('<img class="img'+i+' "style="float: left; width: 512px; height: 170px; opacity: 1;"></img>')
					};
				};

				// check if tile is in the viewport
				if (isElemInViewport($('#mapviewer > .container > .'+sContainer+' > .middle > .img'+i+''), 512, 170) == true || bForceTileLoad == true) {

					// set var to do a load() check on
					var lastVisibleImage = i;

					$('#mapviewer > .container > .'+sContainer+' > .middle > .img'+i+'').css('visibility', 'visible');
					// check if tile has already been loaded
					//alert(i + ' : ' + nTileCount);
					if (
							$('#mapviewer > .container > .'+sContainer+' > .middle > .img'+i+'').attr('src') == undefined ||
							$('#mapviewer > .container > .'+sContainer+' > .middle > .img'+i+'').attr('src') == ''
						) {

						// set the attr alement to load the img data
						$('#mapviewer > .container > .'+sContainer+' > .middle >.img'+i+'').attr('src', sDomain+'img/map/data/'+sContainer+'/'+i+'.gif');

						// bind .load() event handlers
						if(bTileOpacityTween == true) {
							$('#mapviewer > .container > .'+sContainer+' > .middle >.img'+i+'').load(function() {

								$(this).animate({
									opacity : 1
								}, { 'queue' : false, 'duration' : 350, 'easing' : 'linear' });
							});
						};
					}
				};


				if (bForceTileLoad == false) {

				// check if tile is NOT in the viewport (remove them)
					if (isElemInViewport($('#mapviewer > .container > .'+sContainer+' > .middle > .img'+i+''), 512, 170) == false) {

						// check if tile has already been loaded
						if ($('#mapviewer > .container > .'+sContainer+' > .middle > .img'+i+'').attr('src') != undefined) {

							// set the attr alement to load the img data
							$('#mapviewer > .container > .'+sContainer+' > .middle >.img'+i+'').css('visibility', 'hidden');

							// bind .load() event handlers
							if(bTileOpacityTween == true) {
								$('#mapviewer > .container > .'+sContainer+' > .middle >.img'+i+'').load(function() {

									$(this).animate({
										opacity : 1
									}, { 'queue' : false, 'duration' : 350, 'easing' : 'linear' });

								});
							};
						};
					};
				};


			};

			$('#mapviewer > .container > .'+sContainer+' > .middle >.img'+lastVisibleImage).load(function() {

				showLoader(false);
			});
		});
	};

	var isCurrentMarkerVisible = function(nPopupBottomSpacing) {

		if (currentMarker != null) {

			// nifty check to see if the current marker is inside of the visible container

			var c = parseInt($(currentMarker).css('margin-left'));
			var d = parseInt($(currentMarker).css('margin-top'));
			var e = Math.abs(parseInt($('#mapviewer > .container').css('margin-left')) + $("#map").width()/2); // compensate for left:50% offset
			var f = Math.abs(parseInt($('#mapviewer > .container').css('margin-top'))  + $("#map").height()/2); // compensate for top:50% offset
			var g = e + $('#map').width();
			var h = f + $('#map').height();

			if (c > e && c < g && d > f && d + nPopupBottomSpacing < h) {

				if ($('#markerInfoWrapper > .markerInfo').css('opacity') < 1) {

					// show the current markerInfo
					//$('#markerInfoWrapper > .markerInfo').css('opacity', 1)
					$('#markerInfoWrapper > .markerInfo').animate({
						'opacity' : 1
					}, { 'queue' : false, 'duration' : 50, 'easing' : 'linear' });
				};

			} else {

				// hide the current markerInfo
				//$('#markerInfoWrapper > .markerInfo').css('opacity', 0)
				$('#markerInfoWrapper > .markerInfo').animate({
					'opacity' : 0
				}, { 'queue' : false, 'duration' : 50, 'easing' : 'linear' });
			};
		}

	};

	var isElemInViewport = function(oElement, offsetLeft, offsetTop) {

		var oElement = $(oElement);

		// check for the elem being outside of the viewport
		// (as this is calculated from the top left we compensate for this)
		if(oElement.viewportOffset().left < -offsetLeft || oElement.viewportOffset().top < -offsetTop){

			//elem is left of or above viewport
			return false;
		}

		if(oElement.viewportOffset().left > $(window).width() || oElement.viewportOffset().top > $(window).height()){

			//elem is below or right of viewport
			return false;
		}

		return true;
	};

	var latToPixels = function(lat) {

		 /*
			 latitude calc
		 */

		 // compare pixel offset to leeuwarden
		 var tmpLat = 53.2019 - lat;

		// apply the longitude factor per pixel (this one's pretty close)
		tmpLat = tmpLat / 0.00071145707376;

		// add this pixel value to the offset of leeuwarden
		return tmpLat + 814;
	};

	// place a marker specified per zoom level
	var placeMarker = function(zoomLevel, lat, lng, id, markerType, grpCount) {

		// calculate pixel values
		var pixelLat = latToPixels(lat);
		var pixelLng = lngToPixels(lng);

		switch (zoomLevel) {

			case 1 :

				switch (markerType) {

					case "act" :

						$('#mapviewer > .container > .map1 > .markers').prepend($('<div id=act_'+id+' class="marker" style="position: absolute; width: 24px; height: 24px; background-image: url(\''+sDomain+'/img/map/controls/marker_act.png\'); margin-top: '+((pixelLat/6)-12)+'px; margin-left: '+((pixelLng/6)-12)+'px; cursor: pointer;"></div>').bind('mouseenter', function() {$(this).css('background-image', 'url(\''+sDomain+'/img/map/controls/marker_act-hover.png\')')}).bind('mouseleave', function() {$(this).css('background-image', 'url(\''+sDomain+'/img/map/controls/marker_act.png\')')}) );


						$('#mapviewer > .container > .map1 > .markers > #act_'+id+'').bind('click', function() {

							 // register the current marker
							 currentMarker = $(this);

							 // show the current markerInfo
							 showMarkerInfo(currentMarker);

						});

						$('#mapviewer > .container > .map1 > .markers > #act_'+id+'').bind('touchend', function() {

							 // register the current marker
							 currentMarker = $(this);

							 // show the current markerInfo
							 showMarkerInfo(currentMarker);

						});
						break;

					case "grp" :

						$('#mapviewer > .container > .map1 > .markers').prepend($('<div id=grp_'+id+' class="marker" style="position: absolute; width: 36px; height: 36px; background-image: url(\''+sDomain+'/img/map/controls/marker_grp.png\'); margin-top: '+((pixelLat/6)-18)+'px; margin-left: '+((pixelLng/6)-18)+'px; cursor: pointer;"><div style="padding-top: 10px; font-family: arial; font-size: 14px; font-weight: bold; color: #cceedc;"><center>'+grpCount+'</center></div></div>').bind('mouseenter', function() {$(this).css('background-image', 'url(\''+sDomain+'/img/map/controls/marker_grp-hover.png\')'); $($(this).children()[0]).css('color', 'white')}).bind('mouseleave', function() {$(this).css('background-image', 'url(\''+sDomain+'/img/map/controls/marker_grp.png\')');$($(this).children()[0]).css('color', '#CCEEDC')}) );

						$('#mapviewer > .container > .map1 > .markers > #grp_'+id+'').bind('click', function() {

							 // register the current marker
							 currentMarker = $(this);

							 // show the current markerInfo
							 showMarkerInfo(currentMarker);

						});

						$('#mapviewer > .container > .map1 > .markers > #grp_'+id+'').bind('touchend', function() {

							 // register the current marker
							 currentMarker = $(this);

							 // show the current markerInfo
							 showMarkerInfo(currentMarker);

						});
						break;
				}

				break;

			case 2 :

				switch (markerType) {

					case "act" :

						$('#mapviewer > .container > .map2 > .markers').prepend($('<div id=act_'+id+' class="marker" style="position: absolute; width: 24px; height: 24px; background-image: url(\''+sDomain+'/img/map/controls/marker_act.png\'); margin-top: '+((pixelLat/2)-12)+'px; margin-left: '+((pixelLng/2)-12)+'px; cursor: pointer;"></div>').bind('mouseenter', function() {$(this).css('background-image', 'url(\''+sDomain+'/img/map/controls/marker_act-hover.png\')')}).bind('mouseleave', function() {$(this).css('background-image', 'url(\''+sDomain+'/img/map/controls/marker_act.png\')')}) );

						$('#mapviewer > .container > .map2 > .markers > #act_'+id+'').bind('click', function() {

							 // register the current marker
							 currentMarker = $(this);

							 // show the current markerInfo
							 showMarkerInfo(currentMarker);

						});

						$('#mapviewer > .container > .map2 > .markers > #act_'+id+'').bind('touchend', function() {

							 // register the current marker
							 currentMarker = $(this);

							 // show the current markerInfo
							 showMarkerInfo(currentMarker);

						});
						break;

					case "grp" :

						$('#mapviewer > .container > .map2 > .markers').prepend($('<div id=grp_'+id+' class="marker" style="position: absolute; width: 36px; height: 36px; background-image: url(\''+sDomain+'/img/map/controls/marker_grp.png\'); margin-top: '+((pixelLat/2)-18)+'px; margin-left: '+((pixelLng/2)-18)+'px; cursor: pointer;"><div style="padding-top: 10px; font-family: arial; font-size: 14px; font-weight: bold; color: #cceedc;"><center>'+grpCount+'</center></div></div>').bind('mouseenter', function() {$(this).css('background-image', 'url(\''+sDomain+'/img/map/controls/marker_grp-hover.png\')'); $($(this).children()[0]).css('color', 'white')}).bind('mouseleave', function() {$(this).css('background-image', 'url(\''+sDomain+'/img/map/controls/marker_grp.png\')');$($(this).children()[0]).css('color', '#CCEEDC')}) );

						$('#mapviewer > .container > .map2 > .markers > #grp_'+id+'').bind('click', function() {

							 // register the current marker
							 currentMarker = $(this);

							 // show the current markerInfo
							 showMarkerInfo(currentMarker);

						});

						$('#mapviewer > .container > .map2 > .markers > #grp_'+id+'').bind('touchend', function() {

							 // register the current marker
							 currentMarker = $(this);

							 // show the current markerInfo
							 showMarkerInfo(currentMarker);

						});
						break;
				}

				break;

			case 3 :

				switch (markerType) {

					case "act" :

						$('#mapviewer > .container > .map3 > .markers').prepend($('<div id=act_'+id+' class="marker" style="position: absolute; width: 24px; height: 24px; background-image: url(\''+sDomain+'/img/map/controls/marker_act.png\'); margin-top: '+(pixelLat-12)+'px; margin-left: '+(pixelLng-12)+'px; cursor: pointer;"></div>').bind('mouseenter', function() {$(this).css('background-image', 'url(\''+sDomain+'/img/map/controls/marker_act-hover.png\')')}).bind('mouseleave', function() {$(this).css('background-image', 'url(\''+sDomain+'/img/map/controls/marker_act.png\')')}) );

						$('#mapviewer > .container > .map3 > .markers > #act_'+id+'').bind('click', function() {

							 // register the current marker
							 currentMarker = $(this);

							 // show the current markerInfo
							 showMarkerInfo(currentMarker);

						});

						$('#mapviewer > .container > .map3 > .markers > #act_'+id+'').bind('touchend', function() {

							 // register the current marker
							 currentMarker = $(this);

							 // show the current markerInfo
							 showMarkerInfo(currentMarker);

						});
						break;

					case "grp" :

						$('#mapviewer > .container > .map3 > .markers').prepend($('<div id=grp_'+id+' class="marker" style="position: absolute; width: 36px; height: 36px; background-image: url(\''+sDomain+'/img/map/controls/marker_grp.png\'); margin-top: '+(pixelLat-18)+'px; margin-left: '+(pixelLng-18)+'px; cursor: pointer;"><div style="padding-top: 10px; font-family: arial; font-size: 14px; font-weight: bold; color: #cceedc;"><center>'+grpCount+'</center></div></div>').bind('mouseenter', function() {$(this).css('background-image', 'url(\''+sDomain+'/img/map/controls/marker_grp-hover.png\')'); $($(this).children()[0]).css('color', 'white')}).bind('mouseleave', function() {$(this).css('background-image', 'url(\''+sDomain+'/img/map/controls/marker_grp.png\')');$($(this).children()[0]).css('color', '#CCEEDC')}) );

						$('#mapviewer > .container > .map3 > .markers > #grp_'+id+'').bind('click', function() {

							 // register the current marker
							 currentMarker = $(this);

							 // show the current markerInfo
							 showMarkerInfo(currentMarker);

						});

						$('#mapviewer > .container > .map3 > .markers > #grp_'+id+'').bind('touchend', function() {

							 // register the current marker
							 currentMarker = $(this);

							 // show the current markerInfo
							 showMarkerInfo(currentMarker);

						});
						break;
				}

				break;
		}
	}

	/*
		show the markerInfo popup, separated from the rest of the map because it needs
		to extend beyond the map's borders
	*/

	var showMarkerInfo = function(oMarker) {

		// jsonp call to retrieve this event's specific dataset
		// parsing and 'rendering' of the markerInfo window is being done in the
		// ajax's success handler.

		$.ajax({
			url : sLoadDataUrl,
			type : "GET",
			data : 'dataType=eventData&eventId='+$(oMarker).attr('id').substring(4) ,
			dataType : 'jsonp',
			async : true,
			success: function(response) {

				var eventData = response;

				// clean up other markers
				$('#markerInfoWrapper').remove();

				// set initial (first) eventData
				var nEventId = 0;

				// weird IE <9 workaround
				if ($.browser.msie && $.browser.version < 9) {
					var nEventCount = eventData.length -1;
				} else {
					var nEventCount = eventData.length;
				}

				var markerToContainerLeft = parseInt(oMarker.css('margin-left'));
				var mapviewerToContainerLeft = Math.abs(parseInt($('#mapviewer > .container').css('margin-left')) + (parseInt($('#mapviewer').css('width'))/2));
				var markerToContainerTop = parseInt(oMarker.css('margin-top'));
				var mapviewerToContainerTop = parseInt($('#mapviewer > .container').css('margin-top')) + (parseInt($('#mapviewer').css('height'))/2);

				var markerOffsetTop = markerToContainerTop + mapviewerToContainerTop;
				var markerOffsetLeft = markerToContainerLeft - mapviewerToContainerLeft + 11;

				var animationOffset = 25;

				// adjust the left property based on whether it's a group or not (the group markers are bigger)
				var wrapperMarginLeft = ($(oMarker[0]).attr('id').substr(0,3) == 'grp') ? '-109px' : '-115px';

				// wrapper
				$('#mapviewer').after('<div id="markerInfoWrapper" style="left: '+wrapperMarginLeft+'; top: 0px; margin-top: '+(markerOffsetTop + animationOffset)+'px; margin-left: '+markerOffsetLeft+'px; position: absolute; opacity: 0;"></div>');

				// item
				$('#markerInfoWrapper').append('<div class="markerInfo" style="position: absolute; z-index: 5; bottom: 0px;"></div>');

				// top
				$('#markerInfoWrapper > .markerInfo').append('<img src="'+sDomain+'img/map/popup/popup-top.png" style="display: block;" />');

				// close-btn (show / hide on mouseenter / leave of the entire infowindow)
				$('#markerInfoWrapper > .markerInfo').append('<img class="btn-close" src="'+sDomain+'img/map/popup/popup-btn-close.gif" style="display: block; position: absolute; margin-top: -1px; margin-left: 199px; cursor: pointer; opacity: 0;" />');

				// close-btn events
				$('#markerInfoWrapper > .markerInfo > .btn-close').live('click', function() {
					$('#markerInfoWrapper').remove();
				});

				$('#markerInfoWrapper > .markerInfo').live('mouseenter', function() {
					$('#markerInfoWrapper > .markerInfo > .btn-close').animate({
						opacity : 1
					}, { 'queue' : false, 'duration' : 200, 'easing' : 'linear' });
				});

				$('#markerInfoWrapper > .markerInfo').live('mouseleave', function() {
					$('#markerInfoWrapper > .markerInfo > .btn-close').animate({
						opacity : 0
					}, { 'queue' : false, 'duration' : 200, 'easing' : 'linear' });
				});

				// middle
				$('#markerInfoWrapper > .markerInfo').append('<div class="middle" style="width: 230px; padding-top: 14px; padding-bottom: 15px; margin-bottom: -1px; background-image: url(\''+sDomain+'/img/map/popup/popup_bg.png\'); background-repeat: repeat-y;"></div>');

				if (nEventCount > 1) {

					$('#markerInfoWrapper > .markerInfo > .middle').append('<div class="group-nav" style="width: 212px; margin-left: 9px; margin-top: 15px; background-image: url(\'' + sDomain + '/img/map/popup/popup-group-nav_bg.gif\'); background-repeat: repeat-x;" />');

					$('#markerInfoWrapper > .markerInfo > .middle > .group-nav').append('<div class="navWrapper" style="margin:0px auto; font-size: 12px; font-family: Arial; font-weight: bold; color: #00ab4e; text-align: center;"><span class="currentEvent">'+(nEventId+1)+'</span> / '+nEventCount+'</div>');
					$('#markerInfoWrapper > .markerInfo > .middle > .group-nav > .navWrapper').prepend('<img class="btn-left" src="'+sDomain+'img/map/popup/popup-nav-btn-left.gif" style="margin-right: 14px; cursor: pointer;"/>')

					// initial check if we should show the button
					if(nEventId == 0) {
						$('#markerInfoWrapper > .markerInfo > .middle > .group-nav > .navWrapper > .btn-left').css('visibility', 'hidden');
					} else {
						$('#markerInfoWrapper > .markerInfo > .middle > .group-nav > .navWrapper > .btn-left').css('visibility', 'visible');
					}

					$('#markerInfoWrapper > .markerInfo > .middle > .group-nav > .navWrapper > .btn-left').click(function() {

						// clear the old data
						$('#markerInfoWrapper > .markerInfo > .middle > .btn-kekijk').remove();
						$('#markerInfoWrapper > .markerInfo > .middle > .location').remove();
						$('#markerInfoWrapper > .markerInfo > .middle > .title').remove();
						$('#markerInfoWrapper > .markerInfo > .middle > .popup-img').remove();
						$('#markerInfoWrapper > .markerInfo > .middle > .popup-club').remove();

						// load in the new data
						$('#markerInfoWrapper > .markerInfo > .middle').prepend('<a href="'+eventData[nEventId-1].url+'" class="btn-kekijk" style="display: block; width: 185px; height: 21px; margin-left: 23px; background-image: url(\'' + sDomain + '/img/map/popup/popup-btn-bekijk.gif\');"></a>');
						$('#markerInfoWrapper > .markerInfo > .middle').prepend('<div class="location" style="width: 185px; padding-left: 23px; padding-bottom: 9px; font-size: 11px; line-height: 11px; font-family: Arial, sans-serif; color: #00ab4e;">locatie: '+eventData[nEventId-1].loc+'</div>');
						$('#markerInfoWrapper > .markerInfo > .middle').prepend('<div class="title" style="width: 185px; padding-left: 23px; padding-bottom: 3px; font-size: 16px; line-height: 16px; font-family: MetaBlack, Arial, sans-serif; color: #00ab4e; text-transform: uppercase;">'+eventData[nEventId-1].title+'</div>');

						if (eventData[nEventId-1].img != null) {
							$('#markerInfoWrapper > .markerInfo > .middle').prepend('<img class="popup-img" style="margin-left: 23px; border: 1px solid #b9c3be; margin-bottom: 8px;" src="'+eventData[nEventId-1].img+'" />');
						}

						if (eventData[nEventId-1].club != null) {
							$('#markerInfoWrapper > .markerInfo > .middle').prepend('<img class="popup-club" style="position: absolute; width: 34px; height: 34px; border-right: 1px solid #b9c3be; border-bottom: 1px solid #b9c3be; margin-left: 23px;" src="'+eventData[nEventId-1].club+'" />');
						}


						nEventId = nEventId -1;

						// check if we should show the buttons
						if(nEventId == 0) {
							$('#markerInfoWrapper > .markerInfo > .middle > .group-nav > .navWrapper > .btn-left').css('visibility', 'hidden');
						} else {
							$('#markerInfoWrapper > .markerInfo > .middle > .group-nav > .navWrapper > .btn-left').css('visibility', 'visible');
						}

						if(nEventId == eventData.length-1) {
							$('#markerInfoWrapper > .markerInfo > .middle > .group-nav > .navWrapper > .btn-right').css('visibility', 'hidden');
						} else {
							$('#markerInfoWrapper > .markerInfo > .middle > .group-nav > .navWrapper > .btn-right').css('visibility', 'visible');
						}

						// update nav counter
						$('#markerInfoWrapper > .markerInfo > .middle > .group-nav > .navWrapper > .currentEvent').html(nEventId+1);

					});
					$('#markerInfoWrapper > .markerInfo > .middle > .group-nav > .navWrapper').append('<img class="btn-right" style="margin-left: 14px; cursor: pointer;" src="'+sDomain+'img/map/popup/popup-nav-btn-right.gif" />');

					$('#markerInfoWrapper > .markerInfo > .middle > .group-nav > .navWrapper > .btn-right').click(function() {

						// clear the old data
						$('#markerInfoWrapper > .markerInfo > .middle > .btn-kekijk').remove();
						$('#markerInfoWrapper > .markerInfo > .middle > .location').remove();
						$('#markerInfoWrapper > .markerInfo > .middle > .title').remove();
						$('#markerInfoWrapper > .markerInfo > .middle > .popup-img').remove();
						$('#markerInfoWrapper > .markerInfo > .middle > .popup-club').remove();


						$('#markerInfoWrapper > .markerInfo > .middle').prepend('<a href="'+eventData[nEventId+1].url+'" class="btn-kekijk" style="display: block; width: 185px; height: 21px; margin-left: 23px; background-image: url(\'' + sDomain + '/img/map/popup/popup-btn-bekijk.gif\');"></a>');
						$('#markerInfoWrapper > .markerInfo > .middle').prepend('<div class="location" style="width: 185px; padding-left: 23px; padding-bottom: 9px; font-size: 11px; line-height: 11px; font-family: Arial, sans-serif; color: #00ab4e;">locatie: '+eventData[nEventId+1].loc+'</div>');
						$('#markerInfoWrapper > .markerInfo > .middle').prepend('<div class="title" style="width: 185px; padding-left: 23px; padding-bottom: 3px; font-size: 16px; line-height: 16px; font-family: MetaBlack, Arial, sans-serif; color: #00ab4e; text-transform: uppercase;">'+eventData[nEventId+1].title+'</div>');

						if (eventData[nEventId+1].img != null) {
							$('#markerInfoWrapper > .markerInfo > .middle').prepend('<img class="popup-img" style="margin-left: 23px; border: 1px solid #b9c3be; margin-bottom: 8px;" src="'+eventData[nEventId+1].img+'" />');
						}

						if (eventData[nEventId+1].club != null) {
							$('#markerInfoWrapper > .markerInfo > .middle').prepend('<img class="popup-club" style="position: absolute; width: 34px; height: 34px; border-right: 1px solid #b9c3be; border-bottom: 1px solid #b9c3be; margin-left: 23px;" src="'+eventData[nEventId+1].club+'" />');
						}


						nEventId = nEventId +1;

						// check if we should show the buttons
						if(nEventId == 0) {
							$('#markerInfoWrapper > .markerInfo > .middle > .group-nav > .navWrapper > .btn-left').css('visibility', 'hidden');
						} else {
							$('#markerInfoWrapper > .markerInfo > .middle > .group-nav > .navWrapper > .btn-left').css('visibility', 'visible');
						}

						if(nEventId == eventData.length-1) {
							$('#markerInfoWrapper > .markerInfo > .middle > .group-nav > .navWrapper > .btn-right').css('visibility', 'hidden');
						} else {
							$('#markerInfoWrapper > .markerInfo > .middle > .group-nav > .navWrapper > .btn-right').css('visibility', 'visible');
						}

						// update nav counter
						$('#markerInfoWrapper > .markerInfo > .middle > .group-nav > .navWrapper > .currentEvent').html(nEventId+1);
					})

				}

				// bottom
				$('#markerInfoWrapper > .markerInfo').append('<img src="'+sDomain+'img/map/popup/popup-bottom.png" />');

				// animate
				$('#markerInfoWrapper').animate({
					'margin-top' : markerOffsetTop,
					opacity : 1
				}, { 'queue' : false, 'duration' : 500, 'easing' : 'easeOutExpo' });

				$('#markerInfoWrapper > .markerInfo > .middle').prepend('<a href="'+eventData[nEventId].url+'" class="btn-kekijk" style="display: block; width: 185px; height: 21px; margin-left: 23px; background-image: url(\'' + sDomain + '/img/map/popup/popup-btn-bekijk.gif\');"></a>');
				$('#markerInfoWrapper > .markerInfo > .middle').prepend('<div class="location" style="width: 185px; padding-left: 23px; padding-bottom: 9px; font-size: 11px; line-height: 11px; font-family: Arial, sans-serif; color: #00ab4e;">locatie: '+eventData[nEventId].loc+'</div>');
				$('#markerInfoWrapper > .markerInfo > .middle').prepend('<div class="title" style="width: 185px; padding-left: 23px; padding-bottom: 3px; font-size: 16px; line-height: 16px; font-family: MetaBlack, Arial, sans-serif; color: #00ab4e; text-transform: uppercase;">'+eventData[nEventId].title+'</div>');

				if (eventData[nEventId].img != null) {
					$('#markerInfoWrapper > .markerInfo > .middle').prepend('<img class="popup-img" style="margin-left: 23px; border: 1px solid #b9c3be; margin-bottom: 8px;" src="'+eventData[nEventId].img+'" />');
				}

				if (eventData[nEventId].club != null) {
					$('#markerInfoWrapper > .markerInfo > .middle').prepend('<img class="popup-club" style="position: absolute; width: 34px; height: 34px; border-right: 1px solid #b9c3be; border-bottom: 1px solid #b9c3be; margin-left: 23px;" src="'+eventData[nEventId].club+'" />');
				}
			},
			error: function(xhr, errorType, errorMessage) {

				console.log('$.ajax() error:', errorMessage);
			}
		});


	};

	var updateMarkerInfoPosition = function() {

		// interrupt the animation tween & force full opacity
		$('#markerInfoWrapper').stop();
		$('#markerInfoWrapper').css('opacity', 1);

		// get the current maker
		var oMarker = currentMarker;

		var markerToContainerLeft = parseInt(oMarker.css('margin-left'));
		var mapviewerToContainerLeft = Math.abs(parseInt($('#mapviewer > .container').css('margin-left')) + (parseInt($('#mapviewer').css('width'))/2));

		var markerToContainerTop = parseInt(oMarker.css('margin-top'));
		var mapviewerToContainerTop = parseInt($('#mapviewer > .container').css('margin-top')) + (parseInt($('#mapviewer').css('height'))/2);

		var markerOffsetTop = markerToContainerTop + mapviewerToContainerTop + 5;
		var markerOffsetLeft = markerToContainerLeft - mapviewerToContainerLeft + 11;

		$('#markerInfoWrapper').css('margin-top', markerOffsetTop+'px');
		$('#markerInfoWrapper').css('margin-left', markerOffsetLeft+'px');

	};

	var loadData = function(newZoomLevel, sLoadDataUrl) {
		// clean up any existing markers
		$('#mapviewer > .container > .map'+newZoomLevel+' > .markers > .marker').remove();

		// clean up any markerInfo windows
		$('#markerInfoWrapper').remove();

		// check if there is a rest argument (that would for instance be passed in through the mapInputs element -> map.update())
		if(arguments[2]) {

				// load new markerData
				$.ajax({
					url : sLoadDataUrl,
					type : "GET",
					data : 'dataType=markerData&zoomLevel='+newZoomLevel+'&provinceId='+arguments[2].provinceId+'&timeId='+arguments[2].timeId+'&themeIds='+arguments[2].themeIds+'&clubTypeIds='+arguments[2].clubTypeIds+'&targetGroupIds='+arguments[2].targetGroupIds,
					dataType : 'jsonp',
					async : true,
					success: function(response) {
						
						for(i=0; i<response['data'].length;i++) {

							placeMarker(newZoomLevel, response['data'][i].lat, response['data'][i].lng, response['data'][i].id, response['data'][i].type, response['data'][i].count);

						}

						updateCounter(response['general'].total);
					},
					error: function(xhr, errorType, errorMessage) {

						console.log('$.ajax() error:', errorMessage);
					}
				});

		} else {

			// load new markerData
			$.ajax({
				url : sLoadDataUrl,
				type : "GET",
				data : 'dataType=markerData&zoomLevel='+newZoomLevel,
				dataType : 'jsonp',
				async : true,
				success: function(response) {
					
					for(i=0; i<response['data'].length;i++) {
							
						placeMarker(newZoomLevel, response['data'][i].lat, response['data'][i].lng, response['data'][i].id, response['data'][i].type, response['data'][i].count);
					}

					updateCounter(response['general'].total);
				},
				error: function(xhr, errorType, errorMessage) {

					console.log('$.ajax() error:', errorMessage);
				}
			});
		}
	};

	var setZoomLevel = function(newZoomLevel, bTileOpacityTween, bForceTileLoad, sLoadDataUrl, bShowCounter) {

		var scaleFactor;
		var zoomDirection;

		// clean up any markerInfo windows
		$('#markerInfoWrapper').remove();

		// set boundaries
		if (newZoomLevel > 0 && newZoomLevel < 4) {

			// TODO: insert direct positioning before fading based on viewport
			if(currentZoomLevel == 1 && newZoomLevel == 2) {
				scaleFactor = 3;
				zoomDirection = 'in';
			} else if (currentZoomLevel == 2 && newZoomLevel == 3) {
				scaleFactor = 2;
				zoomDirection = 'in';
			} else if (currentZoomLevel == 3 && newZoomLevel == 2) {
				scaleFactor = 2;
				zoomDirection = 'out';
			} else if (currentZoomLevel == 2 && newZoomLevel == 1) {
				scaleFactor = 3;
				zoomDirection = 'out';
			} else if (currentZoomLevel == 1 && newZoomLevel == 3) {
                scaleFactor = 6;
                zoomDirection = 'in'
            } else if (currentZoomLevel == 3 && newZoomLevel == 1) {
                scaleFactor = 6;
                zoomDirection = 'out'
            }


			// react on the new level
			switch (newZoomLevel) {

				case (1):

					// update the controls
					updateZoomControls(newZoomLevel, true, false);

					// position container
					if (zoomDirection == 'in') {
						$("#mapviewer > .container").css("margin-top", (parseInt($("#mapviewer > .container").css("margin-top"))*scaleFactor));
						$("#mapviewer > .container").css("margin-left", (parseInt($("#mapviewer > .container").css("margin-left"))*scaleFactor));
					} else if (zoomDirection == 'out') {
						$("#mapviewer > .container").css("margin-top", (parseInt($("#mapviewer > .container").css("margin-top"))/scaleFactor));
						$("#mapviewer > .container").css("margin-left", (parseInt($("#mapviewer > .container").css("margin-left"))/scaleFactor));
					}

					// clear the other maps
					$("#mapviewer > .container > .map2 > .middle").html('');
					$("#mapviewer > .container > .map3 > .middle").html('');

					// switch maps
					// TODO Setting the display property is temporary. Solves an issue when other zoom levels overlapped the current one
					$("#mapviewer > .container > .map1").css({opacity: 1, display: 'block'});
					$("#mapviewer > .container > .map2").css({opacity: 0, display: 'none'});
					$("#mapviewer > .container > .map3").css({opacity: 0, display: 'none'});

					// set zoom handle
					$("#mapviewer > .controls > .zoom > .handle").animate({
						'margin-top' : 128
					}, { 'queue' : false, 'duration' : 500, 'easing' : 'easeOutExpo' });

					// load the image tiles
					loadImageTiles('map1', 25, bTileOpacityTween, bForceTileLoad);

					// load the marker data, bases on the parsed inputfields					

					if (bMapInputsPresent == true) {
						loadData(newZoomLevel, sLoadDataUrl, website.activities.mapInputsUpdate());
					} else {
						loadData(newZoomLevel, sLoadDataUrl);
					}

					break;

				case (2):

					// update the controls
					updateZoomControls(newZoomLevel, true, true);

					// rough scaling
					if (zoomDirection == 'in') {
						$("#mapviewer > .container").css("margin-top", (parseInt($("#mapviewer > .container").css("margin-top"))*scaleFactor));
						$("#mapviewer > .container").css("margin-left", (parseInt($("#mapviewer > .container").css("margin-left"))*scaleFactor));
					} else if (zoomDirection == 'out') {
						$("#mapviewer > .container").css("margin-top", (parseInt($("#mapviewer > .container").css("margin-top"))/scaleFactor));
						$("#mapviewer > .container").css("margin-left", (parseInt($("#mapviewer > .container").css("margin-left"))/scaleFactor));
					}

					// clear the other maps
					$("#mapviewer > .container > .map1 > .middle").html('');
					$("#mapviewer > .container > .map3 > .middle").html('');

					// switch maps
					// TODO Setting the display property is temporary. Solves an issue when other zoom levels overlapped the current one
					$("#mapviewer > .container > .map1").css({opacity: 1, display: 'none'});
					$("#mapviewer > .container > .map2").css({opacity: 1, display: 'block'});
					$("#mapviewer > .container > .map3").css({opacity: 1, display: 'none'});

					// set zoom handle
					$("#mapviewer > .controls > .zoom > .handle").animate({
						'margin-top' : 87
					}, { 'queue' : false, 'duration' : 500, 'easing' : 'easeOutExpo' });

					// load the image tiles
					loadImageTiles('map2', 225, bTileOpacityTween, bForceTileLoad);

					// load the marker data, bases on the parsed inputfields
					if (bMapInputsPresent == true) {
						loadData(newZoomLevel, sLoadDataUrl, website.activities.mapInputsUpdate());
					} else {
						loadData(newZoomLevel, sLoadDataUrl);
					}

					break;

				case (3):

					// update the controls
					updateZoomControls(newZoomLevel, false, true);

					// rough scaling
					if (zoomDirection == 'in') {
						$("#mapviewer > .container").css("margin-top", (parseInt($("#mapviewer > .container").css("margin-top"))*scaleFactor));
						$("#mapviewer > .container").css("margin-left", (parseInt($("#mapviewer > .container").css("margin-left"))*scaleFactor));
					} else if (zoomDirection == 'out') {
						$("#mapviewer > .container").css("margin-top", (parseInt($("#mapviewer > .container").css("margin-top"))/scaleFactor));
						$("#mapviewer > .container").css("margin-left", (parseInt($("#mapviewer > .container").css("margin-left"))/scaleFactor));
					}

					// clear the other maps
					$("#mapviewer > .container > .map1 > .middle").html('');
					$("#mapviewer > .container > .map2 > .middle").html('');

					// switch maps
					// TODO Setting the display property is temporary. Solves an issue when other zoom levels overlapped the current one
					$("#mapviewer > .container > .map1").css({opacity: 1, display: 'none'});
					$("#mapviewer > .container > .map2").css({opacity: 1, display: 'none'});
					$("#mapviewer > .container > .map3").css({opacity: 1, display: 'block'});

					// set zoom handle
					$("#mapviewer > .controls > .zoom > .handle").animate({
						'margin-top' : 40
					}, { 'queue' : false, 'duration' : 500, 'easing' : 'easeOutExpo' });

					// load the left & right element
					$('#mapviewer > .container > .map3 > .left').attr('src', sDomain+'img/map/data/map3/left.gif');
					$('#mapviewer > .container > .map3 > .right').attr('src', sDomain+'img/map/data/map3/right.gif');

					// load the image tiles
					loadImageTiles('map3', 240, bTileOpacityTween, bForceTileLoad);

					// load the marker data, bases on the parsed inputfields
					if (bMapInputsPresent == true) {
						loadData(newZoomLevel, sLoadDataUrl, website.activities.mapInputsUpdate());
					} else {
						loadData(newZoomLevel, sLoadDataUrl);
					}

					break;
			}


			// update the currentZoomLevel
			currentZoomLevel = newZoomLevel;
		}
	}

	var showCounter = function() {

		var template = $('<div id="counter"><img src="'+sDomain+'img/map/counter/counter_info.png" /></div>').css({
			'position': 'absolute',
			'z-index': '1',
			'bottom': '130px',
			'left': '50%',
			'margin-left': '381px',
			'width': '82px'
		})

		template.prepend($('$<div class="count"></div>').css({
			'float': 'right',
			'font-family': 'MetaBlack, Arial, sans-serif',
			'font-size': '29px',
			'color': 'white'
		}));

		$('#mapviewer').prepend(template);
	}

	var updateCounter = function(sCount) {
		$('#counter > .count').html(sCount);
	}

	/*
		public methods
	*/

	pub.update = function() {

		/*
			read the rest arguments and pass these trough tot the loadData method
		*/
		
		// load new markerData for the current zoomLevel (loadData() clears any existing marker & popup elements)
		loadData(currentZoomLevel, sLoadDataUrl, arguments[0]);
	}

	// call constructor
	init(oSettings);

	// expose public methods / objects
	return pub;

};
