
/*
 * GMapEZ -- Turn specially-marked HTML into Google Maps
 * Copyright (C) July 2005 - May 2006 by Chris Houser <chouser@bluweb.com>
 *
 * 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://bluweb.com/chouser/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://bluweb.com/us/chouser/gmapez/';
  //var imgBase = 'http://www.massbianchet.it/images/';

  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 GSmallMapTypeControl() {
      GMapTypeControl.call( this, true );
    }
    GSmallMapTypeControl.prototype = new GMapTypeControl();
    GSmallMapTypeControl.prototype.constructor = GSmallMapTypeControl;
    window.GSmallMapTypeControl = GSmallMapTypeControl;

    var CtrlTable = {
      '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_KATRINA_TYPE' : true
    };

    var idmarkers = {};
    function markerForUrl( url ) {
      var matcha = /#(.*)/.exec( url );
      if( matcha )
        return idmarkers[ matcha[ 1 ] ];
      else
        return null;
    }

    function wordMap( str ) {
      var wmap = {};
      var list = str.split(' ');
      for( var j = 0; j < list.length; ++j ) {
        wmap[ list[ j ] ] = true;
      }
      return wmap;
    }

    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 ],
              "infowindowopen",
              this,
              function(){
                GEvent.removeListener( onOpen );
                this.chainOpen( i + 1 );
              });
          this.markers[ i ].doOpen();
        }
        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);

    function EZInfoMarker( ezmap, point, icon, title ) {
      this.ezmap = ezmap;
      this.point = point;
      this.icon = icon;
      this.title = title;

      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() {
      var zoom = null;
      if( this.tabs.length > 0 ) {
        this.openInfoWindowTabs( this.tabs, {
          maxWidth: this.ezmap.div.offsetWidth - 100 } );
      }
      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();
      }
    };

    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.mapType = undefined;
      this.autoBounds = undefined;
      this.center = undefined;
      this.span = undefined;
      this.explicitExtent = false;

      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 ) {
      for( var node = parentNode.firstChild; node; node = node.nextSibling){
        var lastOverlay = this.overlayList[ this.overlayList.length - 1 ];
        switch( node.nodeName ) {
        case 'A':
          var textContent = node.innerHTML.replace( /<[^>]*>/g, '' );
          var openThisMarker = /\bOPEN\b/.exec( textContent );
          textContent = textContent.replace( /\bOPEN\b/, '' );
          textContent = textContent.replace( /^\s*/, '' );
          textContent = textContent.replace( /\s*$/, '' );
          if( textContent == 'EXTENT' )
            this.explicitExtent = true;

          var matchll = /\Wll=([-.\d]*),([-.\d]*)/.exec( node.href );
          if( matchll ) {
            var lat = parseFloat( matchll[1] );
            var lng = parseFloat( matchll[2] );
            var point = new GLatLng( lat, lng );
            if( polyline ) {
              polyline.points.push( point );
            }

            if( textContent == 'EXTENT'
                || ( ! this.explicitExtent && this.overlayList.length < 1 ) )
            {
              this.center = point;

              var matchspn = /\Wspn=([-.\d]*),([-.\d]*)/.exec( node.href );
              if( matchspn ) {
                this.span = new GLatLng(
                    parseFloat( matchspn[1] ),
                    parseFloat( matchspn[2] ) );
              }

              var matchtype = /\Wt=(.)/.exec( node.href );
              if( matchtype ) {
                switch( matchtype[1] ) {
                  case 'k': this.mapType = G_SATELLITE_TYPE; break;
                  case 'h': this.mapType = G_HYBRID_TYPE; break;
                }
              }
            }

            if( textContent != 'EXTENT' ) {
              if( ! this.autoBounds ) {
                this.autoBounds = new GLatLngBounds( point, point );
              }
              else {
                this.autoBounds.extend( point );
              }

              var iconmodel = G_DEFAULT_ICON;
              var iconbase = 'marker';
              var sym = null;
              var color = 'ORANGE';

              var matchcolor =
                  /\b(ORANGE|PURPLE|YELLOW|GREEN|BLUE|RED|AQUA|WHITE|GRAY)\b/
                  .exec( textContent );
              if( matchcolor )
                color = matchcolor[0];

              var matchsym =
                  /\b([0-9A-Za-z]|BLANK|HASH|DOLLAR|DOT|START|END)\b/
                  .exec( textContent );
              if( matchsym )
                sym = matchsym[ 0 ];

              var matchmini = /\bMINI\b/.exec( textContent );
              if( matchmini ) {
                iconmodel = MiniIcon;
                iconbase = 'mini';
                sym = 'BLANK';
              }

              if( sym || ! polyline ) {
                var icon = new GIcon( iconmodel );
                icon.image = [
                  imgBase, 'iconEZ2/', iconbase, '-', color, '-',
                  ( sym || 'DOT' ), '.png' ].join('');
                var marker = new EZInfoMarker(
                    this, point, icon, node.getAttribute('title') );

                this.overlayList.push( marker );

                idmarkers[ node.id || node.name ] = marker;
                if( openThisMarker )
                  markerOpener.addMarker( marker );
              }
            }
          }
          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
              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 ) {
                  lastOverlay.infoMapType = window[ typeName ];
                  break;
                }
              }
            }
            else {
              lastOverlay.tabs.push(
                  new GInfoWindowTab( node.getAttribute('title'), node ));
            }
          }
          break;

        case 'LI':
          this.processMarkers( node, polyline );
          break;

        case 'OL':
          var params = { color: null, weight: null, opacity: null };
          for( var word in wordMap( node.className ) ) {
            var matchparam = /^(color|weight|opacity):(.*)$/.exec( word );
            if( matchparam )
              params[ matchparam[1] ] = matchparam[2];
          }
          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 {
        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 = div.cloneNode( true );
      this.div.innerHTML = '';
      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 );

      // map type
      if( this.overlayList.length > 1 && ! this.explicitExtent ) {
        this.mapType = null;
      }
      for( typeName in MapTypeTable ) {
        if( typeName in this.classes ) {
          this.mapType = window[ typeName ];
          break;
        }
      }
      this.mapType = this.mapType || G_MAP_TYPE;

      // center and zoom
      var viewsize = new GSize( this.div.offsetWidth, this.div.offsetHeight );
      var zoomLevel;
      if( this.overlayList.length == 1 || this.explicitExtent ) {
        if( this.span ) {
          zoomLevel = this.mapType.getSpanZoomLevel(
              this.center, this.span, viewsize );
        }
      }
      else if( this.overlayList.length > 1 ) {
        var sw = this.autoBounds.getSouthWest();
        var ne = this.autoBounds.getNorthEast();
        this.center = new GLatLng(
          ( sw.lat() + ne.lat() ) / 2,
          ( sw.lng() + ne.lng() ) / 2 );
        zoomLevel = this.mapType.getBoundsZoomLevel( this.autoBounds, viewsize);
      }
      else {
        this.center = new GLatLng( 41.075210, -85.130310 );
        zoomLevel = 10;
      }

      // apply center, zoom, and map type
      this.map.setCenter( this.center, zoomLevel, this.mapType );

      this.maxstep = Math.floor( this.overlayList.length / overlaysPerStep ) + 2;
      this.initOverlays();
    };

    EZMap.prototype.initOverlays = function() {
      var steplimit = Math.min(this.overlayList.length, this.oi+overlaysPerStep);
      for( ; this.oi < steplimit; ++this.oi ) {
        this.map.addOverlay( this.overlayList[ this.oi ] );
        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 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() {
      // Find all anchor tags linking to GMapEZ markers
      var anchors = document.getElementsByTagName( 'a' );
      for( var mi = 0; mi < anchors.length; ++mi ) {
        var marker = markerForUrl( anchors[ mi ].href );
        if( marker )
          GEvent.bindDom( anchors[ mi ], "click", marker, marker.doOpen );
      }

      // 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 = '';
  (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;
        }
      }
    }
  })();

  document.write( [
    '<script src="http://maps.google.com/maps?file=api&v=2&key=' + key
    + '" type="text/javascript"></script>',
    '<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'));
})();


