     
  var tooltip;
  var toolTipText;
  var polys = [];
  
  function getElementsByClassName(classname, node) 
  {
		if(!node) node = document.getElementsByTagName("body")[0];
	
	  var a = [];
	  var re = new RegExp('\\b' + classname + '\\b');
	  var els = node.getElementsByTagName("div");
	  for(var i=0,j=els.length; i<j; i++)
		  {
	  	if(re.test(els[i].className))
				{
			  	if( els[i].id == 'map_continental_overview' )
				  	a.push(els[i]);
				}
	  	}
	  return a;
	}
	
  function positionOverview() 
	{
	  var elems = getElementsByClassName( 'gmnoprint', document.getElementById("map_continental") );
	  if( elems.length == 0 )
	    setTimeout("positionOverview()",1);
	  else
	  {
		  elems[0].style.position = 'absolute';
		  elems[0].style.left = 0+'px';
		  elems[0].style.top  = 0+'px';
		  
		  //elems[1].style.left = 0+'px';
		  //elems[1].style.top  = 200+'px';
		}
	}
	
  function hideDiv()
  {
    tooltip.style.visibility = 'hidden';
  }
  
  // the sections of the map for searching optimized speed 0=lat, 1=lng, (01)=topLeft, (23)=bottomRight
  // values are latlng for the gmap
  var boxes = new Array(4);
  for( i=0; i<4; i++ ) 
  { 
    boxes[i] = new Array(4); 
  }
  boxes[0][0] = 49.781264058178344; 
  boxes[0][1] = -128.3203125; 
  boxes[0][2] = 31.12819929911196; 
  boxes[0][3] = -106.875;
  
  boxes[1][0] = 49.781264058178344; 
  boxes[1][1] = -106.875; 
  boxes[1][2] = 29.53522956294847; 
  boxes[1][3] = -88.681640625;
  
  boxes[2][0] = 49.781264058178344; 
  boxes[2][1] = -88.681640625; 
  boxes[2][2] = 37.64903402157866; 
  boxes[2][3] = -65.91796875;
  
  boxes[3][0] = 37.64903402157866;  
  boxes[3][1] = -88.681640625;  
  boxes[3][2] = 37.64903402157866; 
  boxes[3][3] = -71.103515625;
  
  /******continental*******
  *      *      *   2     *
  *  0   *  1   *---------*         
  *      *      *   3     *
  ************************/
  function getBox( point )
  { 
    // hawaii and alaska
    if( point.lng() <= -129.0234375)
      return -1;
    else if( point.lng() <= boxes[0][3])
      return 0;
    else if( point.lng() >= boxes[0][3] && point.lng() <= boxes[1][3] )
      return 1;
    else if( point.lat() >= boxes[2][2] )
      return 2;          
    else
      return 3;
  }
  
  function getColor( value )
  {
    if( value <= 5 )
      return '#BAFFFF';
    else if( value <= 10 )
      return '#88CEFF';
    else if( value <= 15 )
      return '#009CCE';
    else if( value <= 20 )
      return '#17679A';
    else if( value <= 25 )
      return '#5697FF';
    else if( value <= 30 )
      return '#255FFF';
    else if( value <= 35 )
      return '#0525CF';
    else if( value <= 40 )
      return '#002D9B';
    else if( value <= 45 )
      return '#003267';
    else if( value > 45 )
      return '#070034';
    else
      return '#BAFFFF';        
  }
  
  // not implementing a timer yet
  function timedDisplay( map, point, elem )
  {
    var inside = false;
    var searchablePolys = [];
    var box = getBox(point);
    switch(box)
    {
      case -1:
        searchablePolys.push( polys[1] );
        searchablePolys.push( polys[11] );
        break;
      case 0:
        searchablePolys.push( polys[2] );
        searchablePolys.push( polys[4] );
        searchablePolys.push( polys[5] );
        searchablePolys.push( polys[12] );
        searchablePolys.push( polys[26] );
        searchablePolys.push( polys[28] );
        searchablePolys.push( polys[31] );
        searchablePolys.push( polys[37] );
        searchablePolys.push( polys[44] );
        searchablePolys.push( polys[47] );
        
        searchablePolys.push( polys[50] );
        break;
      case 1:
        searchablePolys.push( polys[3] );
        searchablePolys.push( polys[5] );
        searchablePolys.push( polys[13] );
        searchablePolys.push( polys[15] );
        searchablePolys.push( polys[16] );
        searchablePolys.push( polys[17] );
        searchablePolys.push( polys[18] );
        searchablePolys.push( polys[22] );
        searchablePolys.push( polys[23] );
        searchablePolys.push( polys[24] );
        
        searchablePolys.push( polys[25] );
        searchablePolys.push( polys[26] );
        searchablePolys.push( polys[27] );
        searchablePolys.push( polys[31] );
        searchablePolys.push( polys[34] );
        searchablePolys.push( polys[36] );
        searchablePolys.push( polys[41] );
        searchablePolys.push( polys[42] );
        searchablePolys.push( polys[43] );
        searchablePolys.push( polys[49] );
        
        searchablePolys.push( polys[50] );
        break;
      case 2:
        searchablePolys.push( polys[6] );
        searchablePolys.push( polys[7] );
        searchablePolys.push( polys[8] );
        searchablePolys.push( polys[13] );
        searchablePolys.push( polys[14] );
        searchablePolys.push( polys[17] );
        searchablePolys.push( polys[19] );
        searchablePolys.push( polys[20] );
        searchablePolys.push( polys[21] );
        searchablePolys.push( polys[22] );
        searchablePolys.push( polys[29] );
        
        searchablePolys.push( polys[30] );
        searchablePolys.push( polys[32] );
        searchablePolys.push( polys[35] );
        searchablePolys.push( polys[38] );
        searchablePolys.push( polys[39] );
        searchablePolys.push( polys[42] );
        searchablePolys.push( polys[45] );
        searchablePolys.push( polys[46] );
        searchablePolys.push( polys[48] );
        searchablePolys.push( polys[49] );
        break;
      case 3:
        searchablePolys.push( polys[0] );
        searchablePolys.push( polys[9] );
        searchablePolys.push( polys[10] );
        searchablePolys.push( polys[17] );
        searchablePolys.push( polys[24] );
        searchablePolys.push( polys[33] );
        searchablePolys.push( polys[40] );
        searchablePolys.push( polys[42] );
        searchablePolys.push( polys[46] );
        break;
      default:
        break;
    }
    
    for( var i=0; i<searchablePolys.length; i++ ) 
    {
      if ( searchablePolys[i].Contains( point ) ) 
      {
        showTooltip( map, searchablePolys[i], elem );
        inside = true;
        break;
      }
    }
    if(!inside)
    {
      hideDiv();   
    }
  }
   
  // ====== This function displays the tooltip ======
  function showTooltip(map, p, elem) 
  {
    toolTipText.innerHTML = p.marker.toolTipText;
    var point  = map.getCurrentMapType().getProjection().fromLatLngToPixel(map.fromDivPixelToLatLng(new GPoint(0,0),true),map.getZoom());
    var offset = map.getCurrentMapType().getProjection().fromLatLngToPixel(p.marker.getPoint(),map.getZoom());
    var anchor = p.marker.getIcon().iconAnchor;
    var width  = p.marker.getIcon().iconSize.width;
    var height = toolTipText.clientHeight;
    var parentX = document.getElementById('wrapper').offsetLeft;
    var parentY = document.getElementById(elem).offsetTop;
    if( elem == 'map_continental' )
      parentX += document.getElementById('map_alaska').offsetWidth;
    
    var pos     = new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(offset.x - point.x + parentX + 4, offset.y - point.y + parentY - height)); 
    pos.apply(tooltip);
    tooltip.style.display="block";
    tooltip.style.visibility="visible";
  }
  
  function loadMap(){ 
    if (GBrowserIsCompatible()) {

      // === A method for testing if a point is inside a polygon
      // === Returns true if poly contains point
      // === Algorithm shamelessly stolen from http://alienryderflex.com/polygon/ 
      GPolygon.prototype.Contains = function(point) {
        var j=0;
        var oddNodes = false;
        var x = point.lng();
        var y = point.lat();
        
        // first check to see if it's even potentially inside this state -- dcuccias
        if( this.getBounds().containsLatLng( point ) )
        {       
          for (var i=0; i < this.getVertexCount(); i++) {
            j++;
            if (j == this.getVertexCount()) {j = 0;}
            if (((this.getVertex(i).lat() < y) && (this.getVertex(j).lat() >= y))
            || ((this.getVertex(j).lat() < y) && (this.getVertex(i).lat() >= y))) {
          	  if ( this.getVertex(i).lng() + (y - this.getVertex(i).lat())
                /  (this.getVertex(j).lat()-this.getVertex(i).lat())
                *  (this.getVertex(j).lng() - this.getVertex(i).lng())<x ) {
                oddNodes = !oddNodes
              }
            }
          }
        }
        return oddNodes;
      }

      // make maps 
      var map = new GMap2(document.getElementById("map_continental"));   
      var mapA = new GMap2(document.getElementById("map_alaska"));
      var mapH = new GMap2(document.getElementById("map_hawaii"));
      
      // create the floating div - don't use infoWindow because it pans the map and we want it to be static
      tooltip = document.createElement("div");
      window.document.getElementsByTagName('body')[0].appendChild(tooltip);
      tooltip.style.visibility="hidden";
      tooltip.style.display="none";
		  tooltip.style.color= "black";
		  tooltip.style.border = '2px solid #c0c1cc';
		  tooltip.style.zIndex = 2000;
      toolTipText = document.createElement("div");
      toolTipText.style.backgroundColor= "white";
      toolTipText.style.padding = 10 + 'px';
      //toolTipText.style.marginLeft = 15 + 'px';
      //var arrow = document.createElement("div");
      //arrow.style.backgroundImage="url(../images/maps/maps-speechbubble.png)";
      //arrow.style.height = 60 + 'px';
      //arrow.style.width = 30 + 'px';
      tooltip.appendChild(toolTipText);
      //tooltip.appendChild(arrow);
      
      // put the screen overlayTiles
      var copyright = new GCopyright(1,
      new GLatLngBounds(new GLatLng(33.212,-87.541),new GLatLng(33.212,-86.541) ),0, "");
          
      // ============================================================
      // ====== Create a copyright collection and add the copyright to it =====
      var copyrightCollection = new GCopyrightCollection('Map Data:');
      copyrightCollection.addCopyright(copyright);
      
      CustomGetTileUrl=function(a,b){
        //return "images/maps/"+a.x+"_"+a.y+".gif"; -- solution for custom map of US based on a.x and a.y
        return "images/maps/black.gif";
      }
      
      var tilelayers = [new GTileLayer(copyrightCollection,2,5)];
      tilelayers[0].getTileUrl = CustomGetTileUrl;
      
      // add the custom black background to the maps
      var custommap = new GMapType(tilelayers, new GMercatorProjection(18), "", {maxResolution:4, minResolution:4});
      var custommapA = new GMapType(tilelayers, new GMercatorProjection(18), "", {maxResolution:2, minResolution:2});
      var custommapH = new GMapType(tilelayers, new GMercatorProjection(18), "", {maxResolution:5, minResolution:5});
      map.addMapType(custommap);
      map.setCenter(new GLatLng(39.10296, -90.12109375),4, custommap);
      mapA.addMapType(custommapA);
      mapA.setCenter(new GLatLng(62.890301, -156.054077),2, custommapA);
      mapH.addMapType(custommapH);
      mapH.setCenter(new GLatLng(20.48737, -157.250534),5, custommapH);
      
      // customization
      map.disableScrollWheelZoom();
      map.disablePinchToZoom();
      map.disableDoubleClickZoom();
      map.removeMapType( G_SATELLITE_MAP );
      map.removeMapType( G_HYBRID_MAP );
      map.disableDragging();
      
      mapA.disableScrollWheelZoom();
      mapA.disablePinchToZoom();
      mapA.disableDoubleClickZoom();
      mapA.removeMapType( G_SATELLITE_MAP );
      mapA.removeMapType( G_HYBRID_MAP );
      mapA.disableDragging();
      
      mapH.disableScrollWheelZoom();
      mapH.disablePinchToZoom();
      mapH.disableDoubleClickZoom();
      mapH.removeMapType( G_SATELLITE_MAP );
      mapH.removeMapType( G_HYBRID_MAP );
      mapH.disableDragging();
              
      GEvent.addListener(map, "mousemove", function(point) {
        timedDisplay(map, point, 'map_continental' );
      });
      
      GEvent.addListener(mapA, "mousemove", function(point) {
        timedDisplay(mapA, point, 'map_alaska' );
      });

      GEvent.addListener(mapH, "mousemove", function(point) {
        timedDisplay(mapH, point, 'map_hawaii' );
      });
      
      // Read the data from states.xml
      var request = GXmlHttp.create();
      request.open("GET", "../xml/states.xml", true);
      request.onreadystatechange = function() {
        if (request.readyState == 4) {
          var xmlDoc = GXml.parse(request.responseText);
          
          // ========= Now process the polylines ===========
          var states = xmlDoc.documentElement.getElementsByTagName("state");

          // read each line
          for (var a = 0; a < states.length; a++) {
            // get any state attributes
            var label  = states[a].getAttribute("name");
            st = statesArray[a];
            var abbr   = st.abbr;
            var numOfEvents   = st.numOfEvents;
            var att   = ( st.att != '0' ) ? st.att : '';
            var colour = states[a].getAttribute("colour");
            var markerPoint = states[a].getAttribute("markerPoint");
            
            // read each point on that line
            var points = states[a].getElementsByTagName("point");
            var pts = [];
            for (var i = 0; i < points.length; i++) {
               pts[i] = new GLatLng(parseFloat(points[i].getAttribute("lat")),
                                   parseFloat(points[i].getAttribute("lng")));
            }
            var color = getColor(numOfEvents);
            var poly = new GPolygon(pts,"#c0c1cc",1,1, color ,1);      
            
            var icon = new GIcon();
            icon.image = "../images/maps/icon.bmp";
            icon.shadow = "../images/maps/icon.bmp";
            icon.iconSize = new GSize(0, 0);
            icon.shadowSize = new GSize(0, 0);
            icon.iconAnchor = new GPoint(0, 0);
            icon.infoWindowAnchor = new GPoint(0, 0);
            icon.infoShadowAnchor = new GPoint(0, 0);
            icon.transparent = "../images/maps/icon.bmp";
            icon.printImage = "../images/maps/icon.bmp";
            icon.mozPrintImage = "../images/maps/icon.bmp";
            
            // split up comma delimited marker
            var index  = markerPoint.indexOf(',', 0);
            var first  = parseFloat( markerPoint.substring(0, index ) );
            var second = parseFloat( markerPoint.substring( index + 2, markerPoint.length ) );
            var marker = new GMarker( new GLatLng( first, second ), icon );
            var attendanceText = (att>0) ? 'Attendance: ' + att : '';
            marker.toolTipText = "<div class='tooltip'>" + label + "<br>Number of Events: " + numOfEvents +" <br>" + attendanceText +"</div>";
            
            poly.marker = marker;
            
            // alaska & hawaii
            if( label != "Alaska" && label != "Hawaii" ) {
              map.addOverlay(poly);              
              map.addOverlay(marker);
            }
            if( label == "Alaska" ) {
              mapA.addOverlay(poly);    
              mapA.addOverlay(marker);
            }
            if( label == "Hawaii" ) {
              mapH.addOverlay(poly);           
              mapH.addOverlay(marker);
            }
               
            polys.push(poly);
          }
          
          
          // ================================================           
        }
      }
            
      request.send(null);
    }
    
    // display a warning if the browser was not compatible
    else {
      alert("Sorry, the Google Maps API is not compatible with this browser");
    }    
    
  }
      