var test;
/** 
 * @fileoverview cMapObjects - Generic Front-end control of GoogleMaps objects
 *
 * @author Bjorn Brala bjorn@swis.nl
 * @version 2.1
 */

/**
 * Construct the MapObjects object
 * @class cMapObjects class
 * @constructor
 */
 function cMapObjects(){
    /************************************************
    *                                               *
    *    Initialisation, listeners and settings.    *
    *                                               *
    ************************************************/
        /** 
        *   Initiazlize the map  
        *   @extends cMapObjects        
        *   @param string sMapid Name of map div
        *   @param float fLat latitute of startpoint
        *   @param float fLon longitute of startpoint
        *   @param int Izoom default zoom level
        **/     
        this.init = function(sMapId, fLat, fLong, iZoom){
            this.oMap = new GMap2(document.getElementById(sMapId));

            cMapObjectsPoly.apply(this, []); // Extend with poly objects
            
            this.aControls      = new Array();
            
            
            this._fLat = parseFloat(fLat);                      // Start viewport
            this._fLng = parseFloat(fLong);                     // |
            this._iZoom = parseInt(iZoom);                      // |
            
            this.loadSettings();                                // Load map specific settings
            this.loadListeners();                               // Load map listeners

            
            if ( this._bPreloaderEnabled ){
                this.oPreloader = new cPreloader(this.oMap);    // Preloader
                this.oPreloader.init(this.oMap, 177);                // Bind to map object                
            }
            
            
            this.aCategorystate = new Array();                  // Category state array. Filled when category
                                                                // visibility.
            
            this.oPoints        = new Object();                 // Object contains geometry points
            
            //this._oTooltip = document.getElementById('GeoTooltip'); // Tooltip element
            
            this._oTooltip = new cTooltip(this.oMap, 'GeoTooltip', 22, 22, 2, 3);
            
            
            this._bUpdateWaiting = false;                       // Set queue to clean
                                            
            this.loadObjects();                                 // Start loading of markers in current view
            this.aCategorystate = this._oMenu.getCatStates();
            
            oState.init();
        }
        
        
        /**
        *  @desc Clean init. 
        **/
        this.cleanInit = function(sMapId, fLat, fLong, iZoom, mapOptions){
            var opts = mapOptions || new Object();
            this.oMap = new GMap2(document.getElementById(sMapId), mapOptions);
            
            this._fLat = fLat;                      // Start viewport
            this._fLng = fLong;                     // |
            this._iZoom = iZoom;                    // |
            
            this.oMap.setCenter(new GLatLng(this._fLat, this._fLng), this._iZoom); 
            
            this.oMap.enableContinuousZoom();
        }
        
        /**
        *    Load listeners needed on the oMap
        **/
        this.loadListeners = function(){
            
            var oRef = this;
        
            /** Update map objects on moveend ( also triggers on zooms ) **/
            GEvent.addListener(oRef.oMap, 'moveend', function() { oState.update(); oRef.loadObjects();} );
            
            /** Remove the tooltip when movement starts **/
            GEvent.addDomListener(oRef.oMap.getContainer(), 'mouseout', function() { 
                oRef._oTooltip.hide(); 
            });
            GEvent.addListener(oRef.oMap, 'movestart', function() { oRef._oTooltip.hide(); } );
            GEvent.addListener(oRef.oMap, 'zoomend', function() { oRef._oTooltip.hide(); } );
            
            /** Polygone check map listener thingie **/
            GEvent.addListener(oRef.oMap, 'click', function(overlay, point) { 
                if ( point ) {
                    var result = oRef.checkClickedPoly(point);
                    if ( result ) {
                        oRef.trigger(result, 'click');
                    }
                }
            });
            this._hoverListener = GEvent.addListener(oRef.oMap, 'mousemove', this.handleMouseMove);
            
        }
        this.handleMouseMove = function(point){
            var result = oGeoStart.checkClickedPoly(point);
            if ( result ) {
                if ( !oGeoStart.oPoints[result].isHidden() ) {
                    oGeoStart.trigger(result, 'mouseover');
                    oGeoStart.oMap.getDragObject().setDraggableCursor("pointer");
                    if ( oGeoStart._bEnableHover ) {
                        oGeoStart._oTooltip.setText(oGeoStart.oPoints[result].titel);
                        //oGeoStart._oTooltip.addCat(parseInt(oGeoStart.oPoints[result]._GeoInfo['sg_id']));
                        oGeoStart._oTooltip.addCat( oMenu.oCatOf[result] );
                        oGeoStart._oTooltip.show(point);
                    }
                }
            } else {
                oGeoStart._oTooltip.hide();
                oGeoStart.oMap.getDragObject().setDraggableCursor(GDraggableObject.getDraggableCursor());
            }
        }
        
        /**
        *    Load settings for the map.
        **/
        this.loadSettings = function(){
            this._iLoadInterval    = 100;       // ms Interval per group of objects
            this._iLoadStep        = 5;        // Objects per load
            this._bQueueLastRequest = true;     // Que next update call.
                                                    // True     - Update
                                                    // False    - Do nothing
                                                
            this._bPreloaderEnabled = oSettings._bPreloaderEnabled;              // Enable preloader
            this._bEnableHover      = oSettings._bEnableHover;                   // Enable hover
            this._bEnableBalloon    = this._bEnableBalloon          || 'true';   // Enable balloon
            this._iPreferredZoom    = parseInt(oSettings._iPreferredZoom);       // Preferred zoom level. Map will zoom 
                                                                                 // here when gotoHiddenId()
                                                
            this._sCategoryKey = 'sg_id';       // Category key in database
            
            // Wip 2.1 Filters
            // Initialize filter palceholders.
            // Use: 
            //      this.createFilter(sKey)
            //      this.removeFilter(sKey)
            //      this.addFilterItem(sKey, sValue)
            //      this.removeFilterItem(sKey, sValue)
            this._aGeoFilterKeys = new Array();                 
            this._aGeoFilterState = new Array();
                        
            this._sDataUrl = sBaseUrl+'GeoStart/ajax/getData.php';    // Relative URL for GeoStart data requests            
            
            this._oMenu = oMenu;                // Menu object
            
            this.oMap.setCenter(new GLatLng(parseFloat(this._fLat), parseFloat(this._fLng)), parseInt(this._iZoom), eval(oSettings.map_default_type)); 

            this.oMap.enableScrollWheelZoom();    // Enable scroll wheel zoom.
            
            /**
            *   Powetred by geostart
            **/            
            this.oMap.addControl(new powered_by_geostart(this.oMap));
            
            /**
            *   Load map controls.
            **/            
            this.loadControls('large');
            
            this.oMap.enableContinuousZoom();
            
        }
        
        this.loadControls = function(sSet){
            if ( this.sCurrentControlSet != sSet ) {
                this.sCurrentControlSet = sSet;
                
                var oAddScript = new cAddScript;
                switch ( sSet ) {
                    case 'none':
                        this.displayControls();
                        break;
                    case 'small':
                        oAddScript.load('small');
                        break;
                    default:
                        oAddScript.load('large');
                        break;
                    
                }
            }        
        }
        
        
        this.displayControls = function(){                
        
                if ( this.aControls.length > 0 ) {
                    this.removeCurrentControls();
                }               
                
                switch ( this.sCurrentControlSet ) {        
                    case 'none':
                        break;            
                    case 'small':
                        var eZoomControl = new Mini_control_grey_zoom(this.oMap);
                        this.oMap.addControl(eZoomControl); 
                        this.aControls.push(eZoomControl);
                        
                        var eKaartControl = new Mini_control_grey_left(this.oMap);
                        this.oMap.addControl(eKaartControl);  
                        this.aControls.push(eKaartControl);                        
                        
                        var eSatControl = new Mini_control_grey_right(this.oMap);
                        this.oMap.addControl(eSatControl);  
                        this.aControls.push(eSatControl);                        
                
                        break;
                    case 'large':
                    default:
                        /** Map controls **/
                        var eZoomPanControl = new Control_grey_panzoom(this.oMap);
                        this.oMap.addControl(eZoomPanControl); 
                        this.aControls.push(eZoomPanControl);
                            
                        /*
                        var eKaartControl = new Control_grey_center(this.oMap, 'Kaart');
                        this.oMap.addControl(eKaartControl);  
                        this.aControls.push(eKaartControl);
                            
                        var eSatellietControl = new Control_grey_right(this.oMap, 'Satelliet');
                        this.oMap.addControl(eSatellietControl); 
                        this.aControls.push(eSatellietControl);
                        
                        var eHistoryControl = new Control_grey_center_left(this.oMap, 'Historie');
                        this.oMap.addControl(eHistoryControl); 
                        this.aControls.push(eHistoryControl);                        
                        
                        var eHelpControl = new Control_grey_left(this.oMap, 'Help');
                        this.oMap.addControl(eHelpControl);  
                        this.aControls.push(eHelpControl);*/
                        break;
                }
        }
        
        /**
        *   remove current controls from the map in preperation of loading new controls
        **/ 
        this.removeCurrentControls = function(){
            var i = this.aControls.length;
            while ( i-- ) {
                this.oMap.removeControl(this.aControls[i]);
            }            
        }
        
        
        /**
        *   Load listeners for geometry. Currently supports only markers.
        *   @param string sMode Currently only support "marker"
        *   @param object oRef Reference object to apply listeners to
        **/
        this.loadGeometryListeners = function(oRef){
            var oRefMapObjects = this;
            
            GEvent.addListener(oRef, 'infowindowclose', function(){ 
                oGeoStart.checkVisibility(oRef); 
            });
            
            
            /** Open info window on marker **/
            GEvent.addListener(oRef, 'infowindowopen', function() {
                pageHit( sBaseUrl + 'locatie/' + oRef._GeoInfo['titel_key'] );

                /** Add listener, if removed open special window to be able to zoom back to the marker. **/          
                GEvent.addListener(oRef, 'remove', function() {
                        oRefMapObjects.oMap.closeInfoWindow();                                            
                        var iZoom   = oRef._GeoInfo['zoom'];
                        if ( iZoom > oRefMapObjects.oMap.getZoom() ){
                            var id = oRef._GeoInfo['id'];
                            var fLat    = oRef.getPoint().lat();
                            var fLng    = oRef.getPoint().lng();
                            oRefMapObjects.oMap.openInfoWindowHtml(oRef.getPoint(), '<div class="infoWindow">Om deze locatie te zien dient u verder ingezoomed te zijn.<br /><br /><hr /><a class="zoomAnchor" href="#" onclick="oGeoStart.oMap.closeInfoWindow();oGeoStart.gotoHiddenId(' + id + ');return false;"><img src="images/help_plus.gif" alt="" /> Zoom naar marker</a></div>');
                        }
                    });
            });
            
            /** Remove the 'remove' listener when infowindow is closed **/
            GEvent.addListener(oRef, 'infowindowclose', function(){
                GEvent.clearListeners(oRef, 'remove');
            });
            
            /** Onclick event. Hide tooltip ( looks bad on moving map ) and open info window **/
            GEvent.addListener(oRef, 'click', function(clickPoint) {
                    /** Ajust lat/lng on poly object to facilitate infowindow opened at clickpoint **/
                    if (    oRef._GeoInfo['g_type'] == 'POLYGON' ||
                            oRef._GeoInfo['g_type'] == 'MULTIPOLYGON' ||
                            oRef._GeoInfo['g_type'] == 'LINESTRING' ){
                        if ( clickPoint ) { 
                            oRef._GeoInfo['lat'] = clickPoint.lat();
                        oRef._GeoInfo['lng'] = clickPoint.lng();
                        }
                    }
            
            
                    if ( oRefMapObjects._bEnableHover ) {
                        oRefMapObjects._oTooltip.hide();                          // Onclick hide the tooltip
                    }
                    
                    // oRef.openInfoWindowHtml(oRef.content);                  // Open the InfoWindow
                    // oRefMapObjects.htmlSubgroepenRequest(oRef._GeoInfo['id']);
                    
                    var sSubgroep;
                    if ( oRef._GeoInfo['sg_key'].indexOf('project') != -1 ) {
                        sSubgroep = "projecten";
                    } else if ( oRef._GeoInfo['sg_key'].indexOf('evenement')  != -1 ) {
                        sSubgroep = "evenementen";
                    } else if ( oRef._GeoInfo['sg_key'].indexOf('water') != -1 || oRef._GeoInfo['sg_key'].indexOf('canon') != -1 ) {
                        sSubgroep = "waterattracties";
                    }
                    
                    window.location = sBaseUrl + "wat_gebeurt_waar/" + sSubgroep + "/" + oRef._GeoInfo['externe_id'] + "/" + oRef._GeoInfo['titel_key'];
                    
                    swap('tab', false);                                     // Close the InfoTab
                    if ( oRef.bHoverShow ) {                                // Logic if tooltip is shown
                        oRef.tempMouseoutListener.remove();                     // Cancel listnerer that hides marker after mouseout
                        oRef.bForceShow = true;                                 // Tag the marker as forced to show
                        
                        // Remove the marker again when the infowindow is closed
                        /*
                        oRef.tempClickListener = GEvent.addListener(oRef, 'infowindowclose', function(){
                            // Reset the mouseout listener for a hidden marker
                            GEvent.addListener(oRef, 'mouseout', function(){ oRef.hide(); });
                        });*/
                        oRef.show();                                            // Show the marker
                    }
            });                            
            
            /** Mouseover event to facilitatie our tooltip **/
            GEvent.addListener(oRef, "mouseover", function() {
                if ( oRef.type == "point" ) {
                    if ( oRefMapObjects._bEnableHover ) {
                        oRefMapObjects._hoverListener.remove();
                    
                        if ( oRefMapObjects._oTooltip.markerOnScreen(oRef.getPoint()) ) {                // Check if marker is onscreen
                            oRefMapObjects._oTooltip.checkAlign(oRef._GeoInfo['g_type']);
                            oRefMapObjects._oTooltip.setText(oRef.tooltip);
                            
                            oRefMapObjects._oTooltip.addCat(oMenu.oCatOf[oRef._GeoInfo['id']]);                            
                            oRefMapObjects._oTooltip.show(oRef.getPoint());
                            // Add a listener to hide it again on mouseout
                            if ( oRef.isHidden() ) {                            // If marker is hidden show it
                                oRef.bHoverShow = true;                             // Mark the marker as "shown by hover"
                                oRef.show();                                        // Show the marker
                                
                                // Add a listener to hide it again on mouseout
                                oRef.tempMouseoutListener = GEvent.addListener(oRef, 'mouseout', function(){
                                    oRef.hide();                                    // Hide the marker
                                    oRef.tempMouseoutListener.remove();             // Remove self (listener)
                                });
                            }
                        }
                    }
                }
            });
            
            /** Mouseout event for tooltip **/                
            GEvent.addListener(oRef, "mouseout", function() {
                if ( oRefMapObjects._bEnableHover ) {
                    oRefMapObjects._oTooltip.hide();
                    oRef.bHoverShow = false;
                    oRefMapObjects._hoverListener = GEvent.addListener(oRefMapObjects.oMap, 'mousemove', oRefMapObjects.handleMouseMove);
                }
            });
        }
       
    /************************************************
    *                                               *
    *    HTML generation functions.                 *
    *                                               *
    ************************************************/
       /**
       *    generate InfoWindow with embed/link information for object
       *    @param string sKey key ( keyfield type ) for marker.
       *    @param int iId Marker object id
       *    @return string sHtml Window containing link and embed information
       **/
       this.htmlLinkEmbedWindow = function( sKey, iId ) {
           //pageHit( sBaseUrl + 'locatie/' + sKey + '/link' );
           var sHtml = '<div style="width:550px;"><div style="float:left;width:260px;">' + 
                            '<p style="color:#666;width:245px;">' + 
                                'Kopieer de onderstaande link om naar de locatie te linken:<br><input id="balloonPermLink" type="text" value="' + sBaseUrl + 'locatie/' + oGeoStart.oPoints[iId]._GeoInfo['titel_key'] + '" onclick="this.select();"><br>' + 
                                '<br>Kopieer de onderstaande broncode in uw website voor een mini-kaart van de locatie.' + 
                            '</p>' + 
                            '<p id="iframeinput">' + 
                                'Breedte: <input onkeyup="oGeoStart.updateIframecode();" id="ifb" value="257" type="text"> <input type="hidden" value="' + iId + '" id="ifid"> Lengte: <input id="ifl" onkeyup="oGeoStart.updateIframecode();" value="310" type="text">' +
                            '</p>' +
                            'Broncode:<br><textarea onclick="this.select();" id="iframecode">' + oGeoStart.getMiniMapCode(sKey, 310, 257) + '</textarea>' + 
                         '</div>' + 
                         '<div style="float:right;width:280px;">' +
                            'Voorbeeld:<br><iframe src="' + sBaseUrl + '?minimap=1&marker_key=' + sKey + '&w=257&h=310" width="257" height="310"></iframe>' +
                         '</div>' + 
                       '</div>' ;
           return sHtml;   
       }       
       
       
       /**
       *    Generate info window based on Array of information gotten from AJAX request
       *    @param array aInfo Information about the point
       *    @return string content String with info window html for marker
       **/
       this.htmlInfoWindow = function(aInfo) {
                /** Info window HTML code. **/
                var sDirection = '';
                var content = '<div class="infoWindow">';
                
                if(bWebbeheerLoggedIn){
                    content += '<img style="float:right;cursor:pointer;margin:0;width:20px;height:16px;background:transparent;" src="webbeheer/images/edit.gif" onclick="editItem(\'markers\',' + aInfo.id + ');" title="wijzig" alt="wijzig" />';
                    // content += '<img style="cursor:pointer;margin:0;width:17px;height:16px;background:transparent;" src="webbeheer/images/delete.gif" onclick="deleteItem(\'markers\',' + aInfo.id + ');" title="verwijder" alt="verwijder" /><br clear="all"/>';
                }
                
                content += "<b>" + aInfo.titel + "</b><br/>";
                if(aInfo.adres !== '') content += aInfo.adres  + '<br/>'; sDirection = aInfo.adres + ',';
                if(aInfo.postcode !== '') content += aInfo.postcode + '<br/>'; sDirection += aInfo.postcode + ',';
                if(aInfo.plaats !== '') content += aInfo.plaats + '<br/>'; sDirection += aInfo.plaats;
                
                if ( aInfo.omschrijving !== '' ){
                    if ( oSettings._bMenu !== false ) {
                        content += '<a class="right" onclick="showInfo(\'' + aInfo.id + '\');return false;" href="#">Meer informatie</a><br/>';
                    } else {
                    
                    
                        content += '<a class="right" href="#" onclick="parent.location = \'' + sBaseUrl + 'locatie/' + aInfo.titel_key +'&fromMapmaker=1\';return false;">Meer informatie</a><br/>';                                                                        
                    }
                } else if ( aInfo.website != '' ) {                
                    if ( aInfo.website.substring(0,7) != 'http://') {
                        aInfo.website = 'http://' + aInfo.website;
                    }
                    
                    if ( oSettings._bMenu !== false ) {
                        content += '<a target="_blank" class="right" href="' + aInfo.website + '">Bezoek de website</a>';
                    } else {
                        content += '<a class="right" onclick="parent.location = \'' + sBaseUrl + 'locatie/' + aInfo.titel_key +'&fromMapmaker=1\';return false;">Meer informatie</a>';
                    }
                }
                
                var aSg = oMenu.oCatOf[aInfo.id] || new Array();
                var i = aSg.length || 0;
                
                content += '<div id="ballonSubgroepen">';
                
                while ( i-- ) {
                    if ( oSettings._bMenu !== false ) {
                        content += '<div class="ballonSubgroep"><img align="absmiddle" class="png subgroep" src="' + oIconmanager.get(aSg[i]).image + '" style="clear:left;margin:0px 8px 0 0 ;vertical-align:middle;height:21px;width:21px;"><a href="#" onclick="oMenu.getItemList(' + aSg[i] + ');return false;">' + oIconmanager.get(aSg[i]).sg_titel + ' ('+oMenu.oCounter[aSg[i]].counter+')</a></div>';
                    } else {
                        content += '<div class="ballonSubgroep"><img align="absmiddle" class="png subgroep" src="' + oIconmanager.get(aSg[i]).image + '" style="clear:left;margin:0px 8px 0 0 ;vertical-align:middle;height:21px;width:21px;"><a href="#" onclick="return false;">' + oIconmanager.get(aSg[i]).sg_titel + ' ('+oMenu.oCounter[aSg[i]].counter+')</a></div>';
                    }
                }

                
                content += '<div class="ballonButton"><a class="zoomAnchor" href="#" onclick="oGeoStart.oMap.zoomIn();return false;"><img src="GeoStart/images/controls/grey/small_plus.gif" alt="" /> Zoom in</a> <a style="margin-left:10px;" class="zoomAnchor" onclick="oGeoStart.oMap.zoomOut();return false;" href="#"><img src="GeoStart/images/controls/grey/small_min.gif" alt="" /> Zoom uit</a> ';
                
                if ( oSettings._bMenu !== false ) {
                    content += '<span style="display:block;clear:both;margin-top:3px;"><a href="' + sBaseUrl + 'locatie/' + aInfo.titel_key +'" onclick="oGeoStart.openEmbed(\'' + aInfo.titel_key + '\', \'' + aInfo.id + '\');return false;">Link</a> | <a onclick="pageHit(\'' + sBaseUrl + 'locatie/' + aInfo.titel_key + '/route\'); showDirForm(\'' + sDirection + '\', \'' + aInfo.titel.replace("'", "&quot;" ).replace('"', "" ) + '\');return false;" href="#">Route</a></span>';
                } else {
                    content += '<span style="display:block;clear:both;margin-top:3px;"><a href="' + sBaseUrl + 'locatie/' + aInfo.titel_key +'&fromMapmaker=1" target="_blank">Link</a> | <a target="_blank" href="' + sBaseUrl + 'locatie/' + aInfo.titel_key + '/route&fromMapmaker=1">Route</a></span></div>';                
                    //content += '<span style="display:block;clear:both;margin-top:3px;"><a href="http://maps.residentie.net">maps.residentie.net</a></span>'; 
                }                
                content += '</div>';
                                                   
                content += '</div>';
                
                return content;
       }
       
       
       this.htmlSubgroepenRequest = function(iId){
            GDownloadUrl('GeoStart/ajax/getCatsForItem.php?iId='+iId, GEvent.callback(this, this.htmlSubgroepen));
       }
       this.htmlSubgroepen = function(oInfo){
            var json = eval('(' + oInfo + ')');
            
            
            var aInfo = json.aSubgroepen;
            var iId = json.aStats.iId;

            var sSubgroep = ''; 

            var i = aInfo.length;
            
            while ( i-- ) { 
                 sSubgroep += '<div class="ballonSubgroep"><img align="absmiddle" class="png subgroep" src="' + oIconmanager.get(aInfo[i].sg_id).labelImage + '" style="clear:left;margin:0px 8px 0 0 ;vertical-align:middle;background-color:#' + oIconmanager.get(aInfo[i].sg_id).bgColor + ';height:21px;width:21px;"><a href="#" onclick="oMenu.getItemList(' + aInfo[i].sg_id + ');return false;">' + aInfo[i].sg_titel + ' (' + this._oMenu.oCounter[aInfo[i].sg_id]['counter'] + ')</a></div>';
            }           
            oGeoStart.oPoints[iId].openInfoWindowHtml(oGeoStart.oPoints[iId].content.replace('<small>Rubrieken worden geladen...</small>', sSubgroep));
       }
              
       
       /**
       *    Html for the loading marker
       *    return string Element for use with infowindow
       **/
       this.htmlLoadingMarker = function(){
            return '<div class="infowindow">Locatie wordt geladen.<br>Een moment geduld aub.</div>';
       }
       
       /**
       *    Generate info window for minimap based on Array of information gotten from AJAX request
       *    @param array aInfo Information about the point
       *    @return string content String with info window html for marker
       **/
       this.htmlMiniInfoWindow = function(aInfo) {
                
                var content = '<div class="infoWindow">';
                content += '<b>' + aInfo.titel  + '</b><br/><br/>';
                
                if ( aInfo.omschrijving !== '' ){
                    content += '<a class="right" href="' + sBaseUrl + 'locatie/' + aInfo.titel_key + '" target="_blank">Meer informatie</a><br/>';
                } else if ( aInfo.website != '' ) {
                    if ( aInfo.website.substring(0,7) != 'http://') {
                        aInfo.website = 'http://' + aInfo.website;
                    }
                    content += '<a target="_blank" class="right" href="' + aInfo.website + '">Bezoek de website</a>';
                }
                
                content += '<div class="ballonButton"><a class="zoomAnchor" href="#" onclick="oGeoStart.oMap.zoomIn();return false;"><img src="GeoStart/images/controls/grey/small_plus.gif" alt="" /> Zoom in</a> <a style="margin-left:10px;" class="zoomAnchor" onclick="oGeoStart.oMap.zoomOut();return false;" href="#"><img src="GeoStart/images/controls/grey/small_min.gif" alt="" /> Zoom uit</a> ';
                content += '<span style="display:block;clear:both;margin-top:3px;"><a href="' + sBaseUrl + 'locatie/' + aInfo.titel_key +'" target="_blank">Link</a> | <a target="_blank" href="' + sBaseUrl + 'locatie/' + aInfo.titel_key + '/route">Route</a></span></div>';
                
                content += '</div>';
                
                return content;             
       }
       

    
    /************************************************
    *                                               *
    *    Data handling.                             *
    *                                               *
    ************************************************/
        /**
        *    Handle the loading of data.
        *        - Check if currently loading, if so set queued request to true.
        *        - Generate get string for bounds + zoom
        *        - Call GDownloadUrl for asynchronous data request
        **/
        this.loadObjects = function(){
            if ( !this.isBusy() ) {                     // If no update is running.
                
                if ( this._bPreloaderEnabled ) {        // Check if Preloader is enabled.
                    this.oPreloader.start();            // Initialize the preloader 
                }
                this.bRemoving = true;                    // Update status, set object to busy removing
                this.bAdding = true;                    // and adding.
                
                var bounds = this.oMap.getBounds();        // Save current bounds
                var iZoom = this.oMap.getZoom();        // Save current zoom
                
                
                // Generate the $_GET string for _sDataUrl
                var sGet = "?nelng=" + ( bounds.getNorthEast().lng() ) + "&nelat=" + ( bounds.getNorthEast().lat() ) + "&swlng=" + ( bounds.getSouthWest().lng() ) + "&swlat=" + ( bounds.getSouthWest().lat() ) + "&iZoom=" + iZoom + "&filter=" + filter ;
                
                // Check if filled for session problems ( F5 reloads JS, but not PHP Session! )
                sGet += '&oMapObjects=' + this.filled();
                
               // Start the Asynchonous request
                GDownloadUrl( this._sDataUrl + sGet, GEvent.callback(this, this.updateObjects));
            } else {                                    // If an update is running
                if ( this._bQueueLastRequest ){         // Check if queuing enabled.
                    this._bUpdateWaiting = true;
                }
            }
        }
        
        
        /**
        *    Check if MapObjects contains any geometry
        **/
        this.filled = function(){
            var i = 0; 
            for ( var x in this.oPoints ) { i += x; break; }  
            if ( i ) {  return true; }
            else {      return false; }
        }
        
        /**
        *    Check for queued commands and execuste appropiate commands if needed
        **/
        this.checkQueue = function(){
            if ( !this.isBusy() ) {                          // If not busy
                if ( this._bMenuUpdateWaiting ) {                   // If MENU update is waiting
                    this._bMenuUpdateWaiting = false;         
                    this.syncCategories();                   // Re-Synchronize category visiblity
                                                                    // Fix for: Click hide category when
                                                                    // updateing. Only the markers who
                                                                    // appear after the click are properly 
                                                                    // Hidden
                    oMenu.countOffItems('GeoCounter_visible'); // Recalculate the total visible markers.
                }
                                                                    // If viewport update is waiting
                if ( this._bQueueLastRequest && this._bUpdateWaiting ) {
                    this._bUpdateWaiting = false;                
                    this.loadObjects();                      // Re-load objects based on current viewport
                }
                
                
                // Handle queues events like clicks ( currrently only used for clicks (4-7-2007) )
                if ( oGeoStart._oQueuedCommand != null && typeof(oGeoStart._oQueuedCommand) == 'object' ){
                    oGeoStart.trigger(this._oQueuedCommand['iId'], oGeoStart._oQueuedCommand['sEvent']);
                    oGeoStart._oQueuedCommand = null;
                } else if ( oGeoStart._oQueuedCommand != null && typeof(oGeoStart._oQueuedCommand) == 'function' ){
                    oGeoStart._oQueuedCommand();
                    oGeoStart._oQueuedCommand = null;
                }
            } else {
                setTimeout('oGeoStart.checkQueue()', 100);                
            }
        }
        
        /**
        *    Check if currently busy updating
        **/
        this.isBusy = function(){
            if ( this.bRemoving || this.bAdding ) { return true;    } 
            else                                  { return false;   }
        }
                
        
        /**
        *   Update map objects. Parse data and send 
        *   requests to update functions for objects
        *   and the oMenu.
        *   @param JSON json Json string with data from getData.php
        **/
        this.updateObjects = function (json){
                var oData = eval('(' + json + ')');


            /** Update menu data. **/
                this._oMenu.update(oData.oMenu);
            
            
            /** Load category states **/
                this.aCategorystate = this._oMenu.getCatStates();
            
            /**    Geometry data **/
                this.aNewGeometry     = oData.aNewGeometry;
                this.aRemoved        = oData.aRemovedGeometry;
    
            /** Load preloader **/
                var iOperations = oData.aOverview.iRemoved + oData.aOverview.iNew; // Count of actions, (add+remove)
                
                if ( this._bPreloaderEnabled ) {                // Check if preloader should be used.
                    this.oPreloader._iOperations = iOperations; // Initialize max counter
                }
            
            /** Start removal loader **/
                this.iRemovedCounter = 0;                       
                this.iRemoved       = oData.aOverview.iRemoved;
                
                // Start the interval to remove per batch.
                this.oDelInterval = setInterval(function() { oGeoStart.removeBatch(); }, this._iLoadInterval);    
            
            /** Start preloader and add loader. **/
                this.iNewCounter = 0;
                this.iNewGeometry = oData.aOverview.iNew;
                
                // Start the interval to add per batch
                this.oAddInterval = setInterval(function() { oGeoStart.displayBatch(); }, this._iLoadInterval);                
            
        }
    
        /**
        *    Batch removal of data. Updates mapobjects internal arrays.
        **/
        this.removeBatch = function(){
            var i = 0;
            for ( var key in this.aRemoved ) {                            // Loop trough global map objects.
                if ( i < this._iLoadStep && this.iRemovedCounter <= this.iRemoved ) { // Loop until max per batch (_iLoadStep) 
                                                                                      // and check if all updates were done.
                    this.trigger(key, 'deleteObject');
                    delete(this.aRemoved[key]);                    // Remove object from remove data update array
                    this.iRemovedCounter++;                                // Global counter to check if remval is done.
                } else {
                    break;
                }
                i++;
            }
            if ( this._bPreloaderEnabled ) {                            // Only update preloader if enabled
                this.oPreloader.updateLoader( i );
            }


            // Little update check counter thingie...
            if ( oMenu ) 
                oMenu.countOffItems('GeoCounter_visible');
            
            // Cleanup functions if done.
            if ( this.iRemovedCounter >= this.iRemoved ) {
                clearInterval(this.oDelInterval);                 // Clear the loop.
                this.iRemovedCounter = 0;
                this.aRemoved = null;
                this.iRemoved = null;
                this.bRemoving = false;                            // Tell map objects hes done.
                
                this.checkQueue();                               /// Call checkqueue to handle queued requests
            }
        }
    
    
        /**
        *    Batch display of data. Updates mapobjects internal arrays.
        *    Comments added to lines different from this.removeBatch
        **/
        this.displayBatch = function(){
            var i = 0;
            for ( var key in this.aNewGeometry ) {
                if ( i < this._iLoadStep && this.iNewCounter <= this.iNewGeometry ) {
                    if( typeof(this.oPoints[key]) != 'object' )                    
                        this.createPoint(this.aNewGeometry[key]);
                    delete(this.aNewGeometry[key]);                        // Remove from 'todo' object.
                    this.iNewCounter++;
                } else { 
                    break; 
                }
                i++;
            }
            if ( this._bPreloaderEnabled ) {
                this.oPreloader.updateLoader( i );                // Update preloader if enabled
            }
            
            // Little update check counter thingie...
            if ( oMenu ) 
                oMenu.countOffItems('GeoCounter_visible');
            
            // Cleanup functions if done.
            if ( this.iNewCounter >= this.iNewGeometry ) {
                clearInterval(this.oAddInterval);
                this.aNewGeometry = null;
                this.iNewGeometry = null;
                this.iNewCounter = 0;
                this.bAdding = false;
                if ( this._bPreloaderEnabled ) {
                    this.oPreloader.remove();             // Hide preloader again.
                }
                this.checkQueue();                        // Call checkqueue to handle queued requests
            }
        }
        
        
        /**
        *    Create point (marker) on map. 
        *    Uses information from cGeoData::aVisible, add any fields from there.
        *   @param array aInfo Array with information
        **/
        this.createPoint = function(aInfo){
            if( typeof(this.oPoints[aInfo['id']]) != 'object' ) {
                switch ( aInfo.g_type ) {
                    case "POLYGON":
                        var oPoly = this.createPolygon(aInfo); 
                        this.oMap.addOverlay(oPoly);                       
                        oPoly.titel = aInfo.titel;
                        oPoly.tooltip = aInfo[oSettings._sTooltipField];
                        oPoly.type = "polygon";
                        oPoly.content = this.htmlInfoWindow(aInfo);
                        oPoly._GeoInfo  = aInfo;                // All information given by cGeoData(PHP!)
                        this.loadGeometryListeners(oPoly);
                        var id = aInfo.id;
                        this.oPoints[id] = oPoly;               // Add object to factory
                        this.checkVisibility(oPoly);
                        break;
                        
                    case "LINESTRING":
                        var oPoly = this.createPolyline(aInfo);
                        this.oMap.addOverlay(oPoly);
                        oPoly.titel = aInfo.titel;
                        oPoly.tooltip = aInfo[oSettings._sTooltipField];                        
                        oPoly.type = "linestring";
                        oPoly.content = this.htmlInfoWindow(aInfo);
                        oPoly._GeoInfo  = aInfo;                // All information given by cGeoData(PHP!)
                        this.loadGeometryListeners(oPoly);
                        var id = aInfo.id;
                        this.oPoints[id] = oPoly;               // Add object to factory
                        this.checkVisibility(oPoly);
                        break;
                        
                    case "POINT":
                        var point = new GMarker( new GLatLng( parseFloat(aInfo.lat), parseFloat(aInfo.lng) ), oIconmanager.get(aInfo.sg_id));    // Create object
                        var id = aInfo.id;
                        this.oPoints[id] = point;               // Add object to factory
                        
                        point.title     = aInfo.titel;          // Define title
                        point.tooltip   = aInfo[oSettings._sTooltipField];
                        point.type        = "point";            // Set geometry type. Not used yet in 1.0
                        point._GeoInfo  = aInfo;                // All information given by cGeoData(PHP!)

                    
                        point.content = this.htmlInfoWindow(aInfo);
                    
                        /** Default event listener for opening info window **/
                        this.loadGeometryListeners(point);
                        
                        /** Add the overlay to the map **/
                        this.oMap.addOverlay(this.oPoints[aInfo.id]);
                        
                        this.checkVisibility(point);
                        
                        break;
                    case "MULTIPOLYGON":
                        var i = aInfo.aGeometry.length;
                        var aGeo = aInfo.aGeometry;
                        var aPolylines = new Array();
                        while ( i-- ) {
                               aPolylines.push(eval('({ color: "#'+sColor+'", weight: '+iPGWidth+', opacity: '+iPGOpacy+', points: "' + aGeo[i][0] + '",levels: "' + aGeo[i][1] + '", zoomFactor: 2, numLevels: 18 })'));
                        }
                        var oEncoded = { 
                            polylines: aPolylines,
                            fill: true,
                            color:'#' + oIconmanager.get(sg_id).bgColor,
                            opacity: iPGFillOpacy,
                            outline: true};
                            
                        var oPoly = new GPolygon.fromEncoded(oEncoded);
                        GMultiPolygon.apply(oPoly, []);                    
                        
                        oPoly._gInitMulti(oEncoded);                    
                        oPoly.titel = aInfo.titel;
                        oPoly.tooltip = aInfo[oSettings._sTooltipField];
                        oPoly.type = "MULTIPOLYGON";
                        oPoly.content = this.htmlInfoWindow(aInfo);
                        oPoly._GeoInfo  = aInfo;                // All information given by cGeoData(PHP!)
                        
                        this.oMap.addOverlay(oPoly);        
                        this.loadGeometryListeners(oPoly);
                        var id = aInfo.id;                    
                        this.aPolyBounds[id] = oPoly.getBounds();                    
                        this.oPoints[id] = oPoly;               // Add object to factory
                        this.checkVisibility(oPoly);
                        break;
                }
            }
            return this.oPoints[id];
        }
        
        
        /**
        *   Check visibility of object and hide if category isn't visible or filtered.
        **/
        this.checkVisibility = function(oRef) {
            if ( oRef._GeoInfo['id'].indexOf("route") == -1 ) {
                // Nieuwe Regel: Bij beide zichtbaar dan laten zien
                if ( !this.checkVisibilityCategory(oRef) && !this.checkVisibilityFilter(oRef) ) {
                    if ( oRef.isHidden() ) {
                        oRef.show(); 
                    }                
                } else {
                    oRef.hide();                
                }            
            }
        }
        
        
        /**
        *   Check category visibility for referenced object.
        **/
        this.checkVisibilityCategory = function(oRef) {
            /** Categgory states for menu **/            
            if ( this.aCategorystate ) {
                /** Check if point is in hidden category **/
                var i = this.aCategorystate.length;
                while ( i-- ) {
                    var j = oMenu.oCatOf[oRef._GeoInfo['id']].length;
                    while ( j-- ) {
                        if ( oMenu.oCatOf[oRef._GeoInfo['id']][j] == parseInt(this.aCategorystate[i]) ) {
                            return true;
                        }
                    }
                }
                return false;                
            } else {
                return false;
            }
        }
            
            
        /**
        *   Check filter for referenced item
        **/
        this.checkVisibilityFilter = function(oRef){
            if ( !this._aGeoFilterKeys ) {
                this._aGeoFilterKeys = new Array();
            }
            /** Check special filters **/           
            var j = this._aGeoFilterKeys.length;          // Initialize loop through filters
            
            while ( j-- ) { 
                // If filter contains 
                if ( this._aGeoFilterState[this._aGeoFilterKeys[j]] && this._aGeoFilterState[this._aGeoFilterKeys[j]].length > 0 ) { // Check if the filter has been filled
                    var k = this._aGeoFilterState[this._aGeoFilterKeys[j]].length;
                    while ( k-- ) { // Loop throught the filter states
                        if ( oRef._GeoInfo[this._aGeoFilterKeys[j]].indexOf(this._aGeoFilterState[this._aGeoFilterKeys[j]][k]) != -1 ) {
                            return true;
                        }
                    }                    
                }
            }
            return false;
        }
        
        /** 
        *   Add command to command queue. 
        *   @param string sCommand String of the event to be triggered
        *   @param int iSubject Id of the object on who the command should be triggered
        **/        
        this.queueCommand = function(sCommand, iSubject){
            this._oQueuedCommand            = new Object();
            this._oQueuedCommand['sEvent']  = sCommand;
            this._oQueuedCommand['iId']     = iSubject;
        }
    /************************************************
    *                                               *
    *    Filter functions                           *
    *                                               *
    ************************************************/
        /**
        *   Create filter for FIELD - Currently only suppport values to filter on, no ranges.
        *   @param string sKey Fieldname for filter, field should be in oPoints[]._GeoInfo
        **/
        this.createFilter = function(sKey) {
            this._aGeoFilterKeys.push(sKey);
            this._aGeoFilterState[sKey] = new Array();
        }
        
        /**
        *   Remove filter for FIELD
        *   @param string sKey Fieldname for filter
        **/
        this.removeFilter = function(sKey) {
            if ( this._aGeoFilterKeys ) {
                var i = this._aGeoFilterKeys.length;
                while( i-- ) {
                    if ( this._aGeoFilterKeys[i] == sKey ) {
                        delete(this._aGeoFilterKeys[i]);
                        break;
                    }
                }                
                if ( this._aGeoFilterState[sKey] ) {
                    delete(this._aGeoFilterState[sKey]);
                }
            }
        }
        
        /**
        *   Add value to filter 
        *   @param string sKey Keyname of the filter/_GeoInfo field.
        *   @param string sValue Value that should be shows on the map
        **/
        this.addFilterItem = function(sKey, sValue) {
            if ( this._aGeoFilterState[sKey] ) {
                this._aGeoFilterState[sKey].push(sValue);                
            }
        }
        
        /**
        *   Remove value from filter
        *   @param string sKey Keyname of the filter/_GeoInfo field.
        *   @param string sValue Value that should be shows on the map
        **/
        this.removeFilterItem = function(sKey, sValue) {
            if ( this._aGeoFilterState[sKey] ) {
                var i = this._aGeoFilterState[sKey].length;
                while ( i-- ) {
                    if ( this._aGeoFilterState[sKey][i] == sValue ) {
                        delete(this._aGeoFilterState[sKey][i]);
                        break;
                    }
                }
            }
        }
    


    /************************************************
    *                                               *
    *    MapObject functions. Front for all objects *
    *                                               *
    ************************************************/
        /**
        *   Trigger event on object.id. Contains logic for hover etc. Might need to move the logic to the listeners?
        *   @param int iId Id of map object
        *   @param sEvent string Event to be triggered on mapobject
        **/
        this.trigger = function(iId, sEvent){
            switch(sEvent){
                case 'mouseout':
                    if ( this._bEnableHover && !this.isBusy() ) {
                        GEvent.trigger(this.oPoints[iId], sEvent);                        
                    }
                    break;
                case 'mouseover':
                    if ( this._bEnableHover && !this.isBusy()) {
                        GEvent.trigger(this.oPoints[iId], sEvent);                        
                    }
                    break;
                case 'click':
                    if ( this._bEnableBalloon && !this.isBusy()) {
                        GEvent.trigger(this.oPoints[iId], sEvent);                        
                    }
                    break;
                case 'deleteObject':
                    if ( this.oPoints[iId] && ( this.oPoints[iId]._GeoInfo['g_type'] == 'POLYGON' || this.oPoints[iId]._GeoInfo['g_type'] == 'LINESTRING' ) ) {
                        delete(this.aPolyBounds[iId]);
                    }
                    this.oMap.removeOverlay(this.oPoints[iId]);   // Remove object from the map.
                    delete(this.oPoints[iId]);                    // Remove object from map objects
                    break;
                default:
                    if ( !this.isBusy() ) 
                        GEvent.trigger(this.oPoints[iId], sEvent);
                    break;
            }
        }
        
        
        /**
        *   Open a hidden object. Uses json string with object data as argument.
        *   @param string json Hidden marker data.
        **/
        this.gotoHidden = function(json){
            var aInfo =  eval ( '(' + json + ')');            
            
            /* var iZoom   = aData.zoom;
            var fLat    = aData.lat;
            var fLng    = aData.lng;
            var iId     = aData.id; 
            
            /** Set zoom to marker zoom or minimum zoom for map 
            if ( iZoom < this._iPreferredZoom ) { iZoom = this._iPreferredZoom; }
            
            /** Create placeholder point and goto 
            var point = new GLatLng(parseFloat(fLat), parseFloat(fLng));
            this.oMap.setCenter(point, parseInt(iZoom));
            
            /** Add a command to the command queue **/           
            
            //this.queueCommand('click', iId);
            
            /** Loading marker if onclick. Real info only available after all markers are loaded. **/
            
            // Check current zoom level
            
            if ( this.oMap.getZoom() < aInfo.zoom ) {
                if ( aInfo.iZoom < this.iPrefferedZoom ) {
                    var iZoom = this.iPrefferedZoom;
                } else {
                    var iZoom = aInfo.zoom;
                }                
                this.oMap.setCenter(new GLatLng(parseFloat(aInfo.lat), parseFloat(aInfo.lng)), parseInt(iZoom));
            }
            
            this.aCategorystate = this._oMenu.getCatStates();
            this.createPoint(aInfo);
            this.oPoints[aInfo['id']].show();
                       
            GEvent.trigger(this.oPoints[aInfo.id], 'click');
        }
        
        /**
        *   Open a hidden object, new style uses ajax request to get data 
        *   @param int iId MapObject id
        **/
        this.gotoHiddenId = function(iId){
            if ( !this.isBusy() ) {      // Check if an map update is running
                if ( !oGeoStart.oMap.getInfoWindow().isHidden() ) // Close opened info window
                    oGeoStart.oMap.closeInfoWindow();
                GDownloadUrl( sBaseUrl + 'GeoStart/ajax/getItemById.php?id='+iId, GEvent.callback( this, this.gotoHidden ) );
            } else {
                setTimeout('oGeoStart.gotoHiddenId('+iId+')', 100);
            }
        }

        
        
        /**
        *   Check zoom level and goto minimum zoom level. Returns true if no change.
        *   @return bool Changed zoom level
        **/
        this.checkZoom = function(){
            if ( this.oMap.getZoom() < this._iPreferredZoom ) {
                this.oMap.setZoom(this._iPreferredZoom);
                return false;
            } else {
                return true;
            }
        }
        
        
        /**
        *    Hide object.id
        *   @param int iId object Id
        **/
        this.hide = function(iId){
            this.oPoints[iId].hide();
        }
        
        /**
        *    Show object.id
        *   @param int iId object Id
        **/
        this.show = function(iId){

            this.oPoints[iId].show();
        }
        
        
        /**
        *   Hide category.id
        *   Uses this._sCategoryKey to identify category in oPoints[id].dbInfo
        *   @param int iId Id reference to MapObjects
        **/
        this.hideCategory = function(iId){
            // If busy remember to update categories after load.
            if ( this.isBusy() ) { this._bMenuUpdateWaiting = true; }

            for ( k in this.oPoints ) {
                if ( this.oPoints[k]._GeoInfo[this._sCategoryKey] == iId ) {
                    this.hide(k);
                }
            }            
        }
        
        /**
        *    Show category.id
        *    Uses this._sCategoryKey to identify category in oPoints[id].dbInfo
        *   @param int iId id of geomtry
        **/
        this.showCategory = function(iId){
            // If busy remember to update categories after load.
            if ( this.isBusy() ) { this._bMenuUpdateWaiting = true; }

            for ( var k in this.oPoints ) {
                if ( this.oPoints[k]._GeoInfo[this._sCategoryKey] == iId ) {
                    this.show(k);
                }
            }            
        }
        
        /**
        *   Show category.id by array 
        *   Uses this._sCategoryKey to identify category in oPoints[id].dbInfo
        *   @param array aInfo Array (NON ASSOCIATIVE) with the categories to be shown.
        **/
        this.showCategoryGroup = function(aInfo){
            // If busy remember to update categories after load.
            if ( this.isBusy() ) { this._bMenuUpdateWaiting = true; }
            
            var i = aInfo.length;
            for ( var k in this.oPoints ) {
                var j = i;
                while ( j-- ) {
                    if ( this.oPoints[k]._GeoInfo[this._sCategoryKey] == aInfo[j] ) {
                        this.show(k);
                    }
                }
            }            
        }

        /**
        *   Hide category.id by array 
        *   Uses this._sCategoryKey to identify category in oPoints[id].dbInfo
        *   @param array aInfo Array (NON ASSOCIATIVE) with the categories to be shown.
        **/
        this.hideCategoryGroup = function(aInfo){
            // If busy remember to update categories after load.
            if ( this.isBusy() ) { this._bMenuUpdateWaiting = true; }

            var i = aInfo.length;
            for ( var k in this.oPoints ) {
                var j = i;
                while ( j-- ) {
                    if ( this.oPoints[k]._GeoInfo[this._sCategoryKey] == aInfo[j] ) {
                        this.hide(k);
                    }
                }
            }            
        }
        
        /**
        *    Sync categorie and points
        *    Used for updateing map if categories got selected while updateing.
        **/
        this.syncCategories = function(){
            this.aCategorystate = this._oMenu.getCatStates();        // Get current state from Menu object
            var i = this.aCategorystate.length;
            
            for ( var k in this.oPoints ) {
                this.checkVisibility(this.oPoints[k]);                
            }       
        }
        
        
        /**
        *   Show or hide ALL markers.
        **/
        this.setAll = function( bVisiblity ){
            // If busy remember to update categories after load.
            if ( this.isBusy() ) { this._bMenuUpdateWaiting = true; }
            
            if ( !bVisiblity ) { this.oMap.closeInfoWindow(); }
            
            for ( var k in this.oPoints ) {                
                if ( bVisiblity ) {                
                    if ( this.oPoints[k].isHidden() ) {
                        this.show(k);
                    }
                } else {
                    if ( !this.oPoints[k].isHidden() ) {
                        this.hide(k);
                    } 
                }
            }        
        }        
        
        /**
        *   Generate counters for visible / invisible items.
        **/      
        this.getVisiblityCounters = function(){
            var iVisible = 0;
            var iTotal = 0;
            for ( k in this.oPoints ) {
                iTotal++;
                if ( !this.oPoints[k].isHidden() ) {
                    iVisible++;
                }
            }
            
            return  {
                        'iTotal':iTotal,
                        'iVisible':iVisible,
                        'iHidden':iTotal - iVisible
                    };
                                    
        }        
    /************************************************
    *                                               *
    *    Minimap functions. Generate minimap code,  *
    *    load / init minimap                        *
    *                                               *
    ************************************************/

        /**
        *   Init a mini map. Clean map with one marker.
        *   Will callback this.loadMiniMap to load JSON data of marker.
        *   @param string sMapId Name of the map div
        *   @param int iId Id of the marker shown in the minimap
        **/
        this.initMinimap = function(sMapId, iId){
            this.oMap = new GMap2(document.getElementById(sMapId));
            
            this.oPoints = Object();
            cMapObjectsPoly.apply(this, []); // Extend with poly objects
            
            GDownloadUrl( 'GeoStart/ajax/getItemById.php?id='+iId, GEvent.callback( this, this.loadMiniMap ) );
        }
        
        /**
        *   Callback function to load the minimap based on the init string.
        *   @param json JSON string with single marker data array
        *   @note Highly customized function for use with minimap.tpl
        **/
        this.loadMiniMap = function(JSON){
            aInfo = eval('(' + JSON + ')');
            
            this.oMap.setCenter(new GLatLng(aInfo.lat, aInfo.lng), 14, G_PHYSICAL_MAP);
            
            this.point = new GMarker( new GLatLng( parseFloat(aInfo.lat), parseFloat(aInfo.lng) ), oIconmanager.get(aInfo.sg_id));    // Create object
            this.point['_GeoInfo'] = aInfo;
            
            
            if ( aInfo.g_type == "point" ) {
                GEvent.addListener(this.point, 'click', function(){
                    oGeoStart.point.openInfoWindowHtml(oGeoStart.htmlMiniInfoWindow(oGeoStart.point._GeoInfo));
                });
            }
            
            this.oMap.addOverlay(this.point);
            
            //document.getElementById('miniTitel').innerHTML = aInfo.titel;
            
            // Delay needed. oMap needs a little while... buggy API :/
            //setTimeout('oGeoStart.oMap.setZoom(15);', 100);
        }
        
        /**
        *   Generate minimap iFrame code for inclusion in antoher webpage. 
        *   @param int iMarkerId 
        *   @param int iH Height in pixels.
        *   @param int iW Width in pixels.
        **/
        this.getMiniMapCode = function(iMarkerId, iH, iW){
            var sCode = '<iframe style="float:none;margin:2px;" src="' + sBaseUrl + '?minimap=1&marker_key=__MARKERID__&w=__WIDTH__&h=__HEIGHT__" width="__WIDTH__" height="__HEIGHT__"></iframe>';
            
            /** Dynamicly replace variables. More of a proof of concept. Tho is makes changing a lot easier **/
            sCode = sCode.replace(/__HEIGHT__/g, iH);
            sCode = sCode.replace(/__WIDTH__/g, iW);
            sCode = sCode.replace(/__MARKERID__/g, iMarkerId);
            
            return sCode;                        
        }
        
        
        /**
        *   Open embed InfoWindowHtml at place of current InfoWindow
        *   @param string sKey Key of geometry/marker
        *   @param int iId Id of the geometry/marker in the database
        **/
        this.openEmbed = function(sKey, iId){
            var point = this.oMap.getInfoWindow().getPoint();
            this.oMap.closeInfoWindow();
            
            this.oMap.openInfoWindowHtml(point, this.htmlLinkEmbedWindow(sKey, iId));
        }
        
        /**
        *   Update the iFrame code based on inputs in cMapObjects::openEmbed
        **/
        this.updateIframecode = function(){
            $('iframecode').value = this.getMiniMapCode( $('ifid').value, $('ifl').value, $('ifb').value );
        }
        
    /************************************************
    *                                               *
    *    Route poi map functions.                   *
    *    load / init minimap                        *
    *                                               *
    ************************************************/
        /**
        *   Init a mini map. Clean map with one marker.
        *   Will callback this.loadMiniMap to load JSON data of marker.
        *   @param string sMapId Name of the map div
        *   @param int iId Id of the marker shown in the minimap
        **/
        this.initPoiMap = function(sMapId, iId){
            this.oMap = new GMap2(document.getElementById(sMapId));
            
            this.oPoints = Object();
            cMapObjectsPoly.apply(this, []); // Extend with poly objects
            
            GDownloadUrl( 'GeoStart/ajax/getPoiById.php?id='+iId, oGeoStart.loadPoiMap);
        }
        
        /**
        *   Callback function to load the minimap based on the init string.
        *   @param json JSON string with single marker data array
        *   @note Highly customized function for use with minimap.tpl
        **/
        this.loadPoiMap = function(JSON){
            aInfo = eval('(' + JSON + ')');
            
            oGeoStart.oMap.setCenter(new GLatLng(aInfo.lat, aInfo.lng), aInfo.zoom);
            
            oGeoStart.point = oGeoStart.createPolyline(aInfo);            
            
            oGeoStart.point['_GeoInfo'] = aInfo;
            
            oGeoStart.oMap.addOverlay(oGeoStart.point);
            
            var bounds = oGeoStart.point.getBounds();
            
            oGeoStart.oMap.setCenter( bounds.getCenter(), oGeoStart.oMap.getBoundsZoomLevel(bounds) );
            
            oGeoStart.oMap.addOverlay(new GMarker(oGeoStart.point.getVertex(0), oIconmanager.get('route_start')));
            oGeoStart.oMap.addOverlay(new GMarker(oGeoStart.point.getVertex(oGeoStart.point.getVertexCount()-1), oIconmanager.get('route_end')));
            
            // Delay needed. oMap needs a little while... buggy API :/
            // setTimeout('oGeoStart.oMap.setZoom('+aInfo.zoom+');', 100);
        }
}






/**
*   Extend on cMapObjects
*   Adds poly functinality
**/
function cMapObjectsPoly(){
    this.bPolyLoaded = true;
    this.aPolyBounds = new Array();

    /**
    *   Create a polyline
    **/   
    this.createPolyline = function(aInfo){
        var aPoints = this.createPoints(aInfo);
        
        if ( aInfo.polykleur.length > 0 ){
            var oPoly = new GPolyline(aPoints, "#" + aInfo.polykleur, 4, 0.5);
        } else {
            var oPoly = new GPolyline(aPoints, "#" + oIconmanager.get(aInfo.sg_id).bgColor, 4, 0.5);
        }
        oPoly._GeoInfo = aInfo;
        return oPoly;
    }
    
    /**
    *   Create a polyline
    **/   
    this.createPolygon = function(aInfo){        
        var aPoints = this.createPoints(aInfo);
        
        var sEdgecolor = "#" + sColor;
        if ( aInfo.polykleur.length > 0 ){
            var oPoly = new GPolygon(aPoints, "#"+sColor, 1, 1, '#' + aInfo.polykleur, 0.2);
        } else {
            var oPoly = new GPolygon(aPoints, "#"+sColor, 1, 1, '#' + oIconmanager.get(aInfo.sg_id).bgColor, 0.2);
        }
        oPoly._GeoInfo = aInfo;
        return oPoly;
    }
    
    /**
    *   Convert array of lat's and lng's to real GPoints()
    **/
    this.createPoints = function(aInfo){
        this.aPolyBounds[aInfo.id] = new GLatLngBounds();
        var aPoints = aInfo['aGeometry'];
        var i = aPoints.length;
        var aGPoints = new Array();
        aPoints.reverse;
        while ( i -- ) {
            point = new GLatLng( parseFloat(aPoints[i].lat), parseFloat(aPoints[i].lng) );
            if ( aInfo['g_type'] == 'POLYGON' ) {
                this.addPolyBound(aInfo.id, point);
            }
            aGPoints.push(point);            
        }
        return aGPoints;
    }
    
    /**
    *   @desc Fills collection of bounds for polygones.
    **/    
    this.addPolyBound = function(iId, point){
        this.aPolyBounds[iId].extend(point);
    }
    
    /**
    *   @desc Check if point is in polygon. Trigger click on item.
    *   @param point GPoint
    *   @return boolean Was an item found.
    **/
    this.checkClickedPoly = function(point){
        if ( point ) {
            for ( var i in this.aPolyBounds ){
                if (this.aPolyBounds[i].contains(point)){                    
                    if (this.oPoints[i] && this.oPoints[i].Contains(point)){
                        return i;
                        break;
                    }
                }
            }
        }
        return false;
    }
}