/*
 * 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,
	      'GScaleControl': true
	    };
	
	    var MapTypeTable = {
	      'G_MAP_TYPE' : true,
	      'G_SATELLITE_TYPE' : true,
	      'G_HYBRID_TYPE' : true,
	      'G_PHYSICAL_TYPE': true
	    };
	
	    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_TYPE; break;
	                case 'h': marker.mapType = G_HYBRID_TYPE; break;
	                // XXX need a G_MAP_TYPE 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[ 16 ] );
	                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 ) {
	                  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 );
	    };
	
	    var mouselat, mouselng;
	    function onmousemove( point ) {
	      mouselat = point.y.toFixed(6);
	      mouselng = point.x.toFixed(6);
	    }
	
	    EZMap.prototype.onScroll = function( scrollEvent ) {
	      var zoom = 0;
	      if( scrollEvent.cancelable ) {
	        scrollEvent.preventDefault();
	      }
	      if( scrollEvent.detail ) {
	        zoom = scrollEvent.detail;
	      }
	      else if( scrollEvent.wheelDelta ) {
	        zoom = -scrollEvent.wheelDelta;
	      }
	      if( zoom ) {
	        var m = this.map.fromLatLngToDivPixel( new GLatLng(mouselat,mouselng) );
	        var c = this.map.fromLatLngToDivPixel( this.map.getCenter() );
	        if( zoom < 0 ) {
	          var x = c.x - ((m.x - c.x) * -.5);
	          var y = c.y - ((m.y - c.y) * -.5);
	          var n = this.map.fromDivPixelToLatLng(new GPoint(x,y));
	          this.map.setCenter(n);
	          this.map.zoomIn();
	        }
	        if( zoom > 0 ) {
	          var x = c.x - (m.x - c.x);
	          var y = c.y - (m.y - c.y);
	          var n = this.map.fromDivPixelToLatLng(new GPoint(x,y));
	          this.map.setCenter(n);
	          this.map.zoomOut();
	        }
	      }
	    };
	
	    EZMap.prototype.initParse = function() {
	      this.processMarkers( this.divData );
	      this.divData = null;
	
	      this.map = new GMap2( this.div );
	      this.map.getContainer().appendChild( this.loading );
	
	      GEvent.addListener( this.map, 'mousemove', onmousemove );
	      GEvent.bindDom(this.div, 'DOMMouseScroll', this, this.onScroll); //Firefox
	      GEvent.bindDom(this.div, 'mousewheel', this, this.onScroll); // IE + Opera
	
	      GEvent.bind( this.map, 'click', this, this.onClick );
	
	      if( ! this.extentMarker && this.overlayList.length == 1 )
	        this.extentMarker = this.overlayList[ 0 ];
	
	      // map type
	      var mapType = G_MAP_TYPE;
	      if( this.extentMarker && this.extentMarker.mapType ) {
	        mapType = this.extentMarker.mapType;
	      }
	      for( typeName in MapTypeTable ) {
	        if( typeName in this.classes ) {
	          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 =16;
	        }
	      }
	      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 = 16;
	      }
	
	      // apply center, zoom, and map type
	      this.map.setCenter( center, 16, 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'));
})();


