/*
 * GMapEZ -- Turn specially-marked HTML into Google Maps
 * Copyright (C) July 2005 - Oct 2006 by Chris Houser <chouser@n01se.net>
 *
 * This code is licensed under the GNU General Public License (GPL)
 *
 * If you use this code on a web page, please include on that page a
 * link to http://n01se.net/gmapez/ -- this is a request, not
 * a requirement.  Thanks.
 */

(function(){
  var startdate = new Date();

  // configuration -- if you're using your own copy of gmapez.js, you
  // may want to modify these:
  var overlaysPerStep = 25;
  var imgBase = 'http://gmapez.googlepages.com/';
  var upperImgBase = 'http://gmapez.upper.googlepages.com/';
  var shadowServer = 'http://n01se.net/shadow.cgi?src=';

  if( window.ez_preload ) {
    // we're already loaded
    return;
  }

  var _lastId = 0;
  function newId() {
    return 'ez_' + (++_lastId);
  }

  function loadfunc() {
    if( ! GBrowserIsCompatible() ) {
 if( document.getElementsByTagName ) {
   // Find all divs marked as GMapEZ
   var divs = document.getElementsByTagName( 'div' );
   for( var i = 0; i < divs.length; ++i ) {
     var div = divs[ i ];
     if( div.className.indexOf( 'GMapEZ' ) > -1 ) {
  div.innerHTML =  [
    "<div>This map cannot be displayed.  The site's key may be ",
    "incorrect, or your browser may not compatible (see if ",
    "your browser is listed ",
    '<a href="http://maps.google.com/support/bin/answer.py?answer=16532">here</a>).</div>',
    '<div class="firefoxref"><iframe src="http://pagead2.googlesyndication.com/cpa/ads?client=ca-pub-1237864095616304&amp;cpa_choice=CAAQyaj8zwEaCIwcWMzeycafKMu293M&amp;oe=UTF-8&amp;dt=1148266564041&amp;lmt=1148266562&amp;format=180x60_as_rimg&amp;output=html&amp;region=_google_cpa_region_&amp;cc=100&amp;u_h=1024&amp;u_w=1280&amp;u_ah=1050&amp;u_aw=1400&amp;u_cd=24&amp;u_tz=-240&amp;u_his=1&amp;u_java=true&amp;u_nplug=11&amp;u_nmime=133" marginwidth="0" marginheight="0" vspace="0" hspace="0" allowtransparency="true" frameborder="0" height="60" scrolling="no" width="180"></iframe></div>'
    ].join('\n');
  div.style.visibility = 'visible';
  div.style.padding = '0.3em';
  div.style.background = '#eee';
  div.style.overflow = 'auto';
     }
   }
 }
 else {
   alert( [
     'Your browser is not capable of displaying',
     'Google Maps on this page. Try using Firefox:',
     'http://getfirefox.com/' ].join('\n') );
 }
 return;
    }

    addOnUnload( GUnload );

    function getTotalOffset( elem ) {
 point = new GPoint( 0, 0 );
 while( elem ) {
   point.x += elem.offsetLeft;
   point.y += elem.offsetTop;
   //alert( elem.offsetTop + ' = ' + point.y );
   elem = elem.offsetParent;
 }
 return point;
    }

    function GSmallMapTypeControl() {
 GMapTypeControl.call( this, true );
    }
    GSmallMapTypeControl.prototype = new GMapTypeControl();
    GSmallMapTypeControl.prototype.constructor = GSmallMapTypeControl;
    window.GSmallMapTypeControl = GSmallMapTypeControl;

    var CtrlTable = {
 'GOverviewMapControl': true,
 'GLargeMapControl': true,
 'GSmallMapControl': true,
 'GSmallZoomControl': true,
 'GSmallMapTypeControl': true,
 'GMapTypeControl': true,
 'GMenuMapTypeControl': true,
 'GHierarchicalMapTypeControl': true,
 'GScaleControl': true
    };

    var MapTypeTable = {
 'G_NORMAL_MAP' : null,
 'G_SATELLITE_MAP' : null,
 'G_HYBRID_MAP' : null,
 'G_PHYSICAL_MAP' : null,
 'G_MAP_TYPE' : 'G_NORMAL_MAP',
 'G_SATELLITE_TYPE' : 'G_SATELLITE_MAP',
 'G_HYBRID_TYPE' : 'G_HYBRID_MAP'
    };

    var idmarkers = {};
    function markerForUrl( url ) {
 var matcha = /#(.*)/.exec( url );
 if( matcha )
   return idmarkers[ matcha[ 1 ] ];
 else
   return null;
    }

    // For this event handler, "this" is the clicked anchor
    function anchorClick() {
 var marker = markerForUrl( this.href );
 if( marker ) {
   if( /\bZOOM\b/.exec( this.className ) ) {
     var mapType = marker.mapType || marker.ezmap.map.getCurrentMapType();
     var zoomLevel;
     if( marker.span ) {
  zoomLevel = mapType.getSpanZoomLevel(
    marker.point, marker.span, marker.ezmap.viewsize );
     }
     else {
  zoomLevel = marker.ezmap.map.getZoom();
     }
     marker.ezmap.map.setCenter( marker.point, zoomLevel, mapType );
   }
   marker.doOpen();
   return false;
 }
 else {
   return true;
 }
    }

    function wordMap( str ) {
 var wmap = {};
 var list = str.split(' ');
 for( var j = 0; j < list.length; ++j ) {
   wmap[ list[ j ] ] = true;
 }
 return wmap;
    }

    function parseParams( str, params ) {
 var matchparam;
 for( var word in wordMap( str ) ) {
   matchparam = /^(\w+):(.*)$/.exec( word );
   if( matchparam && matchparam[1] in params ) {
     params[ matchparam[1] ] = matchparam[2];
   }
 }
 return params;
    }

    var markerOpener = {
 markers: [],
 addMarker: function( marker ) {
   this.markers.push( marker );
 },
 chainOpen: function( i ) {
   /*
    * This is a work-around for a Google Maps bug.  If I try to open
    * all the info windows at once, only the last one succeeds.
    *
    * Otherwise, it is equivalent to:
    *   for( i = 0; i < this.markers.length; ++i )
    *     this.markers[ i ].doOpen();
    */
   i = i || 0;
   if( i < this.markers.length ) {
     var onOpen = GEvent.bind(
    this.markers[ i ].ezmap.map,
    "infowindowopen",
    this,
    function(){
      GEvent.removeListener( onOpen );
      this.chainOpen( i + 1 );
    });
     this.markers[ i ].doOpen( true );
   }
   else {
     //alert('GMapEZ loadtime: ' + ( new Date() - startdate ) );
   }
 }
    };

    var laterFuncs = [];
    var lastFunc = null;
    function doNow() {
 if( laterFuncs.length > 0 ) {
   laterFuncs.shift().call();
   setTimeout( doNow, 1 );
 }
 else {
   if( lastFunc ) {
     lastFunc.call();
   }
 }
    }
    function doLater( obj, func ) {
 laterFuncs.push( function() { func.call( obj ); } );
    }

    var MiniIcon = new GIcon();
    MiniIcon.shadow = "http://labs.google.com/ridefinder/images/mm_20_shadow.png";
    MiniIcon.iconSize = new GSize(12, 20);
    MiniIcon.shadowSize = new GSize(22, 20);
    MiniIcon.iconAnchor = new GPoint(6, 20);
    MiniIcon.infoWindowAnchor = new GPoint(5, 1);

    G_DEFAULT_ICON.transparent = null;
    function EZInfoMarker( ezmap ) {
 this.ezmap = ezmap;
 this.icon = G_DEFAULT_ICON;

 this.point = null;
 this.title = null;

 this.blowup = false;
 this.tabs = [];

 this.infoZoomOffset = undefined;
 this.infoZoomLevel = undefined;
 this.infoMapType = null;
    }
    EZInfoMarker.prototype = new GMarker( new GLatLng( 0, 0 ) );
    EZInfoMarker.prototype.constructor = EZInfoMarker;

    EZInfoMarker.prototype.initialize = function( map ) {
 GMarker.call(
     this,
     this.point,
     {
  icon: this.icon,
  clickable: ( this.tabs.length > 0 || this.blowup ),
  title: this.title
     });
 GMarker.prototype.initialize.call( this, map );
    };

    EZInfoMarker.prototype.doOpen = function( autoopen ) {
 if( ! autoopen ) {
   var body = document.body || document.getElementsByTagName('body')[0];
   if( 'scrollLeft' in body ) {
     // http://www.howtocreate.co.uk/tutorials/javascript/browserwindow
     var myWidth = 0, myHeight = 0;
     if( typeof( window.innerWidth ) == 'number' ) {
  //Non-IE
  myWidth = window.innerWidth;
  myHeight = window.innerHeight;
     } else if( document.documentElement &&
    ( document.documentElement.clientWidth ||
    document.documentElement.clientHeight ) )
     {
  //IE 6+ in 'standards compliant mode'
  myWidth = document.documentElement.clientWidth;
  myHeight = document.documentElement.clientHeight;
     } else if( document.body &&
    ( document.body.clientWidth || document.body.clientHeight ) )
     {
  //IE 4 compatible
  myWidth = document.body.clientWidth;
  myHeight = document.body.clientHeight;
     }

     var mapdiv = this.ezmap.div;
     var totalOffset = getTotalOffset( mapdiv );
     if( totalOffset.x < body.scrollLeft ||
    totalOffset.x + mapdiv.offsetWidth > body.scrollLeft+myWidth ||
    totalOffset.y < body.scrollTop ||
    totalOffset.y + mapdiv.offsetHeight > body.scrollTop+myHeight)
     {
  //alert( totalOffset.x + ', ' + totalOffset.y );
  scrollTo( totalOffset.x, totalOffset.y );
     }
   }
 }

 var zoom = null;
 if( this.tabs.length > 0 ) {
   var opts = { maxWidth: this.ezmap.div.offsetWidth - 100 };
   if( this.icon ) {
     this.openInfoWindowTabs( this.tabs, opts );
   }
   else {
     // "INVISIBLE" markers are never added as overlays -- GMap2
     // knows nothing about them.
     this.ezmap.map.openInfoWindowTabs( this.point, this.tabs, opts );
   }
   for( var i = 0; i < this.tabs.length; ++i ) {
     this.setupInfoForm( this.tabs[ i ] );
   }
 }
 else if( this.blowup ) {
   if( this.infoZoomOffset != undefined )
     zoom = this.ezmap.map.getZoom() + this.infoZoomOffset;
   else if( this.infoZoomLevel != undefined )
     zoom = this.infoZoomLevel;

   if( zoom >= this.ezmap.map.getCurrentMapType().numZoomLevels )
     zoom = this.ezmap.map.getCurrentMapType().numZoomLevels - 1;
   else if( zoom < 0 )
     zoom = 0;

   this.showMapBlowup( { zoomLevel: zoom, mapType: this.infoMapType } );
 }
 else {
   this.ezmap.map.closeInfoWindow();
 }
    };

    EZInfoMarker.prototype.setupInfoForm = function( tab ) {
 var div, a;
 var tabElem = tab.contentElem;
 var classes = tabElem.className ? wordMap( tabElem.className ) : {};
 if( classes.DirectionsToHere ||
     classes.DirectionsFromHere ||
     classes.SearchNearby )
 {
   if( tab.infoFormId ) {
     div = document.getElementById( tab.infoFormId );
     div.innerHTML = '';
   }
   else {
     div = document.createElement('div');
     div.className = 'ez_infoForm';
     tab.infoFormId = div.id = newId();
     tabElem.appendChild( div );
   }
   var _this = this;
   if( classes.DirectionsToHere || classes.DirectionsFromHere ) {
     div.appendChild( document.createTextNode( 'Get directions: ' ) );
     if( classes.DirectionsToHere ) {
  a = document.createElement('a');
  a.innerHTML = 'To here';
  a.onclick = function() { _this.showForm( tab ); };
  a.href = 'javascript:void(null)';
  div.appendChild( a );
     }
     if( classes.DirectionsToHere && classes.DirectionsFromHere ) {
  div.appendChild( document.createTextNode( ' - ' ) );
     }
     if( classes.DirectionsFromHere ) {
  a = document.createElement('a');
  a.innerHTML = 'From here';
  a.onclick = function() {};
  a.href = 'javascript:void(null)';
  div.appendChild( a );
     }
     div.appendChild( document.createElement('br') );
   }
   if( classes.SearchNearby ) {
     a = document.createElement('a');
     a.innerHTML = 'Search nearby';
     a.onclick = function() {};
     a.href = 'javascript:void(null)';
     div.appendChild( a );
   }
 }
    };

    EZInfoMarker.prototype.showForm = function( tab ) {
 var div = document.getElementById( tab.infoFormId );
 div.innerHTML = '<b>Get directions:</b> To here - ';
 var a = document.createElement('a');
 a.innerHTML = 'From here';
 a.onclick = function() {};
 a.href = 'javascript:void(null)';
 div.appendChild( a );
 var x = document.createElement('div');
 x.innerHTML = 'Start address';
 div.appendChild( x );
 this.ezmap.map.getInfoWindow().reset();
    };

    function EZPolyline( color, weight, opacity ) {
 this.points = [];
 this.initialize = function( map ) {
   GPolyline.call( this, this.points, color, weight, opacity );
   GPolyline.prototype.initialize.call( this, map );
 };
    };
    EZPolyline.prototype = new GPolyline();
    EZPolyline.prototype.constructor = EZPolyline;


    function EZMap( div, classes ) {
 this.div = div;
 this.classes = classes;
 this.divData = null;

 this.map = undefined;
 this.viewsize = null;
 this.extentMarker = null;

 this.overlayList = [];

 this.loading = null;
 this.bar = null;
 this.maxstep = 0;
 this.step = 0;
 this.oi = 0;
 this.initFrame();
    }

    EZMap.prototype.logWarning = function( str ) {
 if( ! this.warningNode ) {
   this.warningVis = false;
   this.warningNode = document.createElement('ul');
   this.warningNode.className = 'warnings';
   this.div.appendChild( this.warningNode );

   var warnBtn = document.createElement('button');
   warnBtn.className = 'warnings';
   warnBtn.innerHTML = 'Warnings...';
   this.div.appendChild( warnBtn );
   var ezmap = this;
   warnBtn.onclick = function() { ezmap.toggleWarnings(); };
 }
 var li = document.createElement('li');
 li.innerHTML = str;
 this.warningNode.appendChild( li );
    };

    EZMap.prototype.toggleWarnings = function() {
 this.warningVis = ! this.warningVis;
 this.warningNode.style.display = this.warningVis ? 'block' : 'none';
    };

    EZMap.prototype.processMarkers = function( parentNode, polyline ) {
 var lastOverlay, marker, textContent, imgs;
 var matchll, matchspn, matchtype;
 for( var node = parentNode.firstChild; node; node = node.nextSibling){
   lastOverlay = this.overlayList[ this.overlayList.length - 1 ];
   switch( node.nodeName ) {
   case 'A':
     matchll = /\Wll=([-.\d]*),([-.\d]*)/.exec( node.href );
     if( matchll ) {

  marker = new EZInfoMarker( this );
  marker.title = node.getAttribute('title');
  this.overlayList.push( marker );

  if( node.id || node.name )
    idmarkers[ node.id || node.name ] = marker;

  textContent = node.innerHTML.replace( /<[^>]*>/g, '' );

  if( /\bOPEN\b/.exec( textContent ) )
    markerOpener.addMarker( marker );

  if( /\bEXTENT\b/.exec( textContent ) ) {
    marker.icon = null;
    this.extentMarker = marker;
  }

  if( /\bINVISIBLE\b/.exec( textContent ) ) {
    marker.icon = null;
  }

  marker.point = new GLatLng(
      parseFloat( matchll[1] ),
      parseFloat( matchll[2] ) );

  if( polyline ) {
    marker.icon = null;
    polyline.points.push( marker.point );
  }

  matchspn = /\Wspn=([-.\d]*),([-.\d]*)/.exec( node.href );
  if( matchspn ) {
    marker.span = new GLatLng(
   parseFloat( matchspn[1] ),
   parseFloat( matchspn[2] ) );
  }

  matchtype = /\Wt=(.)/.exec( node.href );
  if( matchtype ) {
    switch( matchtype[1] ) {
      case 'k': marker.mapType = G_SATELLITE_MAP; break;
      case 'h': marker.mapType = G_HYBRID_MAP; break;
      // XXX need a GMapType letter for use by ZOOM links
    }
  }

  // build icon
  imgs = node.getElementsByTagName('img')
  if( imgs.length < 1 ) {
    var matchcolor =
   /\b(ORANGE|PURPLE|YELLOW|GREEN|BLUE|RED|AQUA|WHITE|GRAY)\b/
   .exec( textContent );
    var matchsym =
   /\b([0-9A-Za-z]|BLANK|HASH|DOLLAR|DOT|START|END)\b/
   .exec( textContent );
    var matchmini = /\bMINI\b/.exec( textContent );

    if( matchcolor || matchsym || matchmini ) {
      var upper = matchsym && matchsym[0].match(/^[A-Z]$/);
      marker.icon = new GIcon( matchmini ? MiniIcon : G_DEFAULT_ICON );
      marker.icon.image = [
   upper ? upperImgBase : imgBase,
   matchmini ? 'mini' : 'marker',
   '-',
   matchcolor ? matchcolor[0] : 'ORANGE',
   '-',
   matchmini ? 'BLANK' : ( matchsym ? matchsym[0] : 'DOT' ),
   upper ? '-UPPER' : '',
   '.png' ].join('');

      marker.icon.printImage    = marker.icon.image;
      marker.icon.mozPrintImage = marker.icon.image;
    }
  }
  else {
    marker.icon = new GIcon( G_DEFAULT_ICON, imgs[ 0 ].src );
    marker.icon.printImage    = imgs[ 0 ].src;
    marker.icon.mozPrintImage = imgs[ 0 ].src;
    marker.icon.transparent = null;
    marker.icon.iconAnchor = null;
    marker.icon.infoWindowAnchor = null;

    var params = parseParams( imgs[ 0 ].className, {
      width: null, height: null,
      iconAnchor: null, infoWindowAnchor: null, imageMap: null } );

    var match;
    var width = parseInt( params.width );
    var height = parseInt( params.height );
    marker.icon.iconSize = new GSize( width, height );

    if( params.iconAnchor ) {
      match = /(\d+),(\d+)/.exec( params.iconAnchor );
      if( match ) {
   marker.icon.iconAnchor = new GPoint(
     parseInt( match[1] ),
     parseInt( match[2] ) );
      }
    }
    if( marker.icon.iconAnchor === null ) {
      marker.icon.iconAnchor = new GPoint(
   Math.round( width / 2 ),
   Math.max( 1, height - 2 ) );
    }

    if( params.infoWindowAnchor ) {
      match = /(\d+),(\d+)/.exec( params.infoWindowAnchor );
      if( match ) {
   marker.icon.infoWindowAnchor = new GPoint(
     parseInt( match[1] ),
     parseInt( match[2] ) );
      }
    }
    if( marker.icon.infoWindowAnchor === null ) {
      marker.icon.infoWindowAnchor = new GPoint(
   Math.round( width / 2 ),
   0 );
    }

    if( params.imageMap ) {
      marker.icon.imageMap = [];
      var parts = params.imageMap.split(/\s*,\s*/);
      for( var i = 0; i < parts.length; ++i ) {
   marker.icon.imageMap.push( parseInt( parts[ i ] ) );
      }
      //alert( marker.icon.imageMap );
    }

    if( imgs.length > 1 ) {
      marker.icon.shadow = imgs[ 1 ].src;
      params = parseParams( imgs[ 1 ].className, { width:0, height:0 });
      marker.icon.shadowSize = new GSize( params.width, params.height);
    }
    else {
      marker.icon.shadow = shadowServer + imgs[ 0 ].src;
      marker.icon.shadowSize = new GSize(
     Math.floor( width + height * 0.55 ), height );
    }

    if( imgs.length > 2 ) {
      marker.icon.transparent = imgs[ 2 ].src;
    }
    if( imgs.length > 3 ) {
      marker.icon.printImage = imgs[ 3 ].src;
    }
    if( imgs.length > 4 ) {
      marker.icon.printShadow = imgs[ 4 ].src;
    }
    if( imgs.length > 5 ) {
      marker.icon.mozPrintShadow = imgs[ 5 ].src;
    }
  }
     }
     else {
  this.logWarning( "No ll param for marker [" + node.innerHTML +
    ":" + (node.id || node.name) + "]" );
     }
     break;

   case 'DIV':
     if( ! lastOverlay ) {
  this.logWarning( "div block given before any markers" );
  continue;
     }
     else {
  var infoClasses = wordMap( node.className );
  if( 'GMapEZ' in infoClasses ) {
    // infoWindow blowup
    // XXX replace this with a nested map to allow for use
    // in tabs?
    lastOverlay.blowup = true;
    var matchzoom = /ZOOMLEVEL([-+=]?)(\d+)/.exec( node.innerHTML );
    if( matchzoom ) {
      var num = parseInt( matchzoom[ 2 ] );
      if( matchzoom[ 1 ] == '-' )
   lastOverlay.infoZoomOffset = num;
      else if( matchzoom[ 1 ] == '+' )
   lastOverlay.infoZoomOffset = - num;
      else
   lastOverlay.infoZoomLevel = num;
    }

    for( typeName in MapTypeTable ) {
      if( typeName in infoClasses ) {
   if( MapTypeTable[ typeName ] ) {
     lastOverlay.infoMapType = window[ MapTypeTable[ typeName ] ];
   }
   else {
     lastOverlay.infoMapType = window[ typeName ];
   }
   break;
      }
    }
  }
  else {
    // XXX remove title attribute from div node?
    lastOverlay.tabs.push(
   new GInfoWindowTab( node.getAttribute('title'), node ));
  }
     }
     break;

   case 'LI':
     this.processMarkers( node, polyline );
     break;

   case 'OL':
     var params = parseParams( node.className,
    { color: null, weight: null, opacity: null } );
     if( params.color && ! /^#[0-9a-zA-Z]{6}$/.exec( params.color ) )
  this.logWarning( 'Polyline color should be a 6-digit' +
      ' hex color like "#123abc", not "' + params.color + '"' );
     if( params.weight != null ) {
  var w = parseInt( params.weight );
  if( w < 1 || isNaN( w ) )
    this.logWarning( 'Polyline weight should be an' +
   ' interger above 0, not "' + params.weight + '"' );
  params.weight = w;
     }
     if( params.opacity ) {
  var o = parseFloat( params.opacity );
  if( o < 0 || o > 1 || isNaN( o ) )
    this.logWarning( 'Polyline opacity should be ' +
   ' between 0 and 1, not "' + params.opacity + '"' );
  params.opacity = o;
     }
     var newline = new EZPolyline(
    params.color,
    params.weight,
    params.opacity );
     this.overlayList.push( newline );
     this.processMarkers( node, newline );
     break;

   case '#text':
   case '#comment':
     // ignore text and comments
     break;

   default:
     this.logWarning( "Unknown or misplaced node " + node.nodeName );
     break;
   }
 }
    };

    EZMap.prototype.onClick = function( overlay, point ) {
 if( overlay && overlay.doOpen ) {
   overlay.doOpen();
 }
 else if( point ) {
   this.map.closeInfoWindow();
 }
    };

    EZMap.prototype.nextStep = function( func ) {
 if( this.maxstep > 0 ) {
   this.bar.style.width = Math.round( this.step / this.maxstep * 100 ) + '%';
 }
 this.step += 1;
 doLater( this, func );
    };

    EZMap.prototype.initFrame = function() {
 this.divData = this.div;
 this.div = this.div.cloneNode( false );
 this.divData.parentNode.insertBefore( this.div, this.divData );
 this.divData.parentNode.removeChild( this.divData );
 this.div.style.visibility = 'visible';

 this.loading = document.createElement('div');
 this.loading.className = 'loadprogress';
 this.loading.style.marginTop = ( this.div.offsetHeight / 3 ) + 'px';
 this.loading.innerHTML = '<div class="box"><div class="logo"></div><div class="trough"><div class="bar"></div></div></div>';
 this.bar = this.loading.getElementsByTagName('div')[3];
 this.div.appendChild( this.loading );

 this.nextStep( this.initParse );
    };

    EZMap.prototype.initParse = function() {
 this.processMarkers( this.divData );
 this.divData = null;

 this.map = new GMap2( this.div );
 this.map.getContainer().appendChild( this.loading );

 GEvent.bind( this.map, 'click', this, this.onClick );
 if( 'ScrollWheelZoom' in this.classes ) {
   this.map.enableScrollWheelZoom();
 }

 if( ! this.extentMarker && this.overlayList.length == 1 )
   this.extentMarker = this.overlayList[ 0 ];

 // map type
 var mapType = G_NORMAL_MAP;
 if( this.extentMarker && this.extentMarker.mapType ) {
   mapType = this.extentMarker.mapType;
 }
 for( typeName in MapTypeTable ) {
   if( typeName in this.classes ) {
     if( MapTypeTable[ typeName ] ) {
  mapType = window[ MapTypeTable[ typeName ] ];
     }
     else {
  mapType = window[ typeName ];
     }
     break;
   }
 }

 // center and zoom
 this.viewsize = new GSize( this.div.offsetWidth, this.div.offsetHeight );
 var center, zoomLevel;
 if( this.extentMarker ) {
   center = this.extentMarker.point;
   if( this.extentMarker.span ) {
     zoomLevel = mapType.getSpanZoomLevel(
    center, this.extentMarker.span, this.viewsize );
   }
   else {
     zoomLevel = 10;
   }
 }
 else if( this.overlayList.length > 1 ) {
   var autoBounds;
   for( var i = 0; i < this.overlayList.length; ++i ) {
     if( this.overlayList[ i ].point ) {
  if( ! autoBounds ) {
    autoBounds = new GLatLngBounds(
   this.overlayList[ i ].point,
   this.overlayList[ i ].point );
  }
  else {
    autoBounds.extend( this.overlayList[ i ].point );
  }
     }
   }
   var sw = autoBounds.getSouthWest();
   var ne = autoBounds.getNorthEast();
   center = new GLatLng(
     ( sw.lat() + ne.lat() ) / 2,
     ( sw.lng() + ne.lng() ) / 2 );
   zoomLevel = mapType.getBoundsZoomLevel( autoBounds, this.viewsize);
 }
 else {
   center = new GLatLng( 41.075210, -85.130310 );
   zoomLevel = 10;
 }

 // apply center, zoom, and map type
 this.map.setCenter( center, zoomLevel, mapType );

 this.maxstep = Math.floor( this.overlayList.length / overlaysPerStep ) + 2;
 this.initOverlays();
    };

    EZMap.prototype.initOverlays = function() {
 var overlay;
 var steplimit = Math.min(this.overlayList.length, this.oi+overlaysPerStep);
 for( ; this.oi < steplimit; ++this.oi ) {
   overlay = this.overlayList[ this.oi ];
   if( overlay.points || overlay.icon )
     this.map.addOverlay( overlay );
   this.overlayList[ this.oi ] = null;
 }
 if( this.oi < this.overlayList.length )
   this.nextStep( this.initOverlays );
 else
   this.nextStep( this.initControls );
    };

    EZMap.prototype.initControls = function() {
 for( var ctrl in CtrlTable ) {
   if( ctrl in this.classes ) {
     this.map.addControl( new window[ ctrl ]() );
   }
 }

 this.nextStep( this.initLoading );
    };

    EZMap.prototype.initLoading = function() {
 this.loading.parentNode.removeChild( this.loading );
 this.loading = null;
    };

    // Find all anchor tags linking to GMapEZ markers
    var anchors = document.getElementsByTagName( 'a' );
    for( var mi = 0; mi < anchors.length; ++mi ) {
 if( ! anchors[ mi ].onclick ) {
   anchors[ mi ].onclick = anchorClick;
 }
    }

    // Find all divs marked as GMapEZ
    var divs = document.getElementsByTagName( 'div' );
    for( var i = 0; i < divs.length; ++i ) {
 var div = divs[ i ];
 var classes = wordMap( div.className );
 if( 'GMapEZ' in classes ) {
   new EZMap( div, classes );
 }
    }

    lastFunc = function() {
 // Examine current page location for a reference to a GMapEZ marker
 var marker = markerForUrl( document.location );
 if( marker )
   markerOpener.addMarker( marker );

 // Open all the markers we need to
 markerOpener.chainOpen();
    };

    doNow();
  }

  function chainWindowFunc( funcname, newfunc ) {
    var oldfunc = window[ funcname ];
    if( oldfunc ) {
 window[ funcname ] = function() { oldfunc(); newfunc(); };
    }
    else {
 window[ funcname ] = newfunc;
    }
  }

  window.addOnLoad   = function( func ) { chainWindowFunc( "onload",   func );};
  window.addOnUnload = function( func ) { chainWindowFunc( "onunload", func );};

  window.ez_preload = function() {
    if( window.G_INCOMPAT ) {
 // If the key failed to validate, cause all keys to appear valid
 // and try again.
 window.G_INCOMPAT = false;
 window.GValidateKey = function(){ return true; }
 GLoad();
    }
    addOnLoad( loadfunc );
  }

  var key = '';
  var gmapversion = '2';
  (function(){
    var metas = document.getElementsByTagName( 'meta' );
    var match;
    for( var i = 0; i < metas.length; ++i ) {
 match = /gmapkey:?(.*)/.exec( metas[ i ].name );
 if( match ) {
   if( ! match[ 1 ] ) {
     key = metas[ i ].content;
   }
   else if( (new RegExp( match[ 1 ] )).exec( window.location.href ) ) {
     key = metas[ i ].content;
     break;
   }
 }
 else if( metas[ i ].name == 'gmapversion' ) {
   gmapversion = metas[ i ].content;
 }
    }
  })();

  if( ! window.GMap2 ) {
    document.write( [
 '<script src="http://maps.google.com/maps?file=api&v='
 + gmapversion + '&key=' + key
 + '" type="text/javascript"></script>' ].join('\n') );
  }

  document.write( [
    '<script type="text/javascript">',
    '  ez_preload();',
    '</script>',

    '<style type="text/css">',
    'div.GMapEZ {',
    '  visibility: hidden;',
    '  border: 1px #888 solid;',
    '}',

    'div.GMapEZ ul.warnings {',
    '  position: absolute;',
    '  top: 0;',
    '  left: 0;',
    '  margin: 0;',
    '  padding-right: 0.5em;',
    '  padding-left: 1.5em;',
    '  display: none;',
    '  border: 1px #888 solid;',
    '  background: #fff;',
    '  z-index: 100000000;',
    '  text-align: left;',
    '  font-family: Arial;',
    '  font-size: 9pt;',
    '  overflow: auto;',
    '}',

    'div.GMapEZ button.warnings {',
    '  display: block;',
    '  position: absolute;',
    '  z-index: 100000000;',
    '  bottom: 20px;',
    '  right: 0;',
    '  color: #f00;',
    '}',

    'div.GMapEZ .firefoxref {',
    '  text-align: center;',
    '  margin: 1em;',
    '}',

    'div.GMapEZ .loadprogress {',
    '  position: relative;',
    '  z-index: 100000000;',
    '  text-align: center;',
    '}',

    'div.GMapEZ .loadprogress .box {',
    '  font-family: Arial, sans-serif;',
    '  background: #fff;',
    '  border: 1px #bbb inset;',
    '  width: 136px;',
    '  height: 45px;',
    '  margin: auto;',
    '}',

    'div.GMapEZ .loadprogress .logo {',
    '  margin: 8px;',
    '  margin-bottom: 0;',
    '  width: 120px;',
    '  height: 28px;',
    "  filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" +
   imgBase + "logo3.png',sizingMethod='scale');",
    '}',
    'div.GMapEZ .loadprogress .box > .logo {',
    '  position: relative;',
    '  background: url(' + imgBase + 'logo3.png) no-repeat;',
    '}',

    'div.GMapEZ .loadprogress .trough {',
    '  margin: 8px;',
    '  margin-top: -5px;',
    '  background: #ccc;',
    '  font-size: 1px;',
    '  height: 8px;',
    '  text-align: left;',
    '}',

    'div.GMapEZ .loadprogress .bar {',
    '  height: 8px;',
    '  width: 0px;',
    '  background: #55a url(' + imgBase + 'progressbar.png);',
    '}',

    'v\\:* {',
    '  behavior:url(#default#VML);',
    '}',
    '</style>'
  ].join('\n'));
})();

