// <![CDATA[

/***************************
 * gmapwrapper.js
 *
 * Created by Jennifer Bowen 2007-04-26
 * Last updated 2008-03-17
 * Copyright SCCOOS 2008.
 * No rights to redistribute.
 * 
 * Standardized google maps wrapper library with the following goals:
 *  - Handles loading of layers from kml files
 *  - Reloads markers on a regular interval
 *  - Loads polygons with smooth transitions between using PanTo()
 *  - Allows groupings of layers to be toggled on or off
 *  - Allows for always visible layers
 *
 ****************************/

var maplist = new Array();
var mapcount = new Array();
var maxloadtries = 5;
var args = null;

var lastX = null;
var lastY = null;

function idSafeLabel(str) {
    str = str.replace(/ /g,"_");
    str = str.replace(/\//g,"_");
    str = str.replace(':;-=+()\(\)\[\]\{\}")',"_");
    return str;
}

function urldecode(str) {
  var output = str;
  var binVal, thisString;
  var myregexp = /(%[^%]{2})/;
  while ((match = myregexp.exec(output)) != null
             && match.length > 1
             && match[1] != '') {
    binVal = parseInt(match[1].substr(1),16);
    thisString = String.fromCharCode(binVal);
    output = output.replace(match[1], thisString);
  }
  return output;
}

function computeBlockOffset(elem) {
    return new Array(elem.clientLeft,elem.clientTop); 
}

function executeWhenLoaded (element,code,countdown,interval) {
    if ( countdown == 0 ) {
        var elem = document.getElementById(element);
        elem.innerHTML = "Could not load, please try later";
        return false;
    }

    var elem = document.getElementById(element);
    if ( elem ) {
        code();
        return true;
    }  

    if ( countdown == null ) {
        countdown = 5;
    }

    if ( interval == null ) {
        interval = 5000;
    }

    window.setTimeout( function(e) { executeWhenLoaded(element,code,countdown-1,interval);},interval);

    return false;
}

function executeWhenTrue (expression,code,countdown,interval) {
    if ( countdown == 0 ) {
        alert("Could not load, please try later");
        return false;
    }

    if ( eval(expression) == true ) {
        code();
        return true;
    }  

    if ( countdown == null ) {
        countdown = 5;
    }

    if ( interval == null ) {
        interval = 5000;
    }

    window.setTimeout( function(e) { executeWhenTrue(expression,code,countdown-1,interval);},interval);

    return false;
}

function getImageHeightWidthFromImageBank(uri) {
     var height = 0;
     var width = 0;
     if ( uri.match(/observations\/icons\/star_.*png/) ) {
         height = 20;
         width = 22;
     } else if ( uri.match(/observations\/icons\/triangle_.*png/) ) {
         height = 18;
         width = 20;
     } else if ( uri.match(/observations\/icons\/square_.*png/) ) {
         height = 19;
         width = 19;
     } else if ( uri.match(/observations\/icons\/circle_.*png/) ) {
         height = 8;
         width = 8;
     } else if ( uri.match(/observations\/icons\/.*_tear.png/) ) {
         height = 20;
         width = 12;
     } else if ( uri.match(/moorings\/icons\/.*png/) ) {
         height = 13;
         width = 13;
     } else if ( uri.match(/observations\/icons\/line_.*png/) ) {
         height = 8;
         width = 8;
     } else if ( uri.match(/observations\/icons\/region_.*png/) ) {
         height = 18;
         width = 18;
     } else if ( uri.match(/images\/mapicons\/.*t_[bw]\.png/) ) {
         height = 15;
         width = 15;
     } else if ( uri.match(/images\/mapicons\/.*lp\.png/) ) {
         height = 32;
         width = 32;
     } else if ( uri.match(/images\/mapicons\/.*_[bw]\.png/) ) {
         height = 13;
         width = 13;
     } else if ( uri.match(/harbors\/lalb\/icons\/line_.*\.png/) ) {
         height = 10;
         width = 10;
     } else if ( uri.match(/harbors\/lalb\/icons\/swellicon\.png/) ) {
         height = 9;
         width = 12;
     } else if ( uri.match(/harbors\/lalb\/icons\/.*d_highlight\.png/) ) {
         height = 12;
         width = 12;
     } else if ( uri.match(/harbors\/lalb\/icons\/.*d\.png/) ) {
         height = 12;
         width = 12;
     } else if ( uri.match(/spray\/images\/sslegend\.png/) ) {
         height = 8;
         width = 16;
     } else if ( uri.match(/spray\/images\/glidericon\.png/) ) {
         height = 20;
         width = 47;
     } else if ( uri.match(/spray\/images\/glidericons\/glidericon.*\.png/) ) {
         height = 48;
         width = 48;
     } else if ( uri.match(/spray\/images\.*\.png/) ) {
         height = 12;
         width = 12;
     } else if ( uri.match(/mapicons\/.*dot_small\.png/) ) {
         height = 8;
         width = 8;
     } else if ( uri.match(/wcirc.*\.png/) ) {
         height = 9;
         width = 9;
     } else if ( uri.match(/mapicons\/.*dot\.png/) ) {
         height = 11;
         width = 11;
     }

     return new Array(height,width);
}

/* Function getImageHeightWidth(uri)
 *
 * Retrieves the height and width of an image
 * Will not work if browser cacheing is disabled.
 * You really shouldn't use this unless you can dictate 
 * policy to your users.
 */

function getImageHeightWidth(uri) {
    /* Cache the image before loading it to get the dimensions.  
     * Will not work if caching is disabled!  */

    //var request = GXmlHttp.create();
    //request.open("GET",uri,false);

    var img = new Image();                    
    img.src = uri;

    return ( new Array(img.height,img.width) );
}

/***********************************************************
 * GMapWrapper class
 * 
 * The main class for creating a google maps instance.
 * objMessage - stores where status mesages load/unload.
 * objMap - this is the google map object.
 ****************************/
function GMapWrapper(lat,lon,zoom,maptype,region,wrapperid,mapid) {
  if ( lat == null ) {
    lat = 32.863;
  }
  if ( lon == null ) {
    lon = -117.256;
  }
  if ( zoom == null ) {
    zoom = 14
  }
  if ( maptype == null ) {
    maptype = G_PHYSICAL_MAP;
  }

  if ( region == null ) {
    region = 0;
    region = getFormValue("r");
  }

  this.lat = lat;
  this.lon = lon;
  this.zoom = zoom;
  this.region = region;
  this.callCount = 0;
  
  this.truecenter = new Array(lat,lon,zoom);
  this.maptype = maptype;
  this.region = region;

  this.useAlternateHideShow = true;
  this.useMarkerManager = true;
  this.objMessage = false;
  this.objMap = false;
  this.showloading = true;
  this.showcontrols = true;
  this.showPolygons = true;
  this.showPolyLines = true;
  this.showImageOverlays = true;
  this.showMarkers = true;
  this.showCenters = false;
  this.showInfoWindow = true;
  this.showInfoBlock = false;
  this.showSiteChooser = false;
  this.showOverlayChooser = false;
  this.showHighlightedMarker = true;
  this.showLegendHelp = false;
  this.showMapCoordinates = false;
  this.enableMarkerDrag = false;
  this.enableMarkerGrouping = false;
  this.enableLineSelect = false;
  this.useOldLegendInterface = false;
  this.recenterOnSiteSelect = true;
  this.smoothpan = true;
  this.iw = false;
  this.maxLegendDepth = 1;
  if ( ! wrapperid ) wrapperid = "GmapOuter";
  if ( ! mapid ) mapid = "Gmap";
  this.mapwrapper = wrapperid;
  this.mapid = mapid;

  this.legendtree = null;
  this.datafiles = new Array();
  this.datafiletimes = new Array();
  this.datafilescomplete = new Array();

  this.tilelayers = new Array();
  this.xlayers;
  this.lastsite;
  this.infowindowlayer = 0;
  this.lastopened = 0;
  this.lastZoomFix = 0;
  this.loadinterval = 1 * 60 * 1000; // measured in miliseconds
  this.closeZoom = 14;
  this.groupLoadSize = 10;
  this.newurl = location.href;
  this.isReady = false;
  this.traveling = false;
  this.loadcount = 0;
  this.groupingThreshold = 17;
  this.expandDistance = 30;
  this.includeNameInInfowindow=false;
  this.firstLayer = null;
  this.firstMarker = null;
  this.firstTab = null;
  this.notifyOnMarkerChange = false;
  this.scalePlacement = "topRight";

  /*
  this.defaultIcon=new GIcon();
  this.defaultIcon.image = 'http://maps.google.com/mapfiles/ms/icons/green.png';
  this.defaultIcon.iconSize = new GSize(32,32);
  this.defaultIcon.iconAnchor = new GPoint(16,16);
  this.defaultIcon.infoWindowAnchor = new GPoint(0,32);
*/

  this.defaultIcon=new GIcon();
  this.defaultIcon.image = 'http://www.sccoos.org/data/harbors/lalb/icons/yellowd.png';
  this.defaultIcon.iconSize = new GSize(10,10);
  this.defaultIcon.iconAnchor = new GPoint(5,5);
  this.defaultIcon.infoWindowAnchor = new GPoint(0,10);

  this.styles = new Object();
  this.styles['default'] = new Object();
  this.styles['default'].icon = this.defaultIcon;
  this.styles['default'].strokecolor = "#FFFFFF";
  this.styles['default'].strokeopacity = 0.5;
  this.styles['default'].strokewidth = 3;
  this.styles['default'].fillcolor = "#FFFFFF";
  this.styles['default'].fillopacity = 0.5;
  this.styles['default'].listtype = "checkbox";

  this.styles['noicon_check'] = new Object();
  this.styles['noicon_check'].icon = null;
  this.styles['noicon_check'].strokecolor = "#FFFFFF";
  this.styles['noicon_check'].strokeopacity = 0.5;
  this.styles['noicon_check'].strokewidth = 3;
  this.styles['noicon_check'].fillcolor = "#FFFFFF";
  this.styles['noicon_check'].fillopacity = 0.5;
  this.styles['noicon_check'].listtype = "checkbox";


  this.showMapCoordinates = false;
  this.showLegend = true;
  this.showLegendOnLoad = true;
  this.showLegendButton = false;
  this.allowMovingLegend = true;
  this.legendLeftOffset = "518px";
  this.legendTopOffset = "0px";
  this.legendBottomOffset = null;
  this.chooseFromLegend = false;
  this.clickableMap = false;
  this.showCompass = true;
  this.compassLeftOffset = 10;
  this.compassBottomOffset = 30;

  // Create a pseudo custom event handler using anchors.
  this.mapChangeAnchor = document.createElement("a");
  this.mapChangeAnchor.id = "mapChangeAnchor";

  this.dataLoadedAnchor = document.createElement("a");
  this.dataLoadedAnchor.id = "dataLoadedAnchor";


  maplist.push(this);
  mapcount.push(0);
}

GMapWrapper.prototype.ready = function () {
    this.isReady = true;
}

GMapWrapper.prototype.runWhenReady = function () {
    if ( this.loadcount > maxloadtries ) {
        alert("Map could not load. Please try again later.");
        return false;
    }


    var mapcontainer = document.getElementById(this.mapid);
    if ( this.isReady && mapcontainer) {

        if ( ! document.all ) {
        }
        this.onLoad();
        return true;
    }  

    this.loadcount += 1;

    var obj = this;
    window.setTimeout( function (e) { obj.runWhenReady();},1000);

    return false;
}



/***************************
 * GMapWrapper.loadData
 * 
 * Collects the needed data via an asynchronous request
 * and adds appropriate layers to the map, which in turn
 * load the individual data elements in the map.
 ****************************/
GMapWrapper.prototype.loadData = function( state ) {
    if ( state == null ) {
        state = this.saveState();
    }

    this.cleanup();
    this.layers = new Array();
    this.shownLayers = new Array();
    this.callCount += 1;

    this.curLayer = 0;
    this.curItem = 0;

    for ( var i = 0; i < this.tilelayers.length; i++ ) {
        var placemark = new Object();
        placemark.type = "tiles";
        placemark.urlCallback = this.tilelayers[i].url;
        placemark.opacityCallback = this.tilelayers[i].opacity;
        placemark.name = this.tilelayers[i].label;
        placemark.shown = this.tilelayers[i].shown;
        placemark.priority = this.tilelayers[i].priority;
        placemark.minzoom = this.tilelayers[i].minzoom;
        placemark.maxzoom = this.tilelayers[i].maxzoom;
        placemark.isPng = this.tilelayers[i].isPng;

        var layer = {};
        layer.placemarks = [];
        layer.placemarks.push(placemark);
        layer.type = "tiles";
        layer.shown = this.tilelayers[i].shown;
        layer.abbreviation = this.tilelayers[i].label;
        layer.overlay = null;
        layer.children = [];

        if ( this.showloading ) {
            this.objMessage.setMessage("Loading " + layer.abbreviation + " ...");
            this.objMessage.show();
        }

        layer.legendIconStyle = this.tilelayers[i].iconStyle;
        this.layers.push(layer);
        this.mapAll();
        if ( layer.shown ) this.shownLayers.push(this.curLayer);
        this.curLayer += 1; 
        this.curItem = 0;

        if ( this.showloading ) {
            this.objMessage.hide();
        }
    }

    for ( var i = 0; i < this.datafiles.length; i++ ) {
        var request = GXmlHttp.create();
        request.open("GET",this.datafiles[i],false);
        var extension = this.datafiles[i].match(/^.*\.([a-zA-Z0-9]*)$/)[1];
        request.send(null);
        
        if (request.status > 300 ) {
            this.markSourceAsComplete(this.datafiles[i],new Date().valueOf());
            if ( this.checkLoadDataComplete() ) {
                this.onLoadDataCompletion();
            }
        }

        if (request.status == 200 ) {
            if ( document.all ) {
                var xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
                xmlDoc.loadXML(request.responseText);
                this.addDocument(xmlDoc,extension);
            } else {
                var xmlDoc = (new DOMParser()).parseFromString(request.responseText,"text/xml");
                this.addDocument(xmlDoc,extension);
            }

            this.markSourceAsComplete(this.datafiles[i],new Date().valueOf());
            if ( this.checkLoadDataComplete() ) {
                this.onLoadDataCompletion();
            }
        }
    }

/*
    if ( this.showLegend ) {
        if ( ! this.legend ) {
            this.legend = new GMapLegend(this);
        }
        this.legend.addLegendEntries();
    }
*/

    this.restoreState(state);

    this.customLoadData();
    GEvent.trigger(this,'dataloaded');
}

GMapWrapper.prototype.onMapAreaClick = function(point) { 
    if ( this.showInfoBlock ) {
        if ( this.lastMarker ) {
            this.lastMarker.setImage(this.lastMarker.normalStyle.icon.image);
            this.lastMarker = null;
            GEvent.trigger(this.objMap,'mapclick');
        }
        var ib = document.getElementById("mapinfoblock");
        ib.innerHTML = "";
    }
}

GMapWrapper.prototype.onLoadDataCompletion = function() { 
    this.layerMapping = new Array();
    for ( var i = 0; i < this.layers.length; i++ ) {
        if ( this.layers[i] != null ) {
            this.layerMapping[this.layers[i].abbreviation] = i; 
            this.layers[i].index = i;
        }
    }
    for ( var i = 0; i < this.layers.length; i++ ) {
        if ( this.layers[i] != null ) {
            if ( this.layers[i].parent != null && typeof(this.layerMapping[this.layers[i].parent]) != "undefined" ) {
                this.layers[this.layerMapping[this.layers[i].parent]].children.push(i);
            }
        }
    }

    if ( this.showInfoBlock ) {
        this.createInfoBlock();
    }

    if ( this.showOverlayChooser ) {
        this.createOverlayChooser();
    }

    var mapobj = this;
    if ( this.enableMarkerGrouping ) {
        this.groupCenterIcon = new GIcon();
        this.groupCenterIcon.image = '/imgs/smalldot.png';
        this.groupCenterIcon.iconSize = new GSize(6,6);
        this.groupCenterIcon.iconAnchor = new GPoint(3,3);
        this.groupCenterIcon.infoWindowAnchor = new GPoint(0,3);

        this.groupIcon = new GIcon();
        this.groupIcon.image = '/imgs/groupIcon.png';
        this.groupIcon.iconSize = new GSize(11,11);
        this.groupIcon.iconAnchor = new GPoint(6,6);
        this.groupIcon.infoWindowAnchor = new GPoint(0,6);

        this.createGroupMarkers(false);
        this.groupMarkers();
        this.groupzoom = this.objMap.getZoom();

        GEvent.addListener(this.objMap,"zoomend",function () {
            var zoom = this.getZoom();
            if ( zoom != mapobj.groupzoom ) {
                mapobj.unGroupMarkers()
                mapobj.groupzoom = mapobj.objMap.getZoom();
                if ( zoom > 2 ) {
                    mapobj.createGroupMarkers(false);
                    mapobj.groupMarkers();
                }
            }
        });
    }

    if ( this.enableLineSelect ) {
        this.setupLineSelect();
    }

    if ( this.lastsite ) {
        this.selectSite(lastsite);
        this.travelToSite(lastsite);
    }


    if ( this.showloading ) {
        this.objMessage.hide();
    }

    if ( this.legend && this.showLegendOnLoad ) {
        this.legend.showLegend();
    }
}

GMapWrapper.prototype.checkLoadDataComplete = function() { 
    var complete = true;
    var now = new Date().valueOf();
    for ( var i = 0; i < this.datafiles.length; i++ ) {
        var loaded = false;
        for ( var j = 0; j < this.datafilescomplete.length; j++ ) {
            var match = this.datafiles[i] == this.datafilescomplete[j];
            var t = now - this.datafiletimes[j];
            if ( match && t <= this.loadinterval ) {
                loaded = true;
                break;
            }
        }
        if ( ! loaded ) complete = false;
    }
    return complete;
}

GMapWrapper.prototype.markSourceAsComplete = function (src,time) {
    this.datafilescomplete.push(src);
    this.datafiletimes.push(time);

}


/***************************
 * GMapWrapper.loadMap()
 * 
 * Creates a new GMap2 instance and populates
 * it with data.
 ****************************/
GMapWrapper.prototype.loadMap = function() { 
if( document.all ) {
}
  if(GBrowserIsCompatible()) { 
    this.objMap = new GMap2(document.getElementById(this.mapid));
    this.objMap.enableContinuousZoom();
    this.objMap.enableScrollWheelZoom();
  } else { 
    this.setMessage("Your browser is incompatible with Google Maps API v2");
    return false;
  }

  if ( ! this.objMap ) {
     return false;
  }

  if ( this.showcontrols ) {
    this.objMap.addControl(new GLargeMapControl3D());
    G_PHYSICAL_MAP.getMaximumResolution = function() { return 17; };
    this.objMap.addControl(new GHierarchicalMapTypeControl());
    this.objMap.addControl(new GScaleControl());
    this.objMap.addMapType(G_PHYSICAL_MAP)
  }

  // Detect browser version simply and without overhead, slightly inaccurate
  // in edge cases 
  var ua = navigator.userAgent.toLowerCase(); 
  if (ua.indexOf('msie') && document.all ) {
     this.isIE = true;
     if ( parseInt(ua.substring(ua.indexOf('msie') + 5 ) ) == 7 ) {
        this.isIE7 = true;
     } else {
        this.isIE7 = false;
     }
  } else {
     this.isIE = false;
  }

  this.objMap.setCenter(new GLatLng(this.lat,this.lon),this.zoom);
  this.objMap.setMapType(this.maptype);
  this.mbl = new MovableBlockList();
/*
  if ( this.allowMovingLegend ) {
      if ( ! this.legend ) {
          this.legend = new GMapLegend(this);
      }
      this.legend.initLegend();
      var legend = document.getElementById("MapLegend");
      if ( legend ) {
          this.mbl.removeBlock("MapLegend");  
          this.mbl.addBlock("MapLegend");  
      }
  }
*/

    this.objMessage = new Message(this.mapid,true,true);
    this.objMessage.setMessage("Loading data, please wait ...");
    if ( this.showloading ) {
        this.objMessage.show();
    }

  var bl = document.getElementById("bookmarklink");
  var obj = this;
  if ( bl ) {
      bl.onclick = function () {
          obj.g_writeLinkHere();
      };
  }


  this.loadData(this.mergeStateFromArgs());
  if ( this.showCompass ) {
     //this.addCompass();
  }

    if ( this.clickableMap ) {
        GEvent.addDomListener(this.objMap,'click',function(overlay,point) {
            if ( overlay == obj.objmap ) {
                obj.onMapAreaClick(point);
                if ( obj.lastMarker && obj.showHighlightedMarker ) {
                    obj.lastMarker.setImage(obj.lastMarker.normalStyle.icon.image);
                    obj.lastMarker = null;
                }
            }

        });
    }

    if ( this.showMapCoordinates ) {
        var statusLocation = document.getElementById("map_location"); 
        if ( ! statusLocation ) {
            statusLocation = document.createElement("div");
            statusLocation.id = "map_location";
            var container = document.getElementById(this.mapid);
            container.appendChild(statusLocation);
        }
        GEvent.addListener(this.objMap,"mousemove", function(latlng) {
            statusLocation.style.display = "block";
            var lat = Math.round(latlng.lat()*10000)/10000;
            var lng = Math.round(latlng.lng()*10000)/10000;
            statusLocation.innerHTML = lat + "," + lng;
        });
    }

  if ( this.showloading ) {
    this.objMessage.hide();
  }
  this.customLoadMap();

  /* Schedule data to load on the load interval. */
  var ldobj = this;
  window.setTimeout( function (e) { ldobj.loadData();},ldobj.loadinterval);

  return true;
}

GMapWrapper.prototype.customLoadMap = function() {
}

GMapWrapper.prototype.customLoadData = function() {
}

/***************************
 * GMapWrapper.onLoad()
 * 
 * Starts the map loading process. Should be executed
 * only once the map elements exist. Attached to 
 * window.onload.
 ****************************/
GMapWrapper.prototype.onLoad = function() {
  if ( this.useAlternateHideShow ) {
    GMarker.prototype.hide = function () {
      if (this.getPoint().lat() < 90 && this.getPoint()) {
        try {
          this.savePoint = this.getPoint();
          this.setPoint(new GLatLng(90,0));
        } catch(e) { }
      }
    }

    GMarker.prototype.show = function () {
      if (this.getPoint().lat() >= 85 ) {
        if (this.savePoint) {
          try {
            this.setPoint(this.savePoint);
            this.savePoint = null;
          } catch(e) { }
        }
      }
    }

   GMarker.prototype.isHidden = function () {
      if (this.getPoint().lat() >= 85 ) {
          return true;
      }
      return false;
    }
  }

  return this.loadMap();

}


/***************************
 * GMapWrapper.cleanup()
 * 
 * Removes all markers, polygon layers, anything that could be 
 * reloaded on a document refresh.
 ****************************/
GMapWrapper.prototype.cleanup = function() { 
    this.objMap.clearOverlays();
}

/***************************
 * GMapWrapper.saveState()
 * 
 * Saves the overlay toggle and infowindow state.
 ****************************/
GMapWrapper.prototype.saveState = function() { 
    var state = new Object();
    state.layers = new Object();

    // Save overlay visibility state
    if ( (this.showOverlayChooser || this.chooseFromLegend ) && this.layers  ) {
        for ( var i = 0; i < this.layers.length; i++ ) {
            state.layers[this.layers[i].abbreviation] = this.layers[i].shown;
        }
    }

    // Save infowindow state
    if ( this.iwlayer ) {
        state.iwlayer = this.iwlayer;
        state.iwmarker = this.iwmarker;
        state.iwtab = this.objMap.getInfoWindow().getSelectedTab();
    } else {
        state.iwlayer = null;
    }

    // Save center and zoom
    state.zoom = this.objMap.getZoom();
    var center = this.objMap.getCenter();
    state.lat = center.lat();
    state.lon = center.lng();
    state.maptype = this.objMap.getCurrentMapType();

    return state;
} 

/***************************
 * GMapWrapper.restoreState()
 * 
 * Loads the previous state settings for layer and infowindow
 * visibility.
 ****************************/
GMapWrapper.prototype.restoreState = function(state) {
    if ( state.layers && this.layers ) {
        for ( var i = 0; i < this.layers.length; i++ ) {
            if ( this.showOverlayChooser || this.chooseFromLegend ) {
                if (this.layers[i].abbreviation != null ) {
                     if ((state.layers[this.layers[i].abbreviation] != null ) &&
                         (state.layers[this.layers[i].abbreviation] == false ) ) {
                         var checkbox = document.getElementById("layer_" + i);
                         if ( checkbox ) {
                              checkbox.checked = false;
                              checkbox.parentNode.parentNode.className="unmarked";
                         } 
                         this.hideLayer(i);
                     } else if ((state.layers[this.layers[i].abbreviation] != null ) &&
                         (state.layers[this.layers[i].abbreviation] == true ) ) {
                         var checkbox = document.getElementById("layer_" + i);
                         if ( checkbox ) {
                              checkbox.checked = true;
                              checkbox.parentNode.parentNode.className="";
                         } 
                         this.showLayer(i);
                     }
                }
            }
         }
     }
     this.openInfowindowIfGiven(state.iwlayer,state.iwmarker,state.iwtab);

     if ( state.zoom ) 
         var zoom = parseInt(state.zoom);
     else
         var zoom = this.zoom;

     if ( state.lat && state.lon ) {
         var lat = parseFloat(state.lat);
         var lon = parseFloat(state.lon);
     } else {
         var lat = this.lat;
         var lon = this.lon;
     }

     if ( state.maptype )
         var maptype = state.maptype;
     else 
         var maptype = this.maptype;
     
     this.objMap.setCenter(new GLatLng(lat,lon),zoom,maptype);

     this.zoom = zoom;
     this.maptype = maptype;
     this.lat = lat;
     this.lon = lon;
 
 }


GMapWrapper.prototype.openInfowindowIfGiven = function(iwlayer,location,tabnumber) { 
    for ( var i = 0; i < this.layers.length; i++ ) {
        if ( ( iwlayer != null ) && 
             ( iwlayer == this.layers[i].abbreviation ) ) {
            for ( var j = 0; j < this.layers[i].markers.length; j++ ) {
                if ( this.layers[i].markers[j].fullname == location && this.layers[i].shown == true ) {
                    this.onMarkerClick(this.layers[i].markers[j]);
                    if ( tabnumber > 0 ) {
                        var iw = this.objMap.getInfoWindow();
                        window.setTimeout( function (e) {
                            if ( iw && ( iw.getTabs().length > tabnumber ) ) {
                            // Stupid hack to circumvent the infowindow
                            // not being loaded yet
                                iw.selectTab(tabnumber);
                            }
                        }, 0);
                    }
                }
            }
        }
    }
}

/***************************
 * GMapWrapper.hideLayer()
 * 
 * Hides the indicated marker layer using the provided 
 * hide() method.
 ****************************/
GMapWrapper.prototype.hideLayer = function(l) { 
  if ( typeof(this.layers[l]) == "undefined" ) return; 
  if ( ! this.layers[l].shown ) return;
  for ( var i = 0; i < this.layers[l].children.length; i++ ) {
      this.hideLayer(this.layers[l].children[i]);
  }


  var newlayers = new Array();
  var last = 0;

  if ( this.enableMarkerGrouping ) {
      this.unGroupMarkers();
  }

  if ( this.infowindowlayer == l ) {
      this.objMap.closeInfoWindow();
  }

  if ( this.layers[l].type == "tiles" && this.layers[l].overlay ) {
      if ( this.layers[l].added && this.layers[l].shown ) 
      //if ( this.layers[l].overlay.isHidden() ) 
      this.layers[l].overlay.hide();
      //if ( typeof(this.layers[l].overlay.hide) != "undefined" ) {
          //if ( this.layers[l].overlay.isHidden() ) this.layers[l].overlay.hide();
      //} else {
          //this.objMap.removeOverlay(this.layers[l].overlay);
      //}
  }

  if ( this.layers[l].type == "polyline" ) {
      for ( var i = 0; i < this.layers[l].polylines.length; i++ ) {
          //this.objMap.removeOverlay(this.layers[l].polylines[i]);
          this.layers[l].polylines[i].hide();
      }
  }

  if ( this.layers[l].type == "polygon" ) {
      for ( var i = 0; i < this.layers[l].polygons.length; i++ ) {
          for ( var j = 0; j < this.layers[l].polygons[i].length; j++ ) {
              //this.objMap.removeOverlay(this.layers[l].polygons[i][j]);
              this.layers[l].polygons[i][j].hide();
          }
      }
  }

  if ( this.layers[l].type == "image" ) {
      this.objMap.removeOverlay(this.layers[l].overlay);
      this.layers[l].added = false;
  }

  if ( this.layers[l].type == "marker" ) {
      for ( var i = 0; i < this.layers[l].markers.length; i++ ) {
          if ( this.useMarkerManager ) {
              this.layers[l].markers[i].hide();
          } else {
              this.objMap.removeOverlay(this.layers[l].markers[i]);
              this.layers[l].added = false;
          }
      }
      if ( this.useMarkerManager ) {
          //this.layers[l].mm.refresh();
      }
  }

  for ( var i = 0; i < this.shownLayers.length; i++ ) {
      if ( this.shownLayers[i] != l ) {
          newlayers.push(this.shownLayers[i]);
      }
  }
  this.shownLayers = newlayers;
  this.layers[l].shown = false;

  if ( this.enableMarkerGrouping ) {
      this.createGroupMarkers(true);
      this.groupMarkers();
  }
  GEvent.trigger(this,'layerhidden',this.layers[l]);
}

/***************************
 * GMapWrapper.showLayer()
 * 
 * Shows the indicated marker layer using the provided 
 * show() method.
 ****************************/
GMapWrapper.prototype.showLayer = function(l) {
  if ( typeof(this.layers[l]) == "undefined" ) return; 
  if ( this.layers[l].shown ) return;

  for ( var i = 0; i < this.layers[l].children.length; i++ ) {
      this.showLayer(this.layers[l].children[i]);
  }

  if ( this.enableMarkerGrouping ) {
      this.unGroupMarkers();
  }

  if ( this.layers[l].type == "polyline" ) {
      for ( var i = 0; i < this.layers[l].polylines.length; i++ ) {
          if ( typeof(this.layers[l].added) == "undefined" || ! this.layers[l].added ) {
              this.objMap.addOverlay(this.layers[l].polylines[i]);
          } else {
              this.layers[l].polylines[i].show();
          }
      }
  }

  if ( this.layers[l].type == "polygon" ) {
      for ( var i = 0; i < this.layers[l].polygons.length; i++ ) {
          for ( var j = 0; j < this.layers[l].polygons[i].length; j++ ) {
              if ( typeof(this.layers[l].added) == "undefined" || ! this.layers[l].added ) {
                  this.objMap.addOverlay(this.layers[l].polygons[i][j]);
              } else {
                  this.layers[l].polygons[i][j].show();
              }
          }
      }
  }

  if ( this.layers[l].type == "tiles" ) {
      if ( ! this.layers[l].added ) {
          this.layers[l].added = true;
          this.objMap.addOverlay(this.layers[l].overlay);
      } else {
          this.layers[l].overlay.show();
      }
/*
      if ( typeof(this.layers[l].overlay) != "undefined" && this.layers[l].overlay ) {
          if ( typeof(this.layers[l].overlay.show) != "undefined" && this.layers[l].overlay.isHidden() ) 
              this.layers[l].overlay.show();
          else this.objMap.addOverlay(this.layers[l].overlay);
      } 
*/
  }

  if ( this.layers[l].type == "image" ) {
      this.objMap.addOverlay(this.layers[l].overlay);
      this.layers[l].added = true;
  }

  if ( this.layers[l].type == "marker" ) {
      for ( var i = 0; i < this.layers[l].markers.length; i++ ) {
          if ( this.useMarkerManager) 
              this.layers[l].markers[i].show();
          else
              this.objMap.addOverlay(this.layers[l].markers[i]);
              this.layers[l].added = true;
      }
  }

  if ( this.useMarkerManager && this.layers[l].mm ) this.layers[l].mm.refresh();

  this.layers[l].shown = true;

  this.shownLayers.push(l);

  if ( this.enableMarkerGrouping ) {
      this.createGroupMarkers(true);
      this.groupMarkers();
  }
  GEvent.trigger(this,'layershown',this.layers[l]);
}

/***************************
 * GMapWrapper.getMarkerForSite()
 * 
 * Returns a marker identified by the given abbreviation,
 * if it has been loaded into the marker manager.
 ****************************/
GMapWrapper.prototype.getMarkerForSite = function(abbreviation) {
    var marker = null;
    if ( this.layers ) {
        for ( var i = 0; i < this.layers.length; i++ ) {
            for ( var j = 0; j < this.layers[i].markers.length; j++ ) {
                if (this.layers[i].markers[j] && this.layers[i].markers[j].abbreviation == abbreviation ) {
                    marker = this.layers[i].markers[j];
                }
            }
        }
    } 

    return marker;
}

/***************************
 * GMapWrapper.getOuterMapContainer
 * 
 * Returns the GMapOuter map element. Creates the
 * element if it doesn't already exist.
 ****************************/
GMapWrapper.prototype.getOuterMapContainer = function() {
    var outer = document.getElementById(this.mapwrapper);

    if ( ! outer ) {
         outer = document.createElement("div");
         outer.id = this.mapwrapper;
         var inner = document.getElementById(this.mapid);
         if ( inner ) {
             var parent = inner.parentNode;
             var saved = parent.removeChild(inner);
             parent.appendChild(outer);
             outer.appendChild(saved);
         } else {
             var content = document.createElement("Content");
             if ( content ) {
                 content.appendChild(outer);
             } else {
                 body = document.getElementsByTagName("body")[0];
                 body.appendChild(outer);
             }
             var inner = document.createElement("div");
             inner.id = this.mapid;
             outer.appendChild(inner);
         }
    }

    return outer;
}


/***************************
 * GMapWrapper.createInfoBlock()
 * 
 * Creates an informational block that can be used as an
 * alternative to an infowindow. Typically sits below the
 * map on page load, though this could be changed through css.
 ****************************/
GMapWrapper.prototype.createInfoBlock = function() {
    var infoblock = document.getElementById("mapinfoblock");
    if ( ! infoblock ) {
         var outer = this.getOuterMapContainer();
         var parent = outer.parentNode;
         if ( parent ) {
             infoblock = document.createElement("div");
             infoblock.setAttribute("id","mapinfoblock");
             parent.appendChild(infoblock);    
         } else {
             //alert("Could not attach info block!");
         }
    }
    return infoblock;
}

 
/***************************
 * GMapWrapper.createSiteChooser()
 * 
 * Creates a sidebar for a map that allows users to toggle the
 * appearance of different sites on the map.
 ****************************/
GMapWrapper.prototype.createSiteChooser = function(sites,id,name) {
    // Try to find the appropriate parent node. If it doesn't exist, create
    // it.
    var currentlist;

    if ( ! sites || sites.length < 1 ) return;

    if ( id ) currentlist = document.getElementById(id);

    var outer = this.getOuterMapContainer();

    if ( ! currentlist ) {
        var parent = document.getElementById("sitechooser");
        if ( ! parent ) {
            var map_outer_container = document.getElementById(this.mapwrapper);
            parent = document.createElement("div");
            parent.setAttribute("id","sitechooser");
            map_outer_container.appendChild(parent); 
        }

        var header = document.createElement("div");
        header.className = "sitechooser_label";
        if ( name ) {
            header.innerHTML = name;
        } else {
            header.innerHTML = "Sites";
        }


        currentlist = document.createElement("ul");
        currentlist.id = id;

        section = document.createElement("div");
        section.className = "section";

        section.appendChild(header);
        section.appendChild(currentlist);
        parent.appendChild(section);

    } else {
        for ( var i = 0; i < currentlist.childNodes.length; i++ ) {
            currentlist.childNodes[i] = null;
            currentlist.removeChild(currentlist.childNodes[i]);
        }
    }
    
    for ( var i = 0; i < sites.length; i++ ) {
        var link = document.createElement("a");
        var site = document.createElement("li");
        var name = sites[i].abbreviation;
        if ( ! name ) name = sites[i].name;
        link.innerHTML = name;
        link.setAttribute("id","label_" + name);

        var obj = this;
        if ( document.all ) {
            link.attachEvent('onclick',function(event) {
                obj.openSiteWindowFromSidebar(event);
            });
        } else {
            link.addEventListener('click',function(event) {
                obj.openSiteWindowFromSidebar(event);
            }, false);
        }

        site.appendChild(link);
        currentlist.appendChild(site);
    }

}


/***************************
 * GMapWrapper.createOverlayChooser()
 * 
 * Creates a sidebar for a map that allows users to toggle the
 * appearance of different overlays on the map.
 ****************************/
GMapWrapper.prototype.createOverlayChooser = function() {
    // Try to find the appropriate parent node. If it doesn't exist, create
    // it.
    var currentlist;

    currentlist = document.getElementById("chooselayer");

    var outer = this.getOuterMapContainer();

    if ( ! currentlist ) {
        var parent = document.getElementById("sidepanel");
        if ( ! parent ) {
            var map_outer_container = document.getElementById(this.mapwrapper);
            parent = document.createElement("div");
            parent.setAttribute("id","sidepanel");
            map_outer_container.appendChild(parent); 
        } else {
            var sections = parent.getElementsByClassName("section");
            var gmap_height = parseFloat(container.style.height);
            if ( gmap_height) {
                section_height = ( gmap_height / sections.length ) - 10; 
            }
        }

        var header = document.createElement("div");
        header.className = "sidepanel_label";
        if ( this.chooserLabel ) {
            header.innerHTML = this.chooserLabel;
        } else {
            header.innerHTML = "Layers";
        }


        currentlist = document.createElement("ul");
        currentlist.id = "chooselayer";

        section = document.createElement("div");
        section.className = "section";

        section.appendChild(header);
        section.appendChild(currentlist);
        parent.appendChild(section);

    } else {

        while ( currentlist.childNodes && currentlist.childNodes.length > 0 ) { 
            var child = currentlist.removeChild(currentlist.firstChild);
            if ( child == null ) {
                // removeChild failed catastrophically. BAIL NOW
                return;
            }
            //otherwise, clear out the memory consumed by the node
            child = null;
        }
    }
    
    for ( var i = 0; i < this.layers.length; i++ ) {
        var checkbox = document.createElement("input");
        checkbox.id = "layer_" + i;
        checkbox.name = checkbox.id;
        checkbox.type = "checkbox";
        var ltext = document.createTextNode(this.layers[i].abbreviation);

        var obj = this;
        if ( document.all ) {
            checkbox.attachEvent('onclick',function(event) {
                obj.toggleShowLayer(event);
            });
        } else {
            checkbox.addEventListener('click',function(event) {
                obj.toggleShowLayer(event);
            }, false);
        }

        var item = document.createElement("li");
        item.appendChild(checkbox);
        item.appendChild(ltext);
        currentlist.appendChild(item);

        // If this is a new layer that we haven't seen in the last load,
        // use the layers' default show state. Otherwise, use the last
        // shown state.
        if ( this.layers[i].priority == "primary" ) {
            checkbox.setAttribute("checked","checked");
        } 

    }

}

GMapWrapper.prototype.lineSelectCallback = function(start,end) {

    var midlat = (parseFloat(start[0]) + parseFloat(end[0])) / 2; 
    var midlat = (parseFloat(start[0]) + parseFloat(end[0])) / 2; 
    var midlon = (parseFloat(start[1]) + parseFloat(end[1])) / 2; 
    var bounds = this.objMap.getBounds();
    var size = this.objMap.getSize();
    var southwest = bounds.getSouthWest();
    var northeast = bounds.getNorthEast();
    var vres = size.height / Math.abs(northeast.lat() - southwest.lat());
    var hres = size.width / Math.abs(northeast.lng() - southwest.lng());
    var attribute = document.getElementById("attribute").value;
    if ( ! attribute ) attribute = "Temperature";

    var url = "request.php?action=lineSelect&slat=" + start[0] + "&slon=" + start[1] + "&elat=" + end[0] + "&elon=" + end[1] + "&vres=" + vres + "&hres=" + hres + "&attribute=" + attribute;  
    var obj = this;
    this.showLineInfowindow("<span class='loadingiw'>Loading, please wait ...</span>",midlat,midlon);
    getRemoteText(url,true,function(iwtext) {
        obj.showLineInfowindow(iwtext,midlat,midlon);
    });

    this.lastLineStart = start;
    this.lastLineEnd = end;

}

GMapWrapper.prototype.attributeChangeCallback = function() {
    var attribute = document.getElementById("attrctrl"); 
    var attrelem = document.getElementById("attribute");
    if ( ! attribute || ! attrelem ) {
        return false;
    }

    attribute = attribute.value;
    attrelem.value = attribute;

    // if we need to reload anything shown on the map, do it now.
    if ( this.firstLineMarker && this.secondLineMarker ) {
        this.lineSelectCallback(this.lastLineStart,this.lastLineEnd);
    }
    return true;
}


GMapWrapper.prototype.showLineInfowindow = function(iwtext,lat,lon) {
    this.objMap.openInfoWindowHtml(new GLatLng(lat,lon),iwtext);
}


GMapWrapper.prototype.updateLineSelectPolyline = function() {
    if ( this.firstLineMarker && this.secondLineMarker ) {
        var points = new Array(this.firstLineMarker.getLatLng(),this.secondLineMarker.getLatLng());
        this.removeLineSelectPolyline();
        this.lineSelectPolyline = new GPolyline(points,"#FFFFFF",2,0.7);
        this.objMap.addOverlay(this.lineSelectPolyline);
    }
}

GMapWrapper.prototype.removeLineSelectPolyline = function() {
    if (this.lineSelectPolyline) {
        this.objMap.removeOverlay(this.lineSelectPolyline);
    }
}

GMapWrapper.prototype.updateLineSelectMarkers = function() {
    if ( this.firstLineMarker && this.secondLineMarker ) {
        var start = this.firstLineMarker.getLatLng().toUrlValue().split(",");
        var end = this.secondLineMarker.getLatLng().toUrlValue().split(",");
        this.lineSelectCallback(start,end);
    }
}

GMapWrapper.prototype.setupLineSelect = function() {
    var mapobj = this;

/*
    this.lineSelectMarkerIcon = new GIcon();
    this.lineSelectMarkerIcon.image = 'images/dtriangle.png';
    this.lineSelectMarkerIcon.iconSize = new GSize(22,23);
    this.lineSelectMarkerIcon.iconAnchor = new GPoint(12,23);
    this.lineSelectMarkerIcon.infoWindowAnchor = new GPoint(4,4);
    this.lineSelectMarkerIcon.shadow = 'images/dtrishadow.png';
    this.lineSelectMarkerIcon.shadowSize = new GSize(39,23);
*/

    this.lineSelectMarkerIconStart = new GIcon();
    this.lineSelectMarkerIconStart.image = 'images/startflag.png';
    this.lineSelectMarkerIconStart.iconSize = new GSize(30,39);
    this.lineSelectMarkerIconStart.iconAnchor = new GPoint(15,39);
    this.lineSelectMarkerIconStart.infoWindowAnchor = new GPoint(4,4);

    this.lineSelectMarkerIconEnd = new GIcon();
    this.lineSelectMarkerIconEnd.image = 'images/endflag.png';
    this.lineSelectMarkerIconEnd.iconSize = new GSize(30,39);
    this.lineSelectMarkerIconEnd.iconAnchor = new GPoint(15,39);
    this.lineSelectMarkerIconEnd.infoWindowAnchor = new GPoint(4,4);


    var attrctrl = document.getElementById("attrctrl");
    if ( attrctrl ) {
        GEvent.addDomListener(attrctrl,"change", function() {
            mapobj.attributeChangeCallback();
        });
    }

    GEvent.addListener(this.objMap,"click",function(overlay,point) {
        if ( overlay == null ) {
            if ( ! mapobj.firstLineMarker && ! mapobj.secondLineMarker ) {
                mapobj.firstLineMarker = new GMarker(point,{draggable:true,icon:mapobj.lineSelectMarkerIconStart});

                GEvent.addListener(mapobj.firstLineMarker,"drag",function() {
                    mapobj.updateLineSelectPolyline();
                });

                GEvent.addListener(mapobj.firstLineMarker,"dragend",function() {
                    mapobj.updateLineSelectPolyline();
                    mapobj.updateLineSelectMarkers();    
                });

                mapobj.objMap.addOverlay(mapobj.firstLineMarker);
            } else if ( mapobj.firstLineMarker && ! mapobj.secondLineMarker ) {
                mapobj.secondLineMarker = new GMarker(point,{draggable:true,icon:mapobj.lineSelectMarkerIconEnd});

                GEvent.addListener(mapobj.secondLineMarker,"drag",function() {
                    mapobj.updateLineSelectPolyline();
                });

                GEvent.addListener(mapobj.secondLineMarker,"dragend",function() {
                    mapobj.updateLineSelectPolyline();
                    mapobj.updateLineSelectMarkers();    
                });

                mapobj.objMap.addOverlay(mapobj.secondLineMarker);
                mapobj.updateLineSelectPolyline();
                mapobj.updateLineSelectMarkers();    

            } else if ( mapobj.firstLineMarker && mapobj.secondLineMarker ) {
                mapobj.removeLineSelectPolyline();

                mapobj.objMap.removeOverlay(mapobj.firstLineMarker);
                mapobj.firstLineMarker = null;
                mapobj.firstLineMarker = new GMarker(mapobj.secondLineMarker.getLatLng(),{draggable:true,icon:mapobj.lineSelectMarkerIconStart});

                GEvent.addListener(mapobj.firstLineMarker,"drag",function() {
                    mapobj.updateLineSelectPolyline();
                });

                GEvent.addListener(mapobj.firstLineMarker,"dragend",function() {
                    mapobj.updateLineSelectPolyline();
                    mapobj.updateLineSelectMarkers();    
                });

                mapobj.objMap.addOverlay(mapobj.firstLineMarker);

                mapobj.objMap.removeOverlay(mapobj.secondLineMarker);
                mapobj.secondLineMarker = null;
                mapobj.secondLineMarker = new GMarker(point,{draggable:true,icon:mapobj.lineSelectMarkerIconEnd});

                GEvent.addListener(mapobj.secondLineMarker,"drag",function() {
                    mapobj.updateLineSelectPolyline();
                });

                GEvent.addListener(mapobj.secondLineMarker,"dragend",function() {
                    mapobj.updateLineSelectPolyline();
                    mapobj.updateLineSelectMarkers();    
                });

                mapobj.objMap.addOverlay(mapobj.secondLineMarker);

                mapobj.updateLineSelectPolyline();
                mapobj.updateLineSelectMarkers();    
            }
        }
    });
}


/***************************
 * GMapWrapper.groupMarkers()
 * 
 * Group markers within a certain distance from each other 
 * and display as a single marker.
 ****************************/
GMapWrapper.prototype.createGroupMarkers = function(forceReload,attempts) {
    if ( ! this.shownLayers && attempts < 4 ) {
       if ( attempts == null) {
           attempts = 0;
       }
       window.setTimeout( function (e) { this.createGroupMarkers(false,attempts+1);},1000);
       return;
    }

    var zoom = this.objMap.getZoom();

    if ( forceReload ) {
        this.clearGroupsAtZoom(zoom);
    }

    if ( ! this.groups ) {
        this.groups = new Array();
        this.groupback = new Array();
        this.doneLoading = new Array();
    }

    if ( ! this.groups[zoom] ) {
        if ( this.showloading ) {
            this.objMessage.setMessage("Loading data, please wait ... ");
            this.objMessage.show();
        }
        this.groups[zoom] = new Array();
        this.groupback[zoom] = new Array();
        this.doneLoading[zoom] = false;
        var matrix = new Array();
    
        var r = 0;
        for ( var i = 0; i < this.layers.length; i++ ) {
            for ( var j = 0; j < this.layers[i].markers.length; j++) {
                this.groupback[zoom][r] = new Object();
                this.groupback[zoom][r].layer = i;
                this.groupback[zoom][r].marker = j;

                var s = r;
                for ( var m = i; m < this.layers.length; m++ ) {
                    if ( ! this.showOverlayChooser ) var layerShown = true;
                    else var layerShown = false;

                    for ( var n = 0; n < this.shownLayers.length; n++ ) {
                        if ( this.shownLayers[n] == m ) {
                            layerShown = true;
                        }
                    }

                    for ( var n = j; n < this.layers[m].markers.length; n++ ) {

                        if ( ! matrix[r] ) {
                            matrix[r] = new Array();
                        }
                        if ( ! matrix[s] ) {
                            matrix[s] = new Array();
                        }

                        if ( r == s ) {
                            matrix[r][s] = 0;
                            matrix[s][r] = matrix[r][s];
                        } else if ( ! layerShown ) {
                            matrix[r][s] = this.groupingThreshold + 1;
                        } else {
                            
                            var marker_a = this.objMap.fromLatLngToDivPixel(this.layers[i].markers[j].getPoint());
                            var marker_b = this.objMap.fromLatLngToDivPixel(this.layers[m].markers[n].getPoint());

                            var x = Math.abs(marker_a.x - marker_b.x);
                            var y = Math.abs(marker_a.y - marker_b.y);
                            matrix[r][s] = Math.sqrt((x*x)+(y*y));
                            matrix[s][r] = matrix[r][s];
                        }
                        s++;
                    }
                }
                r++;
            }
        }

        for ( var i = 0; i < matrix.length; i++ ) {
            for ( var j = i+1; j < matrix.length; j++ ) {
                if ( matrix[i][j] < this.groupingThreshold ) {
                    var a = this.groupback[zoom][i]; 
                    var b = this.groupback[zoom][j]; 

                    if ( this.groups[zoom].length < 1 ) {
                        this.groups[zoom].push(new Array());
                        this.groups[zoom][0].push(i,j);
                    } else {
                        var added = false;
                        for ( var p = 0; p < this.groups[zoom].length; p++ ){
                            lastgroup = true;
                            for ( var q = 0; q < this.groups[zoom][p].length; q++ ) {
                                if ( matrix[this.groups[zoom][p][q]][j] > this.groupingThreshold ) {
                                    lastgroup = false;
                                    added = true;
                                    break;
                                }
                                if ( this.groups[zoom][p][q] == j ) {
                                    lastgroup = false; 
                                    added = true; 
                                }
                            }
                            if ( lastgroup ) {
                                this.groups[zoom][p].push(j);
                                added = true;
                            } 
                        }
                        if ( ! added ) {
                            var group = new Array();
                            group.push(i,j);
                            this.groups[zoom].push(group);
                        }
                    }
                } 
            }
        }

        if ( ! this.groupm ) {
            this.groupm = new Array();
        }

        if ( ! this.groupm[zoom] ) {
            this.groupm[zoom] = new Array();
        }

        for ( var i = 0; i < this.groups[zoom].length; i++ ){
            var totallat = 0;
            var totallong = 0;

            for ( var j = 0; j < this.groups[zoom][i].length; j++ ) {
                var markerinfo = this.groupback[zoom][this.groups[zoom][i][j]];
                var marker = this.layers[markerinfo.layer].markers[markerinfo.marker];
                var point = marker.getPoint();
                this.layers[markerinfo.layer].markers[markerinfo.marker].orig = point;
                totallong += point.x;
                totallat += point.y;
            }

            var aggpoint = new GPoint(totallong / j, totallat / j );
            var mapobj = this;

            this.groupm[zoom][i] = new GMarker(aggpoint,{icon:this.groupIcon,title:'click to view markers in this cluster'});
            this.groupm[zoom][i].groupnum = i;

            GEvent.addListener(this.groupm[zoom][i],"click",function () {
                mapobj.hideGroupMarkers();
                mapobj.showGroupMarkers(this.groupnum);
            });
            GEvent.addListener(this.groupm[zoom][i],"mouseover",function () {
                mapobj.showGroupMarkers(this.groupnum);
            });
            GEvent.addListener(this.objMap,"click",function (overlay,point) {
                if ( ! overlay ) { 
                    mapobj.hideGroupMarkers();
                }
            });
        }
        this.doneLoading[zoom] = true;
        //this.objMessage.hide();
    }
}

GMapWrapper.prototype.clearGroupsAtZoom = function(zoom) {
    if ( this.groups && this.groups[zoom] ) {
        for ( var i = 0; i < this.groups[zoom].length; i++ ) {
            for ( var j = 0; j < this.groups[zoom][i].length; j++ ) {
                for ( var k = 0; k < this.groups[zoom][i][j].length; k++ ) {
                    this.groupback[zoom][this.groups[zoom][i][j][k]] = null;
                }
            }
            this.objMap.removeOverlay(this.groupm[zoom][i]);
            this.groupm[zoom][i] = null;
            this.groups[zoom][i] = null;
        }
        this.groupback[zoom] = null;
        this.groups[zoom] = null;
    }
}

 
GMapWrapper.prototype.groupMarkers = function() {
    this.activegroup = null;
    var zoom = this.objMap.getZoom();
    if ( this.groups && this.groups[zoom] ) {
        for ( var i = 0; i < this.groups[zoom].length; i++ ) {
            for ( var j = 0; j < this.groups[zoom][i].length; j++ ) {
                var markerinfo = this.groupback[zoom][this.groups[zoom][i][j]];
                var marker = this.layers[markerinfo.layer].markers[markerinfo.marker];
                marker.hide();
                if ( this.useMarkerManager ) {
                    //this.layers[markerinfo.layer].mm.refresh();
                }
            }
            this.objMap.addOverlay(this.groupm[zoom][i]);
        }
    }
}


GMapWrapper.prototype.unGroupMarkers = function() {
    var zoom = this.groupzoom;
    if ( zoom && this.groups[zoom] ) {
        for ( var i = 0; i < this.groups[zoom].length; i++ ) {
            this.objMap.removeOverlay(this.groupm[zoom][i]);
            for ( var j = 0; j < this.groups[zoom][i].length; j++ ) {
                var markerinfo = this.groupback[zoom][this.groups[zoom][i][j]];
                var marker = this.layers[markerinfo.layer].markers[markerinfo.marker];
                if ( this.groupedLines && this.groupedLines[zoom] && 
                    this.groupedLines[zoom][i]&& this.groupedLines[zoom][i][j] ) {
                    this.objMap.removeOverlay(this.groupedLines[zoom][i][j]);
                }
                if ( this.groupedCenter && this.groupedCenter[zoom] &&
                    this.groupedCenter[zoom][i] && this.groupedCenter[zoom][i][j] ) {
                    this.groupedCenter[zoom][i][j].hide();
                }
                marker.setPoint(marker.orig);
                marker.show();
                if ( this.useMarkerManager ) this.layers[markerinfo.layer].mm.refresh();
            }
        }
    }
}


/***************************
 * GMapWrapper.showGroupMarkers()
 * 
 * Show the individual markers in a given group and hide the aggregate 
 * marker.
 ****************************/
GMapWrapper.prototype.showGroupMarkers = function(groupnum) {
     var zoom = this.objMap.getZoom();

     if ( this.doneLoading[zoom] && this.groupm[zoom] && this.activegroup == null ) {
         this.activegroup = groupnum;
         this.groupzoom = zoom;

         if ( this.groups[zoom] ) {
             if ( ! this.groupedLines ) {
                 this.groupedLines = new Array();
                 this.groupedCenter = new Array();
             }
             if  ( ! this.groupedLines[zoom] ) {
                 this.groupedLines[zoom] = new Array();     
                 this.groupedCenter[zoom] = new Array();     
             }
             var i = groupnum;
             var centerll = this.groupm[zoom][i].getPoint();
             var center = this.objMap.fromLatLngToDivPixel(centerll);
             this.groupm[zoom][i].hide();
             var marker_angle = (2 * Math.PI) * Math.random();
             var anglediff = 2  * Math.PI / parseInt((this.groups[zoom][i].length));
             this.groupedLines[zoom][i] = new Array(); 
             this.groupedCenter[zoom][i] = new Array(); 

             for ( var j = 0; j < this.groups[zoom][i].length; j++ ) {
                 var markerinfo = this.groupback[zoom][this.groups[zoom][i][j]];
                 var marker = this.layers[markerinfo.layer].markers[markerinfo.marker];
                 var x = Math.sin(marker_angle) * this.expandDistance;
                 var y = Math.cos(marker_angle) * this.expandDistance;
                 marker.setPoint(this.objMap.fromDivPixelToLatLng(new GPoint(center.x-x , center.y - y)));
                 marker.show();
                 marker_angle -= anglediff;
                 if ( ! this.groupedLines[zoom][i][j] ) {
                     this.groupedLines[zoom][i][j] = new GPolyline(new Array(centerll,marker.getPoint()),"#FFFFFF",2,0.7);
                     this.objMap.addOverlay(this.groupedLines[zoom][i][j]);
                     this.groupedCenter[zoom][i][j] = new GMarker(centerll,{icon:this.groupCenterIcon});
                     this.objMap.addOverlay(this.groupedCenter[zoom][i][j]);
                 } else if ( this.useAlternateHideShow() ) {
                     this.objMap.addOverlay(this.groupedLines[zoom][i][j]);
                     this.groupedCenter[zoom][i][j].show();
                 } else {
                     this.groupedLines[zoom][i][j].show();
                     this.groupedCenter[zoom][i][j].show();
                 }
                 if ( this.useMarkerManager ) {
                     this.layers[markerinfo.layer].mm.refresh();
                 }
             }
         }
    }
}


/***************************
 * GMapWrapper.hideGroupMarkers()
 * 
 * Hide the individual markers in a group and display the aggregate
 * marker.
 ****************************/
GMapWrapper.prototype.hideGroupMarkers = function() {
     var zoom = this.groupzoom;
     if ( this.doneLoading[zoom] && this.groups[zoom] && (this.activegroup != null)) {
        var i = this.activegroup;
        for ( var j = 0; j < this.groups[zoom][i].length; j++ ) {
             var markerinfo = this.groupback[zoom][this.groups[zoom][i][j]];
             var marker = this.layers[markerinfo.layer].markers[markerinfo.marker];
             marker.hide();
             if ( this.useAlternateHideShow) {
                 // The alternate hide method is intended for markers, only,
                 // and breaks badly with polys.
                 this.objMap.removeOverlay(this.groupedLines[zoom][i][j]);
             } else {
                 this.groupedLines[zoom][i][j].hide();
             }
             this.groupedCenter[zoom][i][j].hide();
             if ( this.useMarkerManager ) {
                 //this.layers[markerinfo.layer].mm.refresh();
             }
         }
         this.groupm[zoom][i].show();
         this.activegroup = null;
     }
}

/***************************
 * GMapWrapper.openSiteWindowFromSidebar()
 * 
 * Selects the appropriate marker to activate on selection from
 * the sidebar.
 ****************************/
GMapWrapper.prototype.openSiteWindowFromSidebar = function(event) {
    if ( !event ) event = window.event;
    if ( typeof(event) == "string" ) {
        site = event;
    } else {
        var site = (event.target) ? event.target : event.srcElement; 
        site = site.id.replace(/^label_(.*)$/,"$1");
    }

    this.selectSite(site);
    if ( site ) {
        var marker = this.getMarkerForSite(site);
        var iw = this.objMap.getInfoWindow();
        if ( this.showInfoWindow || this.showInfoBlock) {
            this.onMarkerClick(marker);
        } 
        if ( this.smoothpan && (this.objMap.getZoom() == marker.zoom) ) {
            this.objMap.panTo(marker.getPoint());
        } else {
            this.objMap.setCenter(marker.getPoint(),marker.zoom);
        }
    }
}

/***************************
 * GMapWrapper.onMarkerClick()
 * 
 * Opens an infowindow for a given marker and records the time
 * that this occurred.
 ****************************/
GMapWrapper.prototype.onMarkerClick = function(marker,triggered) {
    if ( ! marker ) {
        alert("This location is still loading. Thank you for your patience.");
        return;
    }
 
    if ( this.mapAreaMarker ) {
        this.objMap.removeOverlay(this.mapAreaMarker);
    }

    if ( this.showInfoBlock ) {
        var mapinfo = document.getElementById("mapinfoblock");
        mapinfo.innerHTML = marker.iw;
        var parentclasses = mapinfo.parentNode.className;
        if (! parentclasses || (parentclasses && !parentclasses.match("openediw"))) {
            mapinfo.parentNode.className = parentclasses + " openediw";
        }
        if (this.notifyOnMarkerChange) {
            fadeBlink(mapinfo,10,10,10);
        }
    } 
    if ( this.showInfoWindow ) {
         marker.openInfoWindowTabsHtml(marker.iw);
    }

    this.iwlayer = marker.layername;
    this.iwmarker = marker.fullname;

    this.lastopened = (new Date()).getTime();

    if ( this.lastMarker ) {
        this.lastMarker.setImage(this.lastMarker.normalStyle.icon.image);
        this.lastMarker = null;
    }

    if ( this.showHighlightedMarker != false ) {
        marker.setImage(marker.highlightStyle.icon.image);
        this.lastMarker = marker;
    }
    
    if ( this.showTour ) {
        var nextlinks = document.getElementsByName("next");
        var prevlinks = document.getElementsByName("prev");
        var mapobj = this;
        for ( var i = 0; i < nextlinks.length; i++ ) {
            GEvent.addDomListener(nextlinks[i],"click",function(event) {
                if ( !event ) event = window.event;
                var target = (event.target) ? event.target : event.srcElement; 
                if ( marker.next ) {
                    mapobj.travelToSite(marker.next);
                }
            });
            GEvent.addDomListener(prevlinks[i],"click",function(event) {
                if ( !event ) event = window.event;
                var target = (event.target) ? event.target : event.srcElement; 
                if ( marker.prev ) {
                    mapobj.travelToSite(marker.prev);
                }
            });
        }
    }

    if ( typeof(triggered) != "undefined" && triggered === true ) {
        GEvent.trigger(this,'itemselected',marker);        
    }

}

GMapWrapper.prototype.onPolygonClick = function(polyline,point,points) {
    this.objMap.openInfoWindowTabsHtml(point,polyline.iw);
}

GMapWrapper.prototype.onPolylineClick = function(polyline,point) {
    this.objMap.openInfoWindowTabsHtml(point,polyline.iw);
}

/***************************
 * GMapWrapper.addDocument()
 * 
 * Parses the given KML document for site information and passes 
 * this information along to be mapped appropriately by mapAll().
 ****************************/
GMapWrapper.prototype.addDocument = function(xmlDoc,extension) {
    // Only support kml or georss w/rss2.0 for now
    if ( this.showloading ) {
        this.objMessage.setMessage("Loading data, please wait ... ");
        this.objMessage.show();
    }

    if ( extension == "xml" ) {
        var layers =  this.parseRSS2(xmlDoc);
    } else {
        var layers =  this.parseKML(xmlDoc);
    }
    this.layers = this.layers.concat(layers);
    var startlayer = this.layers.length - layers.length;

    if ( layers.length < 1 ) {
    } else {
        for (this.curLayer = startlayer; this.curLayer < this.layers.length; this.curLayer++ ) {
            this.layers[this.curLayer].markers = new Array();
            if ( this.useMarkerManager ) {
                this.layers[this.curLayer].mm = new GMarkerManager(this.objMap,{trackMarkers:true});
            }
            this.layers[this.curLayer].polygons = new Array();
            this.layers[this.curLayer].polylines = new Array();
            if ( this.showloading ) {
                if ( this.layers[this.curLayer].abbreviation ) {
                    this.objMessage.setMessage("Loading " + this.layers[this.curLayer].abbreviation + " ...");
                    //this.objMessage.setMessage("Loading data, please wait ...");
                } else {
                    this.objMessage.setMessage("Loading data, please wait ...");
                }
                this.objMessage.show();
            }

            this.curItem = 0;
            while( this.curItem < this.layers[this.curLayer].placemarks.length ) {
                this.mapAll();

                if ( this.layers[this.curLayer].shown ) {
                    this.shownLayers.push(this.curLayer);
                }

                if ( this.layers[this.curLayer].shown && this.useMarkerManager ) {
                    this.layers[this.curLayer].mm.refresh();
                }
            }

            if ( this.showSiteChooser ) {
                this.createSiteChooser(this.layers[this.curLayer].placemarks,"labels_" + this.curLayer);
            
            }
        }
    }
    if ( this.showloading ) {
        this.objMessage.hide();
    }
}

/***************************
 * GMapWrapper.parseRSS2()
 * 
 * Extracts an array of marker locations and polygons
 * from the given kml representation.
 ****************************/
GMapWrapper.prototype.parseRSS2 = function(xmlDoc) {
    var layers = new Array();

    var rss = xmlDoc.getElementsByTagName("rss"); 
    for ( var i = 0; i < rss.length; i++ ) {
        var channels = rss[i].getElementsByTagName("channel");
        for ( var j = 0; j < channels.length; j++ ) {
            var layer = new Object();
            layer.shown = true;
            layer.placemarks = new Array();
            layer.choicetype = "checkbox";

            var title = channels[j].getElementsByTagName("title");
            if ( title.length > 0 ) {
                layer.abbreviation = GXml.value(title[0]);
            }

            var items = channels[j].getElementsByTagName("item");
            for ( var k = 0; k < items.length; k++ ) {
                var site = new Object();
                site.normalStyle = 'default';
                site.showMarkers = true;
                site.description = new Array();
                var title = items[k].getElementsByTagName("title");
                if ( title.length > 0 ) {
                    site.abbreviation = GXml.value(title[0]);
                    site.name = site.abbreviation;
                }

                var url = items[k].getElementsByTagName("guid");
                if ( url.length > 0 ) {
                    site.link = GXml.value(url[0]);
                }

                var description = items[k].getElementsByTagName("description");
                if ( description.length > 0 ) {
                    if ( this.includeNameInInfowindow ) {
                        d = "";
                        d += '<div class="iwwrapper">';
                        d += '<div class="iwheader">';
                        if (site.link != null) 
                            d += '<a href="' + site.link + '" target="_blank">' + site.name + '</a>';
                        else 
                            d += site.name;

                        d += '</div>';
                        d += '<div class="iwbody">';
                        d += GXml.value(description[0]);
                        d += '</div>';
                        d += '</div>';
                    } else {
                        d = GXml.value(description[0]);
                    }
                    site.description.push(d);
                }

                var point = items[k].getElementsByTagNameNS("http://www.georss.org/georss","point");
                if ( point.length > 0 ) {
                    var pt = GXml.value(point[0]);
                    pt = pt.split(" ");
                    site.type="marker";
                    site.loc = new GLatLng(parseFloat(pt[0]),parseFloat(pt[1]));
                }

                layer.placemarks.push(site);
            }
            layers.push(layer);
        }
    }

    return layers;
}


/***************************
 * GMapWrapper.parseKML()
 * 
 * Extracts an array of marker locations and polygons
 * from the given kml representation.
 ****************************/
GMapWrapper.prototype.parseKML = function(xmlDoc) {
    var mih = null;
    var miw = null;
    var layers = new Array();
    var layer;

    var kml = xmlDoc.getElementsByTagName("kml"); 
    for ( var i = 0; i < kml.length; i++ ) {
        var docs = kml[i].getElementsByTagName("Document");
        for ( var j = 0; j < docs.length; j++ ) {
            var metadata = docs[j].getElementsByTagName("Metadata");
            if ( metadata.length > 0 )  {
                for ( var k = 0; k < metadata.length; k++ ) {
                    var iconHeight = metadata[0].getElementsByTagName("iconHeight");
                    if ( iconHeight.length > 0 ){
                        mih = GXml.value(iconHeight[0]);
                    }

                    var iconWidth = metadata[0].getElementsByTagName("iconWidth");
                    if ( iconWidth.length > 0 ){
                        miw = GXml.value(iconWidth[0]);
                    }

                    var chooserLabel = metadata[0].getElementsByTagName("overlayChooserLabel");
                    if ( chooserLabel.length > 0 ) {
                        this.chooserLabel = GXml.value(chooserLabel[0]);
                    }
                
                    var chooserNames = metadata[0].getElementsByTagName("overlayChooserName");
                    for ( var l = 0; l < chooserNames.length; l++ ) {
                        var layerAbbreviation = GXml.value(chooserNames[l]);
                    }
                }
            }
        }

        var docstyles = kml[i].getElementsByTagName("Style");

        for ( var k = 0; k < docstyles.length; k++ ) {
            var label = docstyles[k].getAttribute("id");
            if ( this.styles[label] == null ) {
                this.styles[label] = new Object();
                this.styles[label].icon = this.defaultIcon;
                this.styles[label].strokecolor = this.styles['default'].strokecolor;
                this.styles[label].strokeopacity = this.styles['default'].strokeopacity;
                this.styles[label].strokewidth = this.styles['default'].strokewidth;
                this.styles[label].fillcolor = this.styles['default'].fillcolor;
                this.styles[label].fillopacity = this.styles['default'].fillopacity;
                this.styles[label].listtype = this.styles['default'].listtype;
            }

            
            var icons = docstyles[k].getElementsByTagName("Icon");
            if ( icons.length > 0 ) {
                var hotspot = GXml.value(icons[0].getElementsByTagName("hotSpot")[0]);
                var uri = GXml.value(icons[0].getElementsByTagName("href")[0]);
                var ih = mih;
                var iw = miw;

                if ( ih == null || iw == null ) {
                    var ihw =  getImageHeightWidthFromImageBank(uri);
                    ih = ihw[0];
                    iw = ihw[1];
                    if ( ih == null || iw == null ) {
                        var ihw =  getImageHeightWidth(uri);
                        ih = ihw[0];
                        iw = ihw[1];
                    }
                }

                if ( ( iw>0 ) && (ih>0) ) {
                    if ( hotspot.length > 0 ) {
                        var x = hotspot[0].getAttribute("x");
                        var y = hotspot[0].getAttribute("y");
                        var xmethod = hotspot[0].getAttribute("xunits");
                        var ymethod = hotspot[0].getAttribute("yunits");
                        if ( xmethod == "fraction" ) {
                            iwx = iw * x;
                        } else {
                            iwx = x;
                        }
                        if ( xmethod == "fraction" ) {
                            iwy = iw * y;
                        } else {
                            iwy = y;
                        }
                    } else {
                        var iwx = iw/2;
                        var iwy = ih/2;
                    }
                    var iwax = iw/2;
                    var iway = ih/2;
                    this.styles[label].icon = new GIcon(); 
                    this.styles[label].icon.image = uri;
                    this.styles[label].icon.iconSize = new GSize(iw,ih);
                    this.styles[label].icon.iconAnchor = new GPoint(iwx,iwy);
                    this.styles[label].icon.infoWindowAnchor = new GPoint(iwax,iway);
                }
            }

            var polystyles = docstyles[k].getElementsByTagName("PolyStyle");
            if ( polystyles.length > 0 ) {
                var r=GXml.value(polystyles[0].getElementsByTagName("color")[0]).substr(6,2)
                var g=GXml.value(polystyles[0].getElementsByTagName("color")[0]).substr(4,2)
                var b=GXml.value(polystyles[0].getElementsByTagName("color")[0]).substr(2,2)
                var a=GXml.value(polystyles[0].getElementsByTagName("color")[0]).substr(0,2)
                this.styles[label].fillcolor = "#" + r + g + b;
                this.styles[label].fillopacity = hex2dec(a) / 256;
                //this.styles[label].fillopacity = hex2dec(GXml.value(polystyles[0].getElementsByTagName("color")[0]).substr(6,2)) / 256;
            }

            var linestyles = docstyles[k].getElementsByTagName("LineStyle");
            if ( linestyles.length > 0 ) {
                var r=GXml.value(linestyles[0].getElementsByTagName("color")[0]).substr(6,2)
                var g=GXml.value(linestyles[0].getElementsByTagName("color")[0]).substr(4,2)
                var b=GXml.value(linestyles[0].getElementsByTagName("color")[0]).substr(2,2)
                var a=GXml.value(linestyles[0].getElementsByTagName("color")[0]).substr(0,2)
                this.styles[label].strokecolor = "#" + r + g + b;
                this.styles[label].strokeopacity = hex2dec(a) / 256;
                this.styles[label].strokewidth = parseFloat(GXml.value(linestyles[0].getElementsByTagName("width")[0]));
            }


            var liststyles = docstyles[k].getElementsByTagName("ListStyle");
            if ( liststyles.length > 0 ) {
                var listitem = liststyles[0].getElementsByTagName("listItemType");
                if ( listitem.length > 0 ) {
                    listitem = GXml.value(listitem[0]);
                    if ( listitem == "radioFolder" ) {
                        this.styles[label].listtype = "radio";
                    }
                }
            }
        }

        var stylemap = kml[i].getElementsByTagName("StyleMap");
        for ( q = 0; q < stylemap.length; q++ ) {
            var label = stylemap[q].getAttribute("id");
            var pairs = stylemap[q].getElementsByTagName("Pair");
            for (var n = 0; n < pairs.length; n++ ) {
                var key = pairs[n].getElementsByTagName("key");
                if ( key.length > 0 ) {
                     var url = pairs[n].getElementsByTagName("styleUrl");

                     var stype = GXml.value(key[0]);
                     if ( ! this.styles[label] ) this.styles[label] = new Object();
                     if ( stype == "normal" ) {
                        this.styles[label].normal = GXml.value(url[0]).substr(1);
}
                     if ( stype == "highlight" ) {
                        this.styles[label].highlight = GXml.value(url[0]).substr(1);
                     }
                }
            }
        } 

        var parentstack = [];
        var lastlevel = 0;
        var folders = kml[i].getElementsByTagName("Folder");
        for ( var k = 0; k < folders.length; k++ ) {
            layer = {};
            layer.freevars = [];
            layer.placemarks = [];
            layer.name = "Layer " + (k+1);
            layer.shown = true;
            layer.abbreviation = abbreviation;
            layer.parent = null;
            layer.level = 0;
            layer.children = [];
                var folderNames = folders[k].getElementsByTagName("name");
                for ( var m = 0; m < folderNames.length; m++ ) {
                    if ( folderNames[m].parentNode == folders[k] ) {
                        layer.name = GXml.value(folderNames[m]);
                        break;
                    }
                }

                var showlayer = folders[k].getElementsByTagName("open");
                if ( showlayer.length > 0 ) {
                    if ( GXml.value(showlayer[0]) == 1 ) {
                        layer.priority = "primary";
                        layer.shown = true;
                    } else {
                        layer.priority = "secondary";
                        layer.shown = false;
                    }
                }

               
                var folderMeta = folders[k].getElementsByTagName("Metadata");
                if ( folderMeta.length > 0 ) {
                    var priority = folderMeta[0].getElementsByTagName("priority");
                    if ( priority.length > 0 ) {
                        layer.priority = GXml.value(priority[0]);
                        if ( layer.priority != "primary" ) {
                            layer.shown = false;
                        }
                    }

                    var helplink = folderMeta[0].getElementsByTagName("helpLink");
                    if ( helplink.length > 0 ) {
                        layer.helplink = GXml.value(helplink[0]);
                    }

                    var chooserNames = folderMeta[0].getElementsByTagName("overlayChooserName");
                    if ( chooserNames.length > 0 ) {
                        layer.abbreviation = GXml.value(chooserNames[0]);
                    }

                    var legendIconHeight = folderMeta[0].getElementsByTagName("legendIconHeight");
                    if ( legendIconHeight.length > 0 ) {
                        layer.legendIconHeight = GXml.value(legendIconHeight[0]);
                    }

                    var legendIconWidth = folderMeta[0].getElementsByTagName("legendIconWidth");
                    if ( legendIconWidth.length > 0 ) {
                        layer.legendIconWidth = GXml.value(legendIconWidth[0]);
                    }

                }

                var styleurl = folders[k].getElementsByTagName("styleUrl");
                if ( styleurl.length > 0 && styleurl[0].parentNode == folders[k] ) {
                    layer.legendIconStyle = GXml.value(styleurl[0]).substr(1);
                }
                if ( layer.legendIconStyle == null ) layer.legendIconStyle = 'default';
            //}

            if ( typeof(layer.abbreviation) == "undefined" ) layer.abbreviation = layer.name;
            
            if ( folders[k].parentNode.tagName == "Folder" ) {
                var curel = folders[k].parentNode;
                while ( curel.tagName == "Folder" && curel.parentNode != null) {
                    layer.level += 1;
                    curel = curel.parentNode; 
                }
            }
            if ( layer.level > lastlevel ) {
                layer.parent = parentstack[parentstack.length-1];
            } else if ( layer.level < lastlevel ) {
                lastparent = parentstack.pop(); 
            } else {
                parentstack.pop();
                layer.parent = parentstack[parentstack.length-1];
            }
            parentstack.push(layer.name);
            lastlevel = layer.level;

            for ( var m = 0; m < folders[k].childNodes.length; m++ ) {
                if ( folders[k].childNodes[m].tagName == "ExtendedData" ) {
                    extendeddata = folders[k].childNodes[m];
                    var data = extendeddata.getElementsByTagName("Data");
                    for ( var n = 0; n < data.length; n++ ) {
                        var dn = GXml.value(data[n].getElementsByTagName("displayName")[0]);
                        var val = data[n].getElementsByTagName("value")[0];
                        if ( dn == "zoomlevel" ) {
                            layer.zoom = GXml.value(val);
                        } else if ( dn == "iw" ) {
                            iw = val.getElementsByTagName("iw");
                        } else if ( dn == "showmarkers" ) {
                            //site.showMarkers = GXml.value(val[0]) == "true";
                        } else {
                            layer.freevars[dn] = GXml.value(val);
                        }
                    } 
                }
            }

            var placemarks = folders[k].getElementsByTagName("Placemark");

            for ( var m=0; m < placemarks.length; m++ ) {
                if ( placemarks[m].parentNode != folders[k] ) continue;
                var site = new Object();
                var polygons = placemarks[m].getElementsByTagName("Polygon");
                var lines = placemarks[m].getElementsByTagName("LineString");
                var points = placemarks[m].getElementsByTagName("Point");
                var metadata = placemarks[m].getElementsByTagName("Metadata");
                var extendeddata = placemarks[m].getElementsByTagName("ExtendedData");
                 
                site.loc = null;
                site.showPolyLines = true;
                site.showPolygons = true;
                site.showMarkers = true;    
                site.freevars = [];

               var styleurl = placemarks[m].getElementsByTagName("styleUrl");
                if ( styleurl.length > 0 ) {
                    site.style = GXml.value(styleurl[0]).substr(1);
                } else {
                    if ( layer.legendIconStyle ) {
                        site.style = layer.legendIconStyle;
                    } else {
                        site.style = 'default';
                    }
                }

                var iw = null;
                if ( extendeddata.length > 0 ) {
                    var data = extendeddata[0].getElementsByTagName("Data");
                    for ( var n = 0; n < data.length; n++ ) {
                        var dn = GXml.value(data[n].getElementsByTagName("displayName")[0]);
                        var val = data[n].getElementsByTagName("value")[0];
                        if ( dn == "zoomlevel" ) {
                            site.zoom = GXml.value(val);
                        } else if ( dn == "iw" ) {
                            iw = val.getElementsByTagName("iw");
                        } else if ( dn == "showmarkers" ) {
                            //site.showMarkers = GXml.value(val[0]) == "true";
                        } else {
                            site.freevars[dn] = GXml.value(val);
                        }
                    } 
                }

                if ( metadata.length > 0 ) {
                    var showmarkers = metadata[0].getElementsByTagName("showmarkers");
                    if (showmarkers.length > 0 ) {
                        if ( GXml.value(showmarkers[0]) == "true" ) {
                           site.showMarkers = true;    
                        } else {
                           site.showMarkers = false;    
                        }
                    }

                    var showpolygons = metadata[0].getElementsByTagName("showpolygons");
                    if (showpolygons.length > 0 ) {
                        if ( GXml.value(showpolygons[0]) == "true" ) {
                           site.showPolygons = true;    
                        } else {
                           site.showPolygons = false;    
                        }
                    }

                    var showlines = metadata[0].getElementsByTagName("showlines");
                    if (showlines.length > 0 ) {
                        if ( GXml.value(showlines[0]) == "true" ) {
                           site.showPolyLines = true;    
                        } else {
                           site.showPolyLines = false;    
                        }
                    }

                    var abbreviation = metadata[0].getElementsByTagName("abbreviation");
                    if ( abbreviation.length > 0 ) {
                        site.abbreviation = GXml.value(abbreviation[0]);
                    } 
                    var link = metadata[0].getElementsByTagName("Link");
                    if ( link.length > 0 ) {
                        site.link = GXml.value(link[0]);
                    }

                    var center = metadata[0].getElementsByTagName("centerpoint");
                    if ( center.length > 0 ) {
                        var clatlon = GXml.value(center[0]).match(/^\s*(([\d+-.]*),([\d+-.]*),([\d+-.]*))\s*$/);
                        if (clatlon && clatlon.length > 3 ) {
                            site.center = new GLatLng(parseFloat(clatlon[3]),parseFloat(clatlon[2]));

                            var showCenter = metadata[0].getElementsByTagName("hidecenter");
                            if ( showCenter.length > 0 ) {
                                site.showcenter = false;
                            } else {
                                site.showcenter = true;
                            }
                            
                        }
                    }

                    var textanchor = metadata[0].getElementsByTagName("textanchor");
                    if ( textanchor.length > 0 ) {
                        var clatlon = GXml.value(textanchor[0]).match(/^\s*(([\d+-.]*),([\d+-.]*),([\d+-.]*))\s*$/);
                        if (clatlon && clatlon.length > 3 ) {
                            site.textanchor = new GLatLng(parseFloat(clatlon[3]),parseFloat(clatlon[2]));
                            var showLabel = metadata[0].getElementsByTagName("showlabel");
                            if ( showLabel.length > 0 ) {
                                site.showlabel = true;
                            } else {
                                site.showlabel = false;
                            }
                        }
                    }

                    var zoom = metadata[0].getElementsByTagName("gmapzoomlevel");
                    if ( zoom.length > 0 ) {
                        site.zoom = parseInt(GXml.value(zoom[0]));
                    } else {
                        site.zoom = this.closeZoom;
                    }

                    if ( ! iw ) iw = metadata[0].getElementsByTagName("iw");
                }

                if ( iw && iw.length > 0 ) {
                    site.description = new Array();
                    site.iwlabel = new Array();
                    for ( var n = 0; n < iw.length; n++ ) {
                        site.iwlabel[n] = "";
                        var labels = iw[n].getElementsByTagName("label");
                        var descr = iw[n].getElementsByTagName("description");
                        if ( labels.length > 0 ) {
                            site.iwlabel[n] = GXml.value(labels[0]);
                        }
                        if ( descr.length > 0 ) {
                            if ( this.includeNameInInfowindow && (iw.length < 2) ) {
                                d = "";
                                d += '<div class="iwwrapper">';
                                d += '<div class="iwheader">';
                                if (site.link != null) 
                                    d += '<a href="' + site.link + '" target="_blank">' + site.abbreviation + '</a>';
                                else 
                                    d += site.abbreviation;

                                d += '</div>';
                                d += '<div class="iwbody">';
                                d += GXml.value(descr[0]);
                                d += '</div>';
                                d += '</div>';

                                site.description[n] = d;
                            } else {
                                site.description[n] = '<div class="iwwrapper"><div class="iwbody">' + GXml.value(descr[0]) + '</div></div>';
                            }
                        }
                    }
                }

                if ( this.showMarkers && site.showMarkers ) {
                    if ( points.length > 0 ) {
                      var coordinates  = points[0].getElementsByTagName("coordinates");
                      if ( coordinates.length > 0 ) {
                          var clatlon = GXml.value(coordinates[0]).match(/^\s*(([\d+-.]*),([\d+-.]*),([\d+-.]*))\s*$/);
                          if (clatlon && clatlon.length > 3 ) {
                              site.loc = new GLatLng(parseFloat(clatlon[3]),parseFloat(clatlon[2]));
                          }
                       }
                    }
                }

                if ( this.showPolygons && site.showPolygons && polygons.length > 0 ) {
                    site.type="polygon";
                    site.points = new Array();
                    for ( var n = 0; n < polygons.length; n++ ) {
                        var latlon = polygons[n].getElementsByTagName("coordinates");

                        for ( var r = 0; r < latlon.length; r++ ) {
                            latlons = GXml.value(latlon[r]).split(/\s/);
                            ppoints = new Array();

                            for (var p = 0; p < latlons.length; p++ ) {
                                if ( latlons[p].match(/^\s*$/) ) {
                                    continue;
                                }
                                var coords = latlons[p].match(/^\s*(([\d+-.]*),([\d+-.]*),([\d+-.]*))\s*$/);
                                if ( coords && coords.length >= 3 ) {
                                    ppoints.push(new GLatLng(parseFloat(coords[3]),parseFloat(coords[2])));
                                }
                            }

                            if ( ppoints.length > 0 ) {
                                site.points.push(ppoints);
                            }
                        }
                    }
                }

                if ( this.showPolyLines && site.showPolyLines && lines.length > 0 ) {
                    site.type="polyline";
                    site.points = new Array();
                    for ( var n = 0; n < lines.length; n++ ) {
                        var latlon = lines[n].getElementsByTagName("coordinates");

                        for ( var r = 0; r < latlon.length; r++ ) {
                            var latlons = GXml.value(latlon[r]).split(/\s/);
                            var ppoints = new Array();

                            for (var p = 0; p < latlons.length; p++ ) {
                                if ( latlons[p].match(/^\s*$/) ) {
                                    continue;
                                }
                                var coords = latlons[p].match(/^\s*(([\d+-.]*),([\d+-.]*),([\d+-.]*))\s*$/);
                                if ( coords && coords.length >= 3 ) {
                                    ppoints.push(new GLatLng(parseFloat(coords[3]),parseFloat(coords[2])));
                                }
                            }

                            if ( ppoints.length > 0 ) {
                                site.points.push(ppoints);
                            }
                        }
                    }
                }

                var names = placemarks[m].getElementsByTagName("name");
                if ( names.length > 0 ) {
                    site.name = GXml.value(names[0]);
                    if ( ! site.abbreviation ) site.abbreviation = site.name;
                }

                var descriptions = placemarks[m].getElementsByTagName("description");
                if ( ! ( site.description ) && descriptions.length > 0 ) {
                    site.description = new Array();
                    site.iwlabel = new Array();
                    for ( var n = 0; n < descriptions.length; n++ ) {
                        if (this.includeNameInInfowindow) {
                            var d = "";
                            d += '<div class="iwwrapper">';
                            d += '<div class="iwheader">';
                            if (site.link != null) 
                                d += '<a href="' + site.link + '" target="_blank">' + site.name + '</a>';
                            else 
                                d += site.name;

                            d += '</div>';
                            d += '<div class="iwbody">';
                            d += GXml.value(descriptions[n]);
                            d += '</div>';
                            d += '</div>';
                            site.description.push(d);
                            site.iwlabel.push(site.name);
                        } else {
                            site.description.push(GXml.value(descriptions[n]));
                        }
                    }
                }

                layer.placemarks.push(site);
            }

            var overlays = folders[k].getElementsByTagName("GroundOverlay");
            for ( var m=0; m < overlays.length; m++ ) {
                var site = new Object();
                site.type = "image";
                site.priority = -1;
                site.showImageOverlays = true;    

                var showio = overlays[m].getElementsByTagName("showimageoverlays");
                if ( showio.length > 0 ) site.showImageOverlays = GXml.value(showio[0]);
                
                var url = overlays[m].getElementsByTagName("href");
                if (url.length > 0) site.href = GXml.value(url[0]);

                var north = overlays[m].getElementsByTagName("north");
                var south = overlays[m].getElementsByTagName("south");
                var east = overlays[m].getElementsByTagName("east");
                var west = overlays[m].getElementsByTagName("west");
                if (north.length > 0 && south.length > 0 && east.length > 0 && west.length > 0 ) {
                    site.north = GXml.value(north[0]);
                    site.south = GXml.value(south[0]);
                    site.east = GXml.value(east[0]);
                    site.west = GXml.value(west[0]);
                } 

                var name = overlays[m].getElementsByTagName("name");
                if ( name.length > 0 ) {
                    site.name = GXml.value(name[0]);
                    if ( ! site.abbreviation ) site.abbreviation = site.name;
                }

                var description = overlays[m].getElementsByTagName("description");
                if ( description.length > 0 ) {
                    site.description = new Array();
                    for ( var n = 0; n < description.length; n++ ) {
                        site.description.push(GXml.value(description[n]));
                    }
                }

                var visibility = overlays[m].getElementsByTagName("visibility");
                if ( visibility.length > 0 ) {
                    site.shown = GXml.value(visibility[0]) == "1";
                } else site.shown = true;
                layer.shown = site.shown;

                var height = overlays[m].getElementsByTagName("height");
                if ( height.length > 0 ) site.height = GXml.value(height[0]);

                var width = overlays[m].getElementsByTagName("width");
                if ( width.length > 0 ) site.width = GXml.value(width[0]);

                var styleurl = overlays[m].getElementsByTagName("styleUrl");
                if ( styleurl.length > 0 ) {
                    site.style = GXml.value(styleurl[0]).substr(1);
                } else {
                    if ( layer.legendIconStyle ) {
                        site.style = layer.legendIconStyle;
                    } else {
                        site.style = 'default';
                    }
                }

                layer.placemarks.push(site);
            }

            layers.push(layer);
            //if ( k == (folders.length-1) ) layers.push(layer);
        }    
    }
    return layers;
}


/***************************
 * GMapWrapper.mapAll()
 * 
 * Plots polygons and markers on the current map.
 ****************************/
GMapWrapper.prototype.mapAll = function() {
    var sites = this.layers[this.curLayer].placemarks;
    var mapobj = this;
    if (this.curItem < sites.length) {
        var lmax = Math.min(this.curItem+this.groupLoadSize,sites.length);
        //this.objMessage.setMessage("Loading "+ lmax +" of " + sites.length);

        while (this.curItem < lmax) {
            var site = sites[this.curItem];
            var style = sites[this.curItem].style;
            if ( this.styles[style] != null ) {
                if ( this.styles[style].normal ) {
                   var normalstyle = this.styles[this.styles[style].normal];
                } else {
                   var normalstyle = this.styles[style];
                }
                if ( this.styles[style].highlight != null) {
                    var highlightstyle = this.styles[this.styles[style].highlight];
                } else {
                    var highlightstyle = normalstyle;
                }
            } else {
                var normalstyle = this.styles['default'];
                var highlightstyle = normalstyle;
            }

            if ( site.type == "tiles" )  {
                var h = new GTileLayer(new GCopyrightCollection(),site.minzoom,site.maxzoom,{isPng:site.isPng});
                h.getTileUrl = site.urlCallback;
                h.getOpacity = site.opacityCallback;
                h.isPng = function () { return site.isPng; }
                this.layers[this.curLayer].type = "tiles";
                this.layers[this.curLayer].overlay = new GTileLayerOverlay(h,{zPriority:site.priority});
                this.layers[this.curLayer].added = this.layers[this.curLayer].shown;
                if ( this.layers[this.curLayer].shown ) {
                    this.objMap.addOverlay(this.layers[this.curLayer].overlay);
                }
            }

            if ( site.type == "image" && this.showImageOverlays && site.showImageOverlays ) {
                this.layers[this.curLayer].type = "image";

                //this.layers[this.curLayer].overlay = new GGroundOverlay(site.href,new GLatLngBounds(new GLatLng(site.south,site.west), new GLatLng(site.north,site.east)));
                //In order to force GGroundOverlay to respect TileOverlay
                //ordering, we use the EInsert ground overlay alternative.
                this.layers[this.curLayer].overlay = EInsert.groundOverlay(site.href,new GLatLngBounds(new GLatLng(site.south,site.west), new GLatLng(site.north,site.east)),site.priority);
               
                if ( this.layers[this.curLayer].shown === true ) {
                    this.layers[this.curLayer].added = true;

                    this.objMap.addOverlay(this.layers[this.curLayer].overlay);
                }
            }

            if ( site.points && site.points.length > 0 ) {
                if ( site.type == "polygon" && this.showPolygons && site.showPolygons ) {
                    this.layers[this.curLayer].type = "polygon";
                    this.layers[this.curLayer].polygons[this.curItem] = new Array();
                    for ( var i = 0; i < site.points.length; i++ ) {
                        this.layers[this.curLayer].polygons[this.curItem][i] = new GPolygon(site.points[i],normalstyle.strokecolor,1,normalstyle.strokeopacity,normalstyle.fillcolor,normalstyle.fillopacity);
                        if ( this.layers[this.curLayer].polygons[this.curItem][i] && this.layers[this.curLayer].shown == true ) {
                            this.layers[this.curLayer].added = true;
                            this.objMap.addOverlay(this.layers[this.curLayer].polygons[this.curItem][i]);
                        }

                                 /*
                    var layers = this.layers;
                    GEvent.addListener( this.objMap, "zoomend" ,function() {
                        var now = (new Date()).getTime();
                        if ( ( mapobj.objMap.getZoom() > 15 ) && ( ( now - mapobj.lastZoomFix ) > 2 ) ) {
                            for ( var i = 0; i < layers.length; i++ ) {
                                 if ( layers[i].polygon[i] ) {
                                     layers[i].polygon.hide();
                                     layers[i].polygon.show();
                                 }
                            }
                            mapobj.lastZoomFix = now;
                        }
                    });
                                 */
                        if ( site.description && site.description != "" ) {
                            this.layers[this.curLayer].polygons[this.curItem][i].iw = new Array();
                            for ( var j = 0; j < site.description.length; j++ ){
                                this.layers[this.curLayer].polygons[this.curItem][i].iw[j] = new GInfoWindowTab(site.iwlabel[j],site.description[j]);
                            }
                            GEvent.addListener( this.layers[this.curLayer].polygons[this.curItem][i], "click" ,function(latlng) {
                                mapobj.onPolygonClick(this,latlng,site.points[i]);
                            });
                        }
                    }
                }
                if ( site.type == "polyline" && this.showPolyLines && site.showPolyLines ) {
                    this.layers[this.curLayer].type = "polyline";
                    this.layers[this.curLayer].placemarks[this.curItem].pls = [];
                    var pl = this.layers[this.curLayer].polylines.length-1;
                    for ( var i = 0; i < site.points.length; i++ ) {
                        this.layers[this.curLayer].polylines.push(new GPolyline(site.points[i],normalstyle.strokecolor,normalstyle.strokewidth,normalstyle.strokeopacity));
                        this.layers[this.curLayer].added = false;
                        if ( this.layers[this.curLayer].polylines ) {
                            pl += 1;
                            this.layers[this.curLayer].polylines[pl].label=site.abbreviation;
                            this.layers[this.curLayer].placemarks[this.curItem].pls.push(this.layers[this.curLayer].polylines[pl]);

                            if ( site.description && site.description != "" ) {
                                this.layers[this.curLayer].polylines[pl].iw = new Array();
                                for ( var j = 0; j < site.description.length; j++ ){
                                    this.layers[this.curLayer].polylines[pl].iw[j] = new GInfoWindowTab(site.iwlabel[j],site.description[j]);
                                }
                            }
 
                            if ( this.layers[this.curLayer].shown ) {
                                this.layers[this.curLayer].added = true;
                                this.objMap.addOverlay(this.layers[this.curLayer].polylines[pl]);
                                GEvent.addListener( this.layers[this.curLayer].polylines[pl], "click" ,function(latlng) {
                                    mapobj.onPolylineClick(this,latlng);
                                });
                            }
                        }
                    }
                    var layers = this.layers;
                    GEvent.addListener( this.objMap, "zoomend" ,function() {
                        var now = (new Date()).getTime();
                        if ( ( mapobj.objMap.getZoom() > 15 ) && ( ( now - mapobj.lastZoomFix ) > 2 ) ) {
                            for ( var i = 0; i < layers.length; i++ ) {
                                 for ( var j = 0; j < layers[i].polylines.length; j++ ) {
                                     mapobj.objMap.removeOverlay(layers[i].polylines[j]);
                                     mapobj.objMap.addOverlay(layers[i].polylines[j]);
                                     layers[i].polylines[j].added = true;
                                 }
                            }
                            mapobj.lastZoomFix = now;
                        }
                    });
                }
                
             }

            if ( site.textanchor) {
                if ( site.showlabel ) {
                    /*
                    var label = new TLabel();
                    label.anchorLatLng = site.textanchor;
                    label.anchorPoint = "bottomLeft";
                    label.content = '<div class="glabel">' + site.name + '</div>';
                    this.objMap.addTLabel(label);
                    */
                    var label = new ELabel(site.textanchor,site.name,"glabel");
                    this.objMap.addOverlay(label);
                }
            }

            var marker = null;
            if ( this.showMarkers && site.showMarkers && ((site.loc != null) || site.showcenter ) ) {
                this.layers[this.curLayer].type = "marker";
                if ( this.enableMarkerDrag ) {
                    var moptions = {draggable:true, icon:normalstyle.icon, bouncy: false, title: site.name };
                } else {
                    var moptions = {draggable:false, icon:normalstyle.icon, title: site.name };
                }
                if ( site.loc ) {
                    marker = new GMarker(site.loc, moptions);
                    marker.loc = site.loc;
                } else {
                    marker = new GMarker(site.center, moptions);
                    marker.loc = site.center;
                }

                if ( marker ) {
                    marker.fullname = site.name;
                    marker.layername = this.layers[this.curLayer].abbreviation;
                    marker.zoom = site.zoom;
                    marker.abbreviation = site.abbreviation;
                    marker.normalStyle = normalstyle;
                    marker.highlightStyle = highlightstyle;

                    if ( this.showTour ) {
                        if ( this.curItem > 0 ) {
                            marker.prev = sites[this.curItem-1].abbreviation;
                            prevstyle = "link";
                        } else {
                            marker.prev = null
                            prevstyle = "nolink";
                        }

                        if ( this.curItem < (sites.length-1) ) {
                            marker.next = sites[this.curItem+1].abbreviation;
                            nextstyle = "link";
                        } else {
                            marker.next = null
                            nextstyle = "nolink";
                        }
                    }

                    if ( this.showInfoBlock ) {
                        marker.iw = site.description[0];
                    } else {
                        marker.iw = new Array();
                        
                        if ( site.description ) {
                            for ( var j = 0; j < site.description.length; j++ ){
                                if ( site.iwlabel  && site.iwlabel.length > j ) {
                                    var iwlabel = site.iwlabel[j];
                                } else {
                                    var iwlabel = "";
                                }
                                var pre = "";
                                var nav = "";
                                if ( this.showTour ) {
                                    pre = "<div style='height: 175px; width: 200px;'>";
                                    nav = "<div style='width: 200px;' class='navrow'>" + 
                                          "<a class='prev " + prevstyle + "' name='prev'>" + 
                                          "&lt;&nbsp;Prev</a>" + "&nbsp;&nbsp;" +
                                          "<a class='next " + nextstyle +"' name='next'>" + 
                                          "Next&nbsp;&gt;</a>" + 
                                          "</div></div>";
                                }
                                marker.iw[j] = new GInfoWindowTab(iwlabel,pre + site.description[j] + nav);
                            }
                        }
                    }

                    this.layers[this.curLayer].markers[this.curItem] = marker;
                    if ( this.useMarkerManager ) {
                        this.layers[this.curLayer].mm.addMarker(this.layers[this.curLayer].markers[this.curItem],2);
                        if ( ! this.layers[this.curLayer].shown ) {
                            this.layers[this.curLayer].markers[this.curItem].hide();
                        }
                    } else {
                        if ( this.layers[this.curLayer].shown ) {
                            this.objMap.addOverlay(this.layers[this.curLayer].markers[this.curItem]);
                        }
                    }


                    if (this.enableMarkerDrag ) {
                         marker.enableDragging();
                         GEvent.addListener(this.layers[this.curLayer].markers[this.curItem],"dragstart",function () {
                            if ( this.connector ) {
                                mapobj.objMap.removeOverlay(this.connector);
                            }
                            if ( mapobj.iw ) {
                                mapobj.iwWasOpen = true;
                                mapobj.objMap.closeInfoWindow();
                             } else {
                                mapobj.iwWasOpen = false;
                            }

                        } );
                        
                        GEvent.addListener(this.layers[this.curLayer].markers[this.curItem],"dragend",function () {
                            var oldloc = this.loc;
                            var newloc = this.getPoint();
                            var oldp = mapobj.objMap.fromLatLngToDivPixel(oldloc);
                            var newp = mapobj.objMap.fromLatLngToDivPixel(newloc);

                            var x = Math.abs(oldp.x - newp.x);
                            var y = Math.abs(oldp.y - newp.y);
                            var d = Math.sqrt((x*x)+(y*y));

                            if ( d > 20 ) {
                                this.connector = new GPolyline(new Array(oldloc,newloc),"#FFFFFF",2,0.8);
                                mapobj.objMap.addOverlay(this.connector);
                            } else {
                                this.setPoint(this.loc);
                            }

                            if ( mapobj.iwWasOpen ) {
                                mapobj.onMarkerClick(this);
                            }

                        } );

                    }

                    if ( (this.showInfoWindow || this.showInfoBlock) && site.description ) {
                        GEvent.addListener(this.layers[this.curLayer].markers[this.curItem],"click",function (latlng) {
                            if ( this.recenterOnSiteSelect ) {
                                mapobj.objMap.panTo(this.getPoint());
                            }
                            mapobj.selectSite(this.abbreviation);
                            mapobj.iw = true;
                            var iw = mapobj.objMap.getInfoWindow();
 
                            mapobj.onMarkerClick(this,true);
                        } );

                        GEvent.addListener(this.layers[this.curLayer].markers[this.curItem],"infowindowclose",function () {
                            var now = (new Date()).getTime();
                            if ( Math.abs(now - mapobj.lastopened) > 5000 ) { 
                                mapobj.deselectSite(this.abbreviation);
                            }

                            mapobj.iw = false;
                            mapobj.iwlayer = null;
                            mapobj.iwmarker = null;
                        } );
                    }
                }
            }            
 
            this.curItem++;
        }
    } else {
    }
}


/***************************
 * GMapWrapper.travelToSite()
 * 
 * Travels smoothly to the specified site. Opens
 * an infowindow if enabled and an infowindow was already
 * openned by the user.
 ****************************/
GMapWrapper.prototype.travelToSite = function(sitename) {
    if ( sitename == -1 ) {
        return;
    }

    this.traveling = true; 
    marker = this.getMarkerForSite(sitename);
    if ( this.showInfoBlock ) {
        var mapinfo = document.getElementById("mapinfoblock");
        mapinfo.innerHTML = marker.iw;
        if (this.notifyOnMarkerChange) {
            fadeBlink(mapinfo,10,100,100,0);
        }
    } 

    iw = this.objMap.getInfoWindow();
    if ( (! iw.isHidden()) && (this.showInfoWindow||this.showInfoBlock)) {
        this.onMarkerClick(marker);
    }

    this.objMap.panTo(marker.getPoint());
    this.selectSite(sitename);
    this.traveling = false;
}

/***************************
 * GMapWrapper.selectSite()
 * 
 * Highlights the named site in the sidebar and makes an internal
 * note that the named site has been selected. Also updates the
 * bookmark url.
 ****************************/
GMapWrapper.prototype.selectSite = function(sitename) {
    if ( this.lastsite ) {
        var lastsite_el = document.getElementById("label_" + this.lastsite);
        lastsite_el.style.fontWeight = "normal";
        lastsite_el.style.fontStyle = "normal";
    }

    var newsite = document.getElementById("label_" + sitename);
    if ( newsite ) {
        newsite.style.fontWeight = "bold";
        newsite.style.fontStyle = "italic";
        this.lastsite = sitename;
    }
}

/***************************
 * GMapWrapper.deselectSite()
 * 
 * Deselects the given site by removing highlighting on sidebar
 * text and marking the site as not selected.
 ****************************/
GMapWrapper.prototype.deselectSite = function() {
    if ( this.lastsite ) {
        var lastsite_el = document.getElementById("label_" + this.lastsite);
        lastsite_el.style.fontWeight = "normal";
        lastsite_el.style.fontStyle = "normal";
    }
    this.lastsite = null;
}

/***************************
 * GMapWrapper.g_writeLinkHere()
 * 
 * Reloads the page with a new url appropriate to the current state
 * of the map.
 ****************************/
GMapWrapper.prototype.g_writeLinkHere = function() {
    if ( ! this.objMap ) {
        location.href=location.href;
    } else {
        var state = this.saveState();
        var layerstr = "";
        
        if ( state && state.layers ) {
            for ( name in state.layers ) {
                if ( state.layers[name] == false ) {
                    layerstr += name + ":false;";
                } else {
                    layerstr += name + ":true;";
                }
            }
        }
        this.newurl = "?";
        if ( state.iwmarker ) this.newurl += "&aSiteName=" + state.iwmarker;
        if ( state.iwlayer ) this.newurl +=  "&aActiveLayer=" + state.iwlayer;  
        if ( state.iwtab ) this.newurl += "&aCurrentTab=" + state.iwtab;
        if ( layerstr ) this.newurl += "&aLayersShown=" + layerstr;
        if ( state.zoom ) this.newurl += "&zoom=" + state.zoom;
        if ( state.lat ) this.newurl += "&lat=" + state.lat;
        if ( state.lon ) this.newurl += "&lon=" + state.lon;
        if ( state.maptype ) this.newurl += "&maptype=" + state.maptype.getUrlArg();
    }

    location.href = this.newurl;
}

function mapArgToMapType(maparg) {
    var maptype = null;
    if ( maparg == "m" ) maptype = G_NORMAL_MAP;
    if ( maparg == "k" ) maptype = G_SATELLITE_MAP;
    if ( maparg == "h" ) maptype = G_HYBRID_MAP;
    if ( maparg == "p" ) maptype = G_PHYSICAL_MAP;
    return maptype;
}

/***************************
 * GMapWrapper.g_writeLinkHere()
 * 
 * Reloads the page with a new url appropriate to the current state
 * of the map.
 ****************************/
GMapWrapper.prototype.mergeStateFromArgs = function() {
    var state = new Object();

    if ( this.defaultState ) {
        state.iwtab = this.defaultState.iwtab;
        state.iwlayer = this.defaultState.iwlayer;
        state.iwmarker = this.defaultState.iwmarker;
        state.lat = this.defaultState.lat;
        state.lon = this.defaultState.lon;
        state.zoom = this.defaultState.zoom;
        state.maptype = this.defaultState.maptype;
        state.layers = this.defaultState.layers;

    }


    var fv = getFormValue("aCurrentTab");
    if ( fv ) state.iwtab = fv;

    var fv = getFormValue("aSiteName");
    if ( fv ) state.iwmarker = fv;

    var fv = getFormValue("aActiveLayer");
    if ( fv ) state.iwlayer = fv;

    var layerstr = getFormValue("aLayersShown");

    if ( layerstr ) {
        state.layers = new Array();
        layerstr = layerstr.split(";");
        for ( var i = 0; i < layerstr.length; i++ ) {
            layerstr[i] = layerstr[i].split(":");
            if ( layerstr[i][1] == "true" ) {
                state.layers[unescape(layerstr[i][0])] = true;
            } else {
                state.layers[unescape(layerstr[i][0])] = false;
            }
        }
    }
    var fv = getFormValue("zoom");
    if ( fv ) state.zoom = fv;

    var fv = getFormValue("lat");
    if ( fv ) state.lat = fv;

    var fv = getFormValue("lon");
    if ( fv ) state.lon = fv;

    var mt = getFormValue("maptype");
    state.maptype = mapArgToMapType(mt);

    if ( state.iwtab ) state.iwtab = urldecode(state.iwtab);
    if ( state.iwlayer ) state.iwlayer = urldecode(state.iwlayer);
    if ( state.iwmarker ) state.iwmarker = urldecode(state.iwmarker);

    return state;
}

GMapWrapper.prototype.layerIsShown = function(l) {
  var shown = false;
  for ( var i = 0; i < this.layers[l].children.length; i++ ) {
     if ( ! this.layerIsShown(this.layers[l].children[i]) )
         return false;
  }
  return this.layers[l].shown;
/*
  for ( var i = 0; i < this.shownLayers.length; i++ ) {
      if ( this.shownLayers[i] == l ) {
          shown = true;
      }
  }
*/
  return shown;
}


/***************************
 * GMapWrapper.addCompass()
 * 
 * Creates a compass to use as a screen overlay.
 ****************************/
GMapWrapper.prototype.addCompass = function() {
    if ( ! this.mapcont ) this.mapcont = document.getElementById(this.mapid);
    if ( this.compassLeftOffset ) {
        var x = this.compassLeftOffset;
    }
    if ( this.compassTopOffset ) {
        var y = this.mapcont.clientHeight - this.compassTopOffset;
    }
    if ( this.compassRightOffset ) {
        var x = this.mapcont.clientWidth - this.compassRightOffset;
    }
    if ( this.compassBottomOffset ) {
        var y = this.compassBottomOffset;
    }

    if ( ! this.mapcont ) this.mapcont = document.getElementById(this.mapid);
    var compass_size = new GScreenSize(0,0);
    var screenloc  = new GScreenPoint(x,y);
    var imageloc = new GScreenPoint(0,0);
    this.compass = new GScreenOverlay("/images/mapicons/compass.png",screenloc,imageloc,compass_size);
    this.objMap.addOverlay(this.compass);

    objmap = this;
    GEvent.addDomListener(window,'resize',function() {
        objmap.objMap.removeOverlay(objmap.compass);
        objmap.addCompass();
    });

}

/***************************
 * GMapWrapper.toggleShowLayer()
 * 
 * Toggles the indicated marker layer visibility.
 ****************************/
GMapWrapper.prototype.toggleShowLayer = function(event) {
  if ( typeof(event) != 'object' ) {
      var l = event;
  } else {
      if ( !event ) event = window.event;
      var target = (event.target) ? event.target : event.srcElement; 
      var l = Number(target.id.replace(/^layer_(.*)$/,"$1"));
  }

  if ( ! this.layers ) {
     //alert("shownLayer is broken!");
  }
  if ( this.layerIsShown(l) ) {
      this.hideLayer(l);
  } else {
      this.showLayer(l);
  }
}

GMapWrapper.prototype.addLegend = function(legend) {
    this.legend = legend;
    if ( this.allowMovingLegend ) {
        this.mbl.addBlock("MapLegend");
    }
}

GMapWrapper.prototype.openOnFirstLoad = function(layername,markername,tabnumber) {
    this.firstLayer = layername;
    this.firstMarker = markername;
    this.firstTab = tabnumber;
}

/***************************
 * GMapWrapper.getLayerWithLabel()
 * 
 * Returns the layer number corresponding to the provided label.
 ****************************/
GMapWrapper.prototype.getLayerWithLabel = function(label) {
    if ( ! this.layers ) return;
    for ( var i = 0; i < this.layers.length; i++ ) {
        if (this.layers[i].abbreviation == label) {
            return i;
        }
    }
    return null;
}


/***************************
 * GMapWrapper.addTileLayer()
 * 
 * Toggles the indicated marker layer visibility.
 ****************************/
GMapWrapper.prototype.addTileLayer = function(urlCallback,opacityCallback,label,minzoom,maxzoom,priority,isPng,iconstyle,shown) {
    var tilelayer = new Array();
    tilelayer['url'] = urlCallback;
    tilelayer['label'] = label;
    tilelayer['minzoom'] = minzoom;
    tilelayer['maxzoom'] = maxzoom;
    tilelayer['opacity'] = opacityCallback;
    tilelayer['isPng'] = isPng;
    tilelayer['priority'] = priority;
    tilelayer['shown'] = shown;
    tilelayer['iconStyle'] = iconstyle;
    this.tilelayers.push(tilelayer);     
}

GMapWrapper.prototype.addIconStyle = function(stylename,uri,ih,iw,listtype) {
    if ( this.styles[stylename] == null ) {
        this.styles[stylename] = new Object();
    }
    this.styles[stylename].listtype = listtype;
    this.styles[stylename].icon = new GIcon(); 
    this.styles[stylename].icon.image = uri;
    this.styles[stylename].icon.iconSize = new GSize(iw,ih);
    this.styles[stylename].icon.iconAnchor = new GPoint(iw/2,ih/2);
    this.styles[stylename].icon.infoWindowAnchor = new GPoint(iw/2,ih/2);
}

GMapWrapper.prototype.setMessage = function(str,fade) {
    if ( fade == null ) fade = true;
    var msg = document.getElementById("message");
    var parent = document.getElementById(this.mapid);
    if ( ! msg ) {
        msg = document.createElement("div");
        msg.id = "message";
        parent.appendChild(msg);
    }
    msg.innerHTML = str;
    msg.style.display="block";
    msg.style.opacity = "1.0";
    msg.style.left = ((parent.offsetWidth - msg.offsetWidth)/2) + "px";
    msg.style.top = ((parent.offsetHeight - msg.offsetHeight) / 2) + "px";
    if ( fade ) {
        msg.style.display = "block";
        fadeAway(msg,3000,10,100,100);
    }
}

function findNodeWithLabel(rootnode,label) {
    var found = null;
    if ( rootnode.name == label ) return rootnode;
    for ( var i = 0; i < rootnode.descendents.length; i++ ) {
        found = findNodeWithLabel(rootnode.descendents[i],label);
        if ( found != null ) return found;
    }
    return found;
}



// ]]>
