(function() {
    var oBWMapObjects = {};

	function loadScript(sScriptUrl, fCallback) {
		var oScript 	= document.createElement('script');
		oScript.src 	= sScriptUrl;
		oScript.type 	= 'text/javascript';
		oScript.onload	= fCallback; // load calendar
		// load callback for IE<=8
		oScript.onreadystatechange = function() {
			if (this.readyState == 'loaded' || this.readyState == 'complete') {
				fCallback(); // load calendar
			}
		};
		document.getElementsByTagName('head')[0].appendChild(oScript);
	}

	var browser = function() {
		var ua = navigator.userAgent;
		return {
			ie: ua.match(/MSIE\s([^;]*)/)
		};
    }();

	var URL_BASE 		= 'http://www.maastrichtbereikbaar.nl/',
		months 			= ['januari','februari','maart','april', 'mei','juni','juli','augustus','september','oktober','november','december'],
		isLoaded 		= false,
		bWidgetCodeLoaded 	= false;
		oBWMap = null;
		oBWData = null;
		oBWMarkers = null,
		mmb_ParkingspotOverlay,
		iHeaderHeight = 52,
		iFooterHeight = 24,
		iWidgetWidth = 0,
		iWidgetHeight = 0
		//var iFooterHeight = 28;
		//var iHeaderHeight = 49;

	oBWMapObjects = {
		'googleMap': {
			'oMap': null,
			'isLoaded': false
		},
		'businessObjects': {
			'aMarkers': [],
			'isLoaded': false
		},
		'roadworkObjects': {
			// by severity 0-4
			'oRoadWorkMarkers': {
				  0 : []
				, 1 : []
				, 2 : []
				, 3 : []
				, 4 : []
			},
			'isLoaded': false
		},
        'parkingObjects': {
			'oParkingMarkers': [],
			'isLoaded': false
		},
        'trafficLayerObjects': {
            'oTrafficLayer': null,
            'isLoaded': false
        }
	}
	//console.log('define bwmapobjects');
	//console.log(oBWMapObjects.roadworkObjects.oRoadWorkMarkers);
	//setTimeout(function() {console.log('timeout!'); oBWMapObjects.roadworkObjects.oRoadWorkMarkers[0][0] = 'test';}, 5000);

	function loadBWBinds(oBusinessWidget) {
		var toggleCalItem = function(oItem) {

			var oContent		= oItem.find('.cal-item-content'),
				oIntro			= oContent.children('.cal-item-text'),
				oExpand			= oContent.children('.cal-item-text-full'),
				oArrow			= oItem.find('.cal-item-arrow');


			if (oIntro.is('div:visible')) {
				oExpand.show();
				oIntro.hide();
				oItem.addClass('cal-item-active');
				oArrow.arrow({ width: 15, height: 8, direction: 'up'});
			} else {
				oContent.height('auto');
				oItem.removeClass('cal-item-active');
				oExpand.hide();
				oIntro.show();
				oArrow.arrow({ width: 15, height: 8, direction: 'down'});
			}

		};

		oBusinessWidget
			.delegate('.cal-item', 'click', function(e) {

				var oCurrObj 		= $(this),
					oHasTextFull 	= oCurrObj.find('.cal-item-text-full'),
					oCurrOpen 		= oBusinessWidget.find('.cal-item-text-full:visible').closest('.cal-item');

				if (oHasTextFull.length > 0) {
					if (oCurrOpen.length > 0 && oCurrOpen[0] != oCurrObj[0]) {
						toggleCalItem(oCurrOpen);
					}
					toggleCalItem(oCurrObj);
				}

			})
			.delegate('.cal-item-expandable', 'hover', function(e) {

				$(this).toggleClass('cal-item-expandable-hover');

			});
	}

	function mmb_getBWMarkerImageAndShape(sType) {
		var oRet = { oImage: null, oShape: null };
		var sIconUrl = URL_BASE + 'modules/mijnmb/img/markers/'+sType+'.png';
		var iWidth = 0;
		var iHeight = 0;
		var iCenterPosX = 0;
		var iCenterPosY = 0;
		var oShape = null;

		switch(sType){
			case 'business_default':
				iWidth = 48;
				iHeight = 68;
				iCenterPosX = 24;
				iCenterPosY = 66;
				oRet.oShape = {
					coord: [27,0,29,1,30,2,32,3,33,4,34,5,36,6,37,7,39,8,40,9,41,10,43,11,44,12,46,13,47,14,47,15,47,16,47,17,47,18,47,19,47,20,47,21,47,22,47,23,47,24,47,25,47,26,47,27,47,28,47,29,47,30,47,31,47,32,47,33,47,34,47,35,47,36,47,37,47,38,47,39,47,40,47,41,47,42,47,43,47,44,47,45,47,46,47,47,47,48,47,49,47,50,47,51,47,52,47,53,47,54,47,55,46,56,46,57,46,58,45,59,43,60,42,61,40,62,39,63,38,64,36,65,35,66,32,67,20,67,18,66,11,65,10,64,9,63,8,62,6,61,4,60,3,59,3,58,2,57,2,56,2,55,2,54,1,53,0,52,0,51,0,50,0,49,0,48,0,47,0,46,0,45,0,44,0,43,0,42,0,41,0,40,0,39,0,38,0,37,0,36,0,35,0,34,0,33,0,32,0,31,0,30,0,29,0,28,0,27,0,26,0,25,0,24,0,23,0,22,0,21,0,20,0,19,0,18,0,17,0,16,0,15,1,14,2,13,3,12,5,11,6,10,7,9,9,8,10,7,12,6,13,5,14,4,16,3,17,2,19,1,20,0,27,0],
					type: 'poly'
				  };
				break;
			case 'business_store':
				iWidth = 54;
				iHeight = 68;
				iCenterPosX = 27;
				iCenterPosY = 66;
				oRet.oShape = {
					coord: [24,0,29,1,31,2,32,3,33,4,35,5,36,6,38,7,39,8,41,9,42,10,43,11,45,12,46,13,48,14,49,15,51,16,51,17,52,18,52,19,52,20,52,21,52,22,52,23,51,24,51,25,50,26,50,27,50,28,51,29,51,30,51,31,51,32,51,33,51,34,52,35,52,36,53,37,53,38,53,39,53,40,53,41,53,42,53,43,53,44,53,45,53,46,53,47,52,48,50,49,50,50,50,51,50,52,50,53,49,54,47,55,46,56,45,57,44,58,43,59,42,60,40,61,39,62,38,63,35,64,33,65,32,66,30,67,23,67,21,66,20,65,18,64,16,63,14,62,13,61,11,60,10,59,9,58,9,57,7,56,6,55,4,54,4,53,3,52,3,51,3,50,3,49,1,48,0,47,0,46,0,45,0,44,0,43,0,42,0,41,0,40,0,39,0,38,0,37,1,36,1,35,2,34,2,33,2,32,2,31,2,30,2,29,3,28,3,27,3,26,3,25,2,24,1,23,1,22,1,21,1,20,1,19,1,18,2,17,2,16,3,15,3,14,4,13,5,12,5,11,6,10,6,9,7,8,8,7,8,6,9,5,10,4,10,3,11,2,12,1,13,0,24,0],
					type: 'poly'
				  };
				break;
			case 'business_factory':
				iWidth = 58;
				iHeight = 68;
				iCenterPosX = 29;
				iCenterPosY = 66;
				oRet.oShape = {
					coord: [35,0,36,1,36,2,36,3,40,4,41,5,42,6,42,7,46,8,47,9,48,10,48,11,51,12,53,13,54,14,54,15,54,16,54,17,54,18,54,19,54,20,54,21,54,22,54,23,55,24,55,25,55,26,55,27,55,28,56,29,57,30,57,31,57,32,57,33,57,34,57,35,57,36,57,37,57,38,57,39,57,40,57,41,57,42,57,43,57,44,57,45,57,46,57,47,57,48,56,49,55,50,54,51,53,52,51,53,50,54,48,55,47,56,45,57,44,58,43,59,41,60,40,61,38,62,37,63,36,64,34,65,27,66,26,67,18,67,17,66,15,65,14,64,12,63,11,62,9,61,7,60,6,59,4,58,3,57,1,56,1,55,0,54,0,53,0,52,0,51,0,50,0,49,0,48,0,47,0,46,0,45,0,44,0,43,0,42,0,41,0,40,0,39,1,38,2,37,3,36,3,35,3,34,3,33,3,32,3,31,3,30,4,29,4,28,5,27,5,26,6,25,7,24,7,23,8,22,8,21,9,20,11,19,13,18,14,17,15,16,17,15,19,14,20,13,20,12,23,11,23,10,23,9,23,8,23,7,23,6,23,5,23,4,24,3,24,2,24,1,25,0,35,0],
					type: 'poly'
				  };
				break;
			case 'business_cultural':
				iWidth = 56;
				iHeight = 68;
				iCenterPosX = 28;
				iCenterPosY = 66;
				oRet.oShape = {
					coord: [30,0,32,1,33,2,35,3,36,4,38,5,39,6,40,7,42,8,43,9,45,10,46,11,48,12,49,13,50,14,52,15,53,16,54,17,55,18,55,19,55,20,55,21,55,22,55,23,55,24,55,25,55,26,55,27,55,28,55,29,55,30,55,31,55,32,55,33,55,34,55,35,55,36,55,37,55,38,55,39,55,40,55,41,55,42,55,43,55,44,55,45,55,46,55,47,55,48,55,49,55,50,55,51,54,52,52,53,51,54,50,55,48,56,47,57,45,58,44,59,42,60,40,61,36,62,34,63,33,64,32,65,30,66,29,67,21,67,20,66,18,65,17,64,15,63,14,62,12,61,11,60,10,59,8,58,7,57,5,56,4,55,2,54,1,53,0,52,0,51,0,50,0,49,0,48,0,47,0,46,0,45,0,44,1,43,2,42,2,41,2,40,2,39,2,38,2,37,1,36,0,35,0,34,0,33,0,32,0,31,0,30,0,29,0,28,0,27,1,26,2,25,3,24,5,23,6,22,8,21,9,20,9,19,9,18,9,17,9,16,9,15,9,14,9,13,9,12,10,11,10,10,10,9,12,8,13,7,14,6,16,5,17,4,19,3,20,2,22,1,23,0,30,0],
					type: 'poly'
				  };
				break;
			default:
				iWidth = 42;
				iHeight = 57;
				iCenterPosX = 21;
				iCenterPosY = 57;
				oShape = {
					coord: [35,0,37,1,38,2,39,3,40,4,40,5,41,6,41,7,41,8,41,9,41,10,41,11,41,12,41,13,41,14,41,15,41,16,41,17,41,18,41,19,41,20,41,21,41,22,41,23,41,24,41,25,41,26,41,27,41,28,41,29,41,30,41,31,41,32,41,33,41,34,41,35,40,36,40,37,39,38,38,39,37,40,35,41,28,42,27,43,27,44,27,45,27,46,26,47,26,48,26,49,26,50,25,51,25,52,25,53,25,54,24,55,23,56,18,56,17,55,16,54,16,53,16,52,16,51,15,50,15,49,15,48,15,47,14,46,14,45,14,44,14,43,13,42,6,41,4,40,3,39,2,38,1,37,1,36,0,35,0,34,0,33,0,32,0,31,0,30,0,29,0,28,0,27,0,26,0,25,0,24,0,23,0,22,0,21,0,20,0,19,0,18,0,17,0,16,0,15,0,14,0,13,0,12,0,11,0,10,0,9,0,8,0,7,0,6,1,5,1,4,2,3,3,2,4,1,6,0,35,0],
					type: 'poly'
				  };
				break;
		}

		oRet.oImage = new google.maps.MarkerImage(sIconUrl,
			new google.maps.Size(iWidth, iHeight),
			new google.maps.Point(0,0),
			new google.maps.Point(iCenterPosX, iCenterPosY)
		);

		return oRet;
	}

	function mmb_createBWMarker(oLatLng, sType) {
		var oReturnMarker;

		var oSI = mmb_getBWMarkerImageAndShape(sType);

		var oReturnMarker = new google.maps.Marker({
			position: oLatLng,
			map: null,
			icon: oSI.oImage,
			shape: oSI.oShape,
			zIndex: 1,
			draggable: false
		});

		oReturnMarker.infoWindow = new google.maps.InfoWindow({
			maxWidth: 200
		});

		return oReturnMarker;
	}


	// BUSINESS WIDGET LOADER FUNCTIONS
	function loadBWStyle() {

		// load external stylesheet
		var linkElement 	= document.createElement('link');
		linkElement.href 	= URL_BASE+'modules/mijnmb/business.widget.css';
		linkElement.rel 	= 'stylesheet';
		linkElement.type 	= 'text/css';
        document.getElementsByTagName('head')[0].appendChild(linkElement);

		var rules = '',
			theme = oBusinessWidget.config.theme,
			newHeight = (oBusinessWidget.config.height == 'auto') ? oBusinessWidget.config.height : (parseInt(oBusinessWidget.config.height)-90)+'px';

		rules += '\
			#mbr-businessWidget-container .bw-header .bw-header-star { \
				background-color: '+theme.maincolor+'; \
			} \
			#mbr-businessWidget-container .bw-header .bw-header-bottom { \
				background-color: '+theme.maincolor+'; \
			} \
            #mbr-businessWidget-container .bw-header .bw-header-tab-moreinfo { \
				background-color: '+theme.maincolor+'; \
			} \
			#mbr-businessWidget-container .mbr-businessWidget-footer a, #mbr-businessWidget-container .mbr-businessWidget-header a { color: '+theme.maincolor+'; } \
			#mbr-businessWidget-container a { text-decoration: none; color: '+theme.maincolor+'; } \
			#mbr-businessWidget-container a:hover { text-decoration: underline; } \
			#mbr-businessWidget-container div.mbr-businessWidget-content { \
				height: '+newHeight+'; \
			} \
		';

		var styleElement 	= document.createElement('style');
        styleElement.type 	= 'text/css';
		styleElement.id 	= 'calWidgetStyle';
        if (browser.ie) {
			styleElement.styleSheet.cssText = rules;
        } else {
			var frag = document.createDocumentFragment();
			frag.appendChild(document.createTextNode(rules));
			styleElement.appendChild(frag);
        }

        document.getElementsByTagName('head')[0].appendChild(styleElement);

    };

	function svg(tag, attr) {
		var el = document.createElementNS("http://www.w3.org/2000/svg", tag || 'svg');
		if (attr) {
			$.each(attr, function(k, v) {
				el.setAttributeNS(null, k, v);
			});
		}
		return $(el);
	}

	function loadCalEmpty() {

		var html 	= '',
			div 	= document.createElement('div');

		html = 'Geen agendaitems';

		div.id 			= 'cal-item-empty';
		div.innerHTML 	= html;

		return div;
    }

	function mmb_ajaxLoadData(sUrl, oData, oSuccessCallback){
		oData.noCache = new Date().getTime();

		$.getJSON(sUrl+'?&callback=?', oData, oSuccessCallback);
	}


	/**
	 * ROADWORK FUNCTIONS
	 **/
	function mmb_createRoadworkMarker(oRoadwork, oLatLng, iSeverity) {
		var oReturnMarker;

		var oIconImage;
		var oShape = null;
		var oShadow = null;

		if (oRoadwork.sDisplayType == 'event') {
			oShape = {
				coord: [0, 0, 33, 29],
				type: 'rect'
			}
			oShadow = new google.maps.MarkerImage(URL_BASE + 'modules/gmaps/img/eventmarker_shadow.png',
				new google.maps.Size(49, 22),
				new google.maps.Point(0,0),
				new google.maps.Point(15, 22)
			);
		}
		else {
			oShape = {
				coord: [0, 29, 17, 0, 22, 29],
				type: 'poly'
			}
			oShadow = new google.maps.MarkerImage(URL_BASE + 'modules/gmaps/img/roadworkmarker_shadow.png',
				new google.maps.Size(40, 25),
				new google.maps.Point(0,0),
				new google.maps.Point(14, 25)
			);
		}

		var sIconUrl = '';
		switch(iSeverity) {
			case 4:
				sIconUrl = URL_BASE + 'modules/gmaps/img/' + oRoadwork.sDisplayType + 'marker_s4.png';
				break;
			case 3:
				sIconUrl = URL_BASE + 'modules/gmaps/img/' + oRoadwork.sDisplayType + 'marker_s3.png';
				break;
			case 2:
				sIconUrl = URL_BASE + 'modules/gmaps/img/' + oRoadwork.sDisplayType + 'marker_s2.png';
				break;
			case 1:
				sIconUrl = URL_BASE + 'modules/gmaps/img/' + oRoadwork.sDisplayType + 'marker_s1.png';
				break;
			case 0:
			default:
				sIconUrl = URL_BASE + 'modules/gmaps/img/' + oRoadwork.sDisplayType + 'marker_s0.png';
				break;
		}
		oIconImage = new google.maps.MarkerImage(sIconUrl,
			new google.maps.Size(33, 36),
			new google.maps.Point(0,0),
			new google.maps.Point(17, 36)
		);

		var oReturnMarker = new google.maps.Marker({
			position: oLatLng,
			map: null,
			shadow: oShadow,
			icon: oIconImage,
			shape: oShape,
			timePeriod: oRoadwork.iTimePeriod,
			displayType: oRoadwork.sDisplayType,
			zIndex: 1
		});

		return oReturnMarker;
	}


	function mmb_createRoadworkInfoWindow(oRoadwork) {
		var oRetInfoWindow = null;

		// create detour string

		var sDetourHTML = '';
		if (oRoadwork.aDetours.length == 0) {
			sDetourHTML = '<div class="detour-block">Geen omleidingen bekend.</div>'
		}
		else {
			for (i in oRoadwork.aDetours) {
				var oDetour = oRoadwork.aDetours[i];

				sDetourHTML +=
					'<div class="detour-block">' +
						'<b>' + oDetour.sName + '</b><br>' +
						oDetour.sText +
					'</div>';
			}
		}

		var sContentString =
			'<div id="roadwork-infowindow" class="roadwork-infowindow"> \
				<b>' + oRoadwork.sName + '</b> \
				<p>' + oRoadwork.sDescription + '</p> \
				<p><b>Type:</b> ' + oRoadwork.sTypeName + '</p> \
				<p><b>Periode:</b> ' + oRoadwork.sDurationDescription + '</p> \
				<p><b>Omleidingen:</b></p> \
				' + sDetourHTML +
			'</div>';

		var oRetInfoWindow = new google.maps.InfoWindow({
			content: sContentString,
			maxWidth: 250
		});

		return oRetInfoWindow;
	}

	function mmb_hideRoadWork(iSeverity) {
		var oRoadWorkMarkers = oBWMapObjects.roadworkObjects.oRoadWorkMarkers[iSeverity];

		if (oRoadWorkMarkers) {
			var i = oRoadWorkMarkers.length;
			while(--i) {
				if (oRoadWorkMarkers[i].displayType == 'roadwork') {
					oRoadWorkMarkers[i].setMap(null);
				}
			}
		}
	}

	function mmb_hideEvents(iSeverity) {
		var oRoadWorkMarkers = oBWMapObjects.roadworkObjects.oRoadWorkMarkers[iSeverity];

		if (oRoadWorkMarkers) {
			var i = oRoadWorkMarkers.length;
			while(--i) {
				if (oRoadWorkMarkers[i].displayType == 'event') {
					oRoadWorkMarkers[i].setMap(null);
				}
			}
		}
	}

	function mmb_showRoadWorkSpecific(iSeverity, sDisplayType, iTimePeriod) {
		var oRoadWorkMarkers = oBWMapObjects.roadworkObjects.oRoadWorkMarkers[iSeverity];

		if (oRoadWorkMarkers.length > 0) {
			var i = oRoadWorkMarkers.length;
			while(--i) {
				if ((oRoadWorkMarkers[i].timePeriod > 0) &&
					(oRoadWorkMarkers[i].timePeriod <= iTimePeriod)) {
					if ((oRoadWorkMarkers[i].displayType == sDisplayType)) {
						oRoadWorkMarkers[i].setMap(oBWMapObjects.googleMap.oMap);
					}
				}
				else {
					oRoadWorkMarkers[i].setMap(null);
				}
			}
		}
	}

	function mmb_loadRoadWorkCallback(oRoadWorkJSON) {
		for (iSeverityIndex in oRoadWorkJSON) {
			var iSevLen = oRoadWorkJSON[iSeverityIndex].length;
			for (var i = 0; i < iSevLen; i++) {
				var oRoadwork = oRoadWorkJSON[iSeverityIndex][i];
				var aDisplayPositions = oRoadwork.aDisplayPositions;
				var iStartIndex = oBWMapObjects.roadworkObjects.oRoadWorkMarkers[iSeverityIndex].length;

				var iDpLen = aDisplayPositions.length;
				for (var j = 0; j < iDpLen; j++) {
					var oDisplayPosition = aDisplayPositions[j];

					var oLatLng = new google.maps.LatLng(oDisplayPosition.lat, oDisplayPosition.lng);

					var oMarker = mmb_createRoadworkMarker(oRoadwork, oLatLng, parseInt(iSeverityIndex));

					if(oMarker != '') {
						// create infowindow
						var oInfoWindow = mmb_createRoadworkInfoWindow(oRoadwork);
						oMarker.infowindow = oInfoWindow;

						google.maps.event.addListener(oMarker, 'click', function() {
							this.infowindow.open(oBWMapObjects.googleMap.oMap, this);
							$('#roadwork-infowindow').parent().each(function() { $(this).css('overflow', 'hidden') });
						});
						oBWMapObjects.roadworkObjects.oRoadWorkMarkers[iSeverityIndex].push(oMarker);
					}
					else {
						console.log( 'nothing found' );
					}
				}
			}
		}

		oBWMapObjects.roadworkObjects.isLoaded = true;
	}

    function mmb_getMarkerMainLocation() {
        var oRetMarker = null;
        var aMarkers = oBWMapObjects.businessObjects.aMarkers;

        for(var i = 0; i < aMarkers.length; i++) {
            if(parseInt(aMarkers[i].data.iIsMainLocation) == 1) {
                oRetMarker = aMarkers[i];
                break;
            }
        }

        return oRetMarker;
    }

    /**
    * Creates a Parking marker of a specific type
    *
    * @param oLatLng the location of the marker
    * @param iZIndex the zindex of the marker
    * @param the type of the marker, can be
    *        - parking (default)
    *        - parkandwalk
    *        - parkandride
    *
    * @return a google.maps.MarkerImage object
    **/
   function mmb_createParkingMarker(oLatLng, iZIndex, sType) {
       var oReturnMarker;

       var oIconImage;
       var oShape = {
           coord: [0, 0, 32, 49],
           type: 'rect'
       };
       var oShadow = new google.maps.MarkerImage(URL_BASE + 'modules/gmaps/img/parkingmarker_shadow.png',
           new google.maps.Size(59, 32),
           new google.maps.Point(0,0),
           new google.maps.Point(12, 32)
       );

       switch(sType) {
           case 'parkandwalk':
               oIconImage = new google.maps.MarkerImage(URL_BASE + 'modules/gmaps/img/parkandwalkmarker_v2.png',
                   new google.maps.Size(32, 58),
                   new google.maps.Point(0,0),
                   new google.maps.Point(17, 58)
               );
               break;
           case 'parkandride':
               oIconImage = new google.maps.MarkerImage(URL_BASE + 'modules/gmaps/img/parkandridemarker_v2.png',
                   new google.maps.Size(32, 58),
                   new google.maps.Point(0,0),
                   new google.maps.Point(17, 58)
               );
               break;
           case 'parking':
           default:
               oIconImage = new google.maps.MarkerImage(URL_BASE + 'modules/gmaps/img/parkingmarker_v2.png',
                   new google.maps.Size(32, 58),
                   new google.maps.Point(0,0),
                   new google.maps.Point(17, 58)
               );
           break;
       }

       var oReturnMarker = new google.maps.Marker({
           position: oLatLng,
           map: null,
           shadow: oShadow,
           icon: oIconImage,
           shape: oShape,
           zIndex: iZIndex
       });

       return oReturnMarker;
   }

    function mmb_hideParkingLocations() {
        var oParkingMarkers = oBWMapObjects.parkingObjects.oParkingMarkers;

        if (oParkingMarkers) {
            clearInterval(oBWMapObjects.parkingObjects.sUpdateIntervalId);
            oBWMapObjects.parkingObjects.sUpdateIntervalId = '';

            for (var sIndex in oParkingMarkers) {
                oParkingMarkers[sIndex].setMap(null);
                oParkingMarkers[sIndex].overlay.setMap(null);
            }
        }
    }

    function mmb_showParkingLocations() {
        var oParkingMarkers = oBWMapObjects.parkingObjects.oParkingMarkers;

        // filter out parking locations within 500 mtr (test)?
        var oMainMarker = mmb_getMarkerMainLocation();
        if (oParkingMarkers && oMainMarker != null) {
			var i = oParkingMarkers.length;
            for(sIndex in oParkingMarkers) {
				if(oParkingMarkers.hasOwnProperty(sIndex)) {
					var oCurrMarker = oParkingMarkers[sIndex];
					var distanceInMetres = google.maps.geometry.spherical.computeDistanceBetween(oMainMarker.getPosition(), oCurrMarker.getPosition());
					if(distanceInMetres < 500) {
						oCurrMarker.setMap(oBWMapObjects.googleMap.oMap);
						oCurrMarker.overlay.setMap(oBWMapObjects.googleMap.oMap);
					}
					else {
						oCurrMarker.setMap(null);
						oCurrMarker.overlay.setMap(null);
					}
				}
            }
        }
    }


    function mmb_loadParkingsCallback(oParkingsJSON) {
		if (oParkingsJSON !== '0') {
		for (var i = 0; i < oParkingsJSON.length; i++) {
                var aParking = oParkingsJSON[i];
                var oLatlng = new google.maps.LatLng(aParking['sLatitude'], aParking['sLongitude']);
                var iZIndex = (oParkingsJSON.length - i) * 10;

                var oMarker = mmb_createParkingMarker(oLatlng, iZIndex, aParking['sType']);
                var oMmb_ParkingspotOverlay = new mmb_ParkingspotOverlay({
                    map: null,
                    id: aParking['iId'],
                    freespots: parseInt(aParking['iFreeParkingSpots']),
                    totalspots: parseInt(aParking['iTotalParkingSpots']),
                    zIndex: oMarker.getZIndex() + 1
                });

                oMmb_ParkingspotOverlay.bindTo('position', oMarker, 'position');

                oMarker.overlay = oMmb_ParkingspotOverlay;

                // add info window met parkeer info
                var sContent = '<b>' + aParking.sName + '</b><br/> \
                               ' + aParking.sAddress + '<br/> \
                               ' + aParking.sZip + '<br/> \
                               ' + aParking.sCity + '<br/>';
                oMarker.infoWindow = new google.maps.InfoWindow({
                    content: sContent,
                    maxWidth: 200
                });
                google.maps.event.addListener(oMarker, 'click', function(oEvent) {
                    this.infoWindow.open(oBWMapObjects.googleMap.oMap, this);
                });

                // append to parkingmarkers global
                oBWMapObjects.parkingObjects.oParkingMarkers[aParking['sName']] = oMarker;

            }

            oBWMapObjects.parkingObjects.isLoaded = true;
        }
    }

    function mmb_showTrafficLayer() {
        oBWMapObjects.trafficLayerObjects.oTrafficLayer.setMap(oBWMapObjects.googleMap.oMap);
    }
    function mmb_hideTrafficLayer() {
        oBWMapObjects.trafficLayerObjects.oTrafficLayer.setMap(null);
    }
    function mmb_loadTrafficLayer() {
        oBWMapObjects.trafficLayerObjects.oTrafficLayer = new google.maps.TrafficLayer();

        oBWMapObjects.trafficLayerObjects.isLoaded = true;
    }

    function mmb_showAllFilters() {
    	// show markers
		var iTimePeriod = 2; //coming week
		if(oBusinessWidget.config.filters.roadwork) {
			mmb_showRoadWorkSpecific(4, 'roadwork', iTimePeriod);
			mmb_showRoadWorkSpecific(3, 'roadwork', iTimePeriod);
			mmb_showRoadWorkSpecific(2, 'roadwork', iTimePeriod);
			mmb_showRoadWorkSpecific(1, 'roadwork', iTimePeriod);
			mmb_showRoadWorkSpecific(0, 'roadwork', iTimePeriod);
	        mmb_showRoadWorkSpecific(4, 'event', iTimePeriod);
			mmb_showRoadWorkSpecific(3, 'event', iTimePeriod);
			mmb_showRoadWorkSpecific(2, 'event', iTimePeriod);
			mmb_showRoadWorkSpecific(1, 'event', iTimePeriod);
			mmb_showRoadWorkSpecific(0, 'event', iTimePeriod);

			//mmb_arrangeMarkerZIndices();
		}
    	if(oBusinessWidget.config.filters.parkings) {
            	mmb_showParkingLocations();
            }
       	if(oBusinessWidget.config.filters.traffic) {
        	mmb_showTrafficLayer();
        }
    }

    function mmb_loadWidgetPoll() {
	    if(oBWMapObjects.googleMap.isLoaded &&
	       oBWMapObjects.businessObjects.isLoaded &&
	       oBWMapObjects.roadworkObjects.isLoaded &&
	       oBWMapObjects.parkingObjects.isLoaded &&
	       oBWMapObjects.trafficLayerObjects.isLoaded) {

		   mmb_arrangeMarkerZIndices();
	       mmb_showAllFilters();
		   $(document).trigger('mmb-bw-ready');
	    }
	    else {
	        setTimeout(mmb_loadWidgetPoll, 1000);
	    }
	}

	function loadBWMapFilters() {
		mmb_ajaxLoadData(URL_BASE + 'modules/mijnmb/ajax.get.roadworkjson.php', {}, mmb_loadRoadWorkCallback);
        mmb_ajaxLoadData(URL_BASE + 'modules/mijnmb/ajax.get.parkingsjson.php', {}, mmb_loadParkingsCallback);
        mmb_loadTrafficLayer();

        mmb_loadWidgetPoll();
	}

	/**
	 * GENERAL MARKER FUNCTIONS
	 **/
	function mmb_compareMarkerPosition(oLeft, oRight) {
		var iResult;

		try {
			var a = parseFloat(oLeft.getPosition().lat());
			var b = parseFloat(oRight.getPosition().lat());

			if (a == b) {
				iResult = 0;
			}

			iResult = (a < b) ? 1 : -1;
		}
		catch(e) {
			//console.log('mmb_compareMarkerPosition');
			//console.log(oLeft);
			//console.log(oRight);
		}

		return iResult;
	}
	/**
	 * Arrange z-indices for all map markers: ascending by lat position.
	 **/
	function mmb_arrangeMarkerZIndices() {
		var oAllMarkers = oBWMapObjects.roadworkObjects.oRoadWorkMarkers[0].concat(
			oBWMapObjects.roadworkObjects.oRoadWorkMarkers[1],
			oBWMapObjects.roadworkObjects.oRoadWorkMarkers[2],
			oBWMapObjects.roadworkObjects.oRoadWorkMarkers[3],
			oBWMapObjects.roadworkObjects.oRoadWorkMarkers[4],
			oBWMapObjects.businessObjects.aMarkers
		);

		// exception for Parking Markers. They have a string index.
		if(oBWMapObjects.parkingObjects.oParkingMarkers.length > 0) {
			for(var sIndex in oBWMapObjects.parkingObjects.oParkingMarkers) {
				oAllMarkers.push(oBWMapObjects.parkingObjects.oParkingMarkers[sIndex]);
			}
		}

		oAllMarkers.sort(mmb_compareMarkerPosition);
		var iZIndex = 10;
		for (var i = 0; i < oAllMarkers.length; i++) {
			oAllMarkers[i].setZIndex(iZIndex);

			// exception for Parking Markers that contain an overlay over their marker.
			if (oAllMarkers[i].overlay) {
				iZIndex++;
				oAllMarkers[i].overlay.setZ(iZIndex);
			}

			iZIndex++;
		}
	}

	function mmb_loadBWMapMarkersCallback(oMarkersJSON) {
		for (var i = 0; i < oMarkersJSON.length; i++) {
			var oData = oMarkersJSON[i];

			var oLatLng = new google.maps.LatLng(parseFloat(oData.sLat), parseFloat(oData.sLng));
			var oMarker = mmb_createBWMarker(oLatLng, oData.sType);

			oMarker.data = oData;
			google.maps.event.addListener(oMarker, 'click', function(oEvent) {
				var sContent = '<b>'+this.data.sTitle+'</b><br/>'+this.data.sDescription;

				this.infoWindow.setContent(sContent);
				this.infoWindow.open(oBWMapObjects.googleMap.oMap, this);
			});

			oMarker.setMap(oBWMapObjects.googleMap.oMap);

			oBWMapObjects.businessObjects.aMarkers.push(oMarker);
		}

		oBWMapObjects.businessObjects.isLoaded = true;
	}

	function loadBWMapMarkers() {
		var oData = { iWidgetId: oBusinessWidget.config.id, noCache: new Date().getTime() };
		var sUrl = URL_BASE + 'modules/mijnmb/ajax.get.widgetmarkersjson.php';

		mmb_ajaxLoadData(sUrl, oData, mmb_loadBWMapMarkersCallback);
	}

	function loadBWMap() {
		var iPadding = 9;
		var iHeight = oBusinessWidget.widgetContent.height();
		var iWidth = oBusinessWidget.widget.width() - (iPadding*2);

		oBusinessWidget.widgetContent.html(' \
			<div id="mbr-bw-map" class="bw-map" style="width: '+iWidth+'px; height: '+iHeight+'px;"></div> \
            <div id="mbr-moreinfo" class="bw-moreinfo" style="background-color: #ffffff; display:none; width: '+iWidth+'px; height: '+(iHeight-2)+'px;"> \
            <p style="padding: 5px;"> \
                <b>Wat is de ondernemerswidget?</b><br/> \
                Met de widget kan een ondernemer een kaart van Maastricht genereren op de contactpagina van zijn of haar website.<br/>  \
                Centraal op de plattegrond staat de vestiging van het bedrijf met de parkeergelegenheden voor auto en fiets in de buurt van het bedrijf en de actuele informatie over wegwerkzaamheden. De widget is een directe link naar de site Maastricht-Bereikbaar.nl en krijgt binnenkort ook een eigen routeplanner.<br/>  \
                <br/> \
                De ondernemer kan zelf informatie aan de widget toevoegen en heel precies aangeven wat de locatie is van bijvoorbeeld laad-en los-perron, parkeerterrein of fietsstalling van het bedrijf. De widget is aan te passen aan de kleurstelling en kolombreedte van de eigen website.\
            </p> \
            </div> \
		');

		var oMapDiv = document.getElementById('mbr-bw-map');
		var oLatlng = new google.maps.LatLng(parseFloat(oBWData.lat), parseFloat(oBWData.lng));

		var oMyOptions = {
			zoom: parseInt(oBusinessWidget.config.zoom),
			center: oLatlng,
			mapTypeId: google.maps.MapTypeId.ROADMAP,
			streetViewControl: true,
			mapTypeControlOptions: { mapTypeIds: [google.maps.MapTypeId.ROADMAP, google.maps.MapTypeId.SATELLITE, google.maps.MapTypeId.HYBRID]}
		};
		try {
			var oMap = oBWMapObjects.googleMap.oMap =  new google.maps.Map(oMapDiv, oMyOptions);
			google.maps.event.trigger(oMap, 'resize');
			oBWMapObjects.googleMap.isLoaded = true;

			// load business markers
			loadBWMapMarkers();

			// load filters
			loadBWMapFilters();
		}
		catch(e) {
			//console.log(e);
		}
	}

    function loadBWContentBinds() {
        oBusinessWidget.widgetHeader.find('.bw-header-tab-moreinfo')
        .unbind('click')
        .bind('click', function() {
            var oThis = $(this);
            oThis.removeClass('class', 'bw-header-tab-moreinfo-active');
            oBusinessWidget.widgetHeader.find('.bw-header-tab-map').removeClass('bw-header-tab-map-active');

            oThis.addClass('bw-header-tab-moreinfo-active');

            oBusinessWidget.widgetContent.find('#mbr-bw-map').hide();
            oBusinessWidget.widgetContent.find('#mbr-moreinfo').show();
        });

        oBusinessWidget.widgetHeader.find('.bw-header-tab-map')
        .unbind('click')
        .bind('click', function() {
            var oThis = $(this);
            oThis.removeClass('bw-header-tab-map-active');
            oBusinessWidget.widgetHeader.find('.bw-header-tab-moreinfo').removeClass('bw-header-tab-moreinfo-active');

            oThis.addClass('bw-header-tab-map-active');

            oBusinessWidget.widgetContent.find('#mbr-moreinfo').hide();
            oBusinessWidget.widgetContent.find('#mbr-bw-map').show();
        });
    }

	function loadBWHeader() {
		var iPadding = 14;
		var iLogoWidth = 42;
		var iWidth = oBusinessWidget.widget.width() - (iPadding*2) - iLogoWidth;

		oBusinessWidget.widgetHeader.html(' \
			<div class="bw-header"> \
				<a href="' +URL_BASE + '" target="_blank"><div class="bw-header-star"></div></a> \
				<div class="bw-header-title"><div class="bw-header-title-text" style="width: '+iWidth+'px;">'+oBWData.title+'</div><a href="' +URL_BASE + '" target="_blank"><div class="bw-header-bottom"></div></a></div> \
                <div class="bw-header-tabs"> \
                    <div class="bw-header-tab-moreinfo"></div> \
                    <div class="bw-header-tab-map bw-header-tab-map-active"></div> \
                    <div style="clear:both;"></div>\
                </div> \
                <div style="clear:both;"></div>\
			</div> \
		');
	}

	function loadBWFooter() {
		oBusinessWidget.widgetFooter.html(' \
			<div class="bw-footer">ook een <a href="'+URL_BASE+'mijn-maastricht-bereikbaar.html" target="_blank">ondernemerswidget</a>?</div> \
		');
	}

	function loadBWContent(callback) {

		var oConfig = { 'id' : oBusinessWidget.config.id };

		$.getJSON(URL_BASE+'modules/mijnmb/business.widget.php?callback=?', oConfig, function(oData) {
			oBWData = oData;
			// load the map
			if (typeof(google) != 'undefined') {
				loadBWMap();
			}
			else {
				window.loadBWMap = loadBWMap;
			}

			loadBWFooter();
			loadBWHeader();

			// load binds
			loadBWContentBinds();

			callback();
		});
	}

	function loadWidgetCode() {

		if (bWidgetCodeLoaded === false) { // IE FIX multipleload
			var iMinHeight = $('#mbr-businessWidget').parent().height() < 200 ? 200 : $('#mbr-businessWidget').parent().height();

			var sBWCode = '';
			if(oBusinessWidget.config.width == 'auto' && oBusinessWidget.config.height == 'auto') {
				var sHeight = (oBusinessWidget.config.height == 'auto' ? iMinHeight+'px' : (oBusinessWidget.config.height - iFooterHeight - iHeaderHeight - iPadding - iPadding)+'px');

				sBWCode = ' \
					<div id="mbr-businessWidget-container"> \
						<div class="mbr-businessWidget-top-container"> \
							<div class="mbr-businessWidget-corner-top-left"></div> \
							<div class="mbr-businessWidget-top"></div> \
							<div class="mbr-businessWidget-corner-top-right"></div> \
						</div> \
						<div class="mbr-businessWidget-left"> \
							<div class="mbr-businessWidget-right"> \
								<div class="mbr-businessWidget-header"></div> \
								<div class="mbr-businessWidget-content" style="height:'+sHeight+';"> \
								</div> \
								<div class="mbr-businessWidget-footer"></div> \
							</div> \
						</div> \
						<div class="mbr-businessWidget-bottom-container"> \
							<div class="mbr-businessWidget-corner-bottom-left"></div> \
							<div class="mbr-businessWidget-bottom"></div> \
							<div class="mbr-businessWidget-corner-bottom-right"></div> \
						</div> \
					</div> \
				';
			}
			else {
				var iPadding = 9;
				var sHeight = (oBusinessWidget.config.height == 'auto' ? iMinHeight+'px' : (oBusinessWidget.config.height - iFooterHeight - iHeaderHeight - iPadding - iPadding)+'px');
				sBWCode = ' \
					<div style="width:'+(oBusinessWidget.config.width == 'auto' ? 'auto' : oBusinessWidget.config.width+'px')+';"> \
					<div id="mbr-businessWidget-container"> \
						<div class="mbr-businessWidget-top-container"> \
							<div class="mbr-businessWidget-corner-top-left"></div> \
							<div class="mbr-businessWidget-top"></div> \
							<div class="mbr-businessWidget-corner-top-right"></div> \
						</div> \
						<div class="mbr-businessWidget-left"> \
							<div class="mbr-businessWidget-right"> \
								<div class="mbr-businessWidget-header"></div> \
								<div class="mbr-businessWidget-content" style="height:'+sHeight+';"></div> \
								<div class="mbr-businessWidget-footer"></div> \
							</div> \
						</div> \
						<div class="mbr-businessWidget-bottom-container"> \
							<div class="mbr-businessWidget-corner-bottom-left"></div> \
							<div class="mbr-businessWidget-bottom"></div> \
							<div class="mbr-businessWidget-corner-bottom-right"></div> \
						</div> \
					</div> \
					</div> \
				';
			}



			$('#mbr-businessWidget').before(sBWCode);

			loadBWStyle();

			oBusinessWidget.widget 			= $('#mbr-businessWidget-container');
			oBusinessWidget.widgetHeader 	= oBusinessWidget.widget.find('.mbr-businessWidget-header');
			oBusinessWidget.widgetContent 	= oBusinessWidget.widget.find('.mbr-businessWidget-content');
			oBusinessWidget.widgetFooter	= oBusinessWidget.widget.find('.mbr-businessWidget-footer');

			//oBusinessWidget.widget
			//	.height(oBusinessWidget.config.height)
			//	.width(oBusinessWidget.config.width);

			loadBWContent(function() {return;});

			bWidgetCodeLoaded = true;
		}
	}

	function mmb_ParkingspotOverlay(opt_options) {
		   this.setValues(opt_options);
		   this.setMap(opt_options.map);

		   this.id = opt_options.id;
		   this.freespots = opt_options.freespots;
		   this.totalspots = opt_options.totalspots;
		   this.alignX = opt_options.alignX;

		   var divlabel = this.divlabel_ = document.createElement('div');

		   divlabel.style.cssText = 'position: absolute; ' +
							   'width: 28px; height: 12px;' +
							   'overflow: hidden; z-index: ' + opt_options.zIndex + ';' +
							   'font-family: Verdana; font-size: 0.8em; color: #cccfd9; text-align: center';

		   var div = this.div_ = document.createElement('div');
			   div.style.cssText = 'position: absolute;' +
								   'width: 28px; height: 4px;' +
								   'z-index: ' + opt_options.zIndex + ';';

		   var percentage = Math.round(((this.freespots / this.totalspots) *100));
		   if (percentage > 100) { percentage = 100; }
		   if (percentage < 0 ) { percentage = 0; }

		   var bardiv = this.bardiv_ = document.createElement('div');
		   bardiv.style.cssText = '' +
							   'width: ' + percentage + '%; height: 4px;' +
							   'background: url("' + URL_BASE + 'modules/gmaps/img/parkingmarker-barfill.png") repeat-x; z-index: ' + opt_options.zIndex + ';';
	   };

	window.googleMapsScriptLoaded = function() {
		// loaded the script

		/**
		* mmb_ParkingspotOverlay SubClass
		**/
	   mmb_ParkingspotOverlay.prototype = new google.maps.OverlayView;

	   mmb_ParkingspotOverlay.prototype.onAdd = function() {
		   var pane = this.getPanes().overlayImage;
		   pane.appendChild(this.divlabel_);
		   this.div_.appendChild(this.bardiv_);
		   pane.appendChild(this.div_);

		   var me = this;
		   this.listeners_ = [
			   google.maps.event.addListener(this, 'position_changed',
			   function() { me.draw(); })
		   ];
	   };

	   mmb_ParkingspotOverlay.prototype.onRemove = function() {
		   this.divlabel_.parentNode.removeChild(this.divlabel_);
		   this.div_.parentNode.removeChild(this.div_);
		   this.bardiv_.parentNode.removeChild(this.bardiv_);

		   for (var i = 0, I = this.listeners_.length; i < I; ++i) {
			   google.maps.event.removeListener(this.listeners_[i]);
		   }
	   };
	   mmb_ParkingspotOverlay.prototype.draw = function() {
		   var projection = this.getProjection();
		   if (projection != null) {
			   var position = projection.fromLatLngToDivPixel(this.get('position'));
			   var percentage = 100 - Math.round(((this.freespots / this.totalspots) *100));

			   position.x = Math.round(position.x);
			   position.y = Math.round(position.y);

			   if (percentage > 100) { percentage = 100; }
			   if (percentage < 0 ) { percentage = 0; }

			   // label
			   var divlabel = this.divlabel_;
			   divlabel.style.left = (position.x - 15) + 'px';
			   divlabel.style.top = (position.y - 25) + 'px';
			   divlabel.style.display = 'block';

			   var labeltext = this.freespots.toString();
			   if (this.freespots <= 0) {
				   labeltext = 'VOL';
			   }

			   this.divlabel_.innerHTML = labeltext;

			   // bar
			   var div = this.div_;
			   div.style.left = (position.x - 15) + 'px';
			   div.style.top = (position.y - 55) + 'px';
			   div.style.display = 'block';

			   var bardiv = this.bardiv_;
			   bardiv.style.width = percentage.toString() + '%';
		   }
	   };
	   mmb_ParkingspotOverlay.prototype.setFreeSpots = function(iFreeSpots) {
		   this.freespots = iFreeSpots;
		   this.draw();
	   };
	   mmb_ParkingspotOverlay.prototype.setTotalSpots = function(iTotalSpots) {
		   this.totalspots = iTotalSpots;
		   this.draw();
	   };
	   mmb_ParkingspotOverlay.prototype.setZ = function(iZIndex) {
		   this.divlabel_.style.zIndex = iZIndex;
		   this.div_.style.zIndex = iZIndex;
		   this.bardiv_.style.zIndex = iZIndex;
		   this.draw();
	   };

	   // load jquery
	  if (typeof(jQuery) != 'undefined') {
			jqueryLoadedInit(); // load calendar widget if jquery is already loaded
		} else {
			loadScript(URL_BASE+'lib/common/js/jquery-1.4.2.min.js', jqueryLoadedInit);
		}
	}

	function jqueryLoadedInit() {
		loadScript(URL_BASE+'lib/common/js/jquery.arrow.js', loadWidgetCode);
		// added to line 678 >> $(document).trigger('mmb-bw-ready');
		$(document).bind('mmb-bw-ready', function(){
			/* LoadCount */
			var strWidgetStatsUrl 	= 'http://www.maastrichtbereikbaar.nl/modules/mijnmb/exec.widgetstats.php';
			//$.getJSON(strWidgetStatsUrl, {id	: oBusinessWidget.config.id, a	: 'load'});
			var data = {id	: oBusinessWidget.config.id, a	: 'load'};
			$.ajax({
				url: 		strWidgetStatsUrl,
				dataType: 	'jsonp',
				data: 		data
			});
			/* ClickMBlink */
			$('#mbr-businessWidget-container .bw-header a')
			.unbind('click')
			.bind('click',function() {
				//$.post(strWidgetStatsUrl, {id	: oBusinessWidget.config.id, a	: 'mblink'});
				var data = {id	: oBusinessWidget.config.id, a	: 'mblink'};
				$.ajax({
					url: 		strWidgetStatsUrl,
					dataType: 	'jsonp',
					data: 		data
				});
			});
			/* ClickOWlink */
			$('#mbr-businessWidget-container .bw-footer a')
			.unbind('click')
			.bind('click',function() {
				//$.post(strWidgetStatsUrl, {id	: oBusinessWidget.config.id, a	: 'owlink'});
				var data = {id	: oBusinessWidget.config.id, a	: 'owlink'};
				$.ajax({
					url: 		strWidgetStatsUrl,
					dataType: 	'jsonp',
					data: 		data
				});
			});
		});
	}

	/**
	 *	check if document is loaded
	 */

			// Dean Edwards/Matthias Miller/John Resig

			function init() {
			  // quit if this function has already been called
			  if (arguments.callee.done) return;

			  // flag this function so we don't do the same thing twice
			  arguments.callee.done = true;

			  // kill the timer
			  if (_timer) clearInterval(_timer);

			  // do stuff
			  // load google maps
			  loadScript('http://maps.google.com/maps/api/js?sensor=false&language=nl&region=NL&libraries=geometry&callback=googleMapsScriptLoaded', function(){return;});
			};

			/* for Mozilla/Opera9 */
			if (document.addEventListener) {
			  document.addEventListener("DOMContentLoaded", init, false);
			}

			/* for Internet Explorer */
			/*@cc_on @*/
			/*@if (@_win32)
			  document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>");
			  var script = document.getElementById("__ie_onload");
			  script.onreadystatechange = function() {
				if (this.readyState == "complete") {
				  init(); // call the onload handler
				}
			  };
			/*@end @*/

			/* for Safari */
			if (/WebKit/i.test(navigator.userAgent)) { // sniff
			  var _timer = setInterval(function() {
				if (/loaded|complete/.test(document.readyState)) {
				  init(); // call the onload handler
				}
			  }, 10);
			}

			/* for other browsers */
			window.onload = init;
	/**
	 *	check if document is loaded
	 */


})();



