/*
 * GMapEZ -- Turn specially-marked HTML into Google Maps
 * Copyright (C) July 2005 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 link = document.createElement('link');
  link.type = 'text/css';
  link.rel = 'stylesheet';
  link.href = 'http://bluweb.com/chouser/gmapez/gmapez.css';
  document.getElementsByTagName('head')[0].appendChild( link );

  function loadfunc() {

    if( ! window.GIcon ) {
      _apiHash = undefined;
      GMapsNamespace();
    }

    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 defaultMarker = new GMarker();
    var autoOpen = [];

    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 ) {
        var divDom = div.cloneNode( true );
        div.innerHTML = '';
        div.style.visibility = 'visible';

        var map = new GMap( div );
        var centered = false;

        for( var ctrl in CtrlTable ) {
          if( ctrl in classes ) {
            map.addControl( new window[ ctrl ]() );
          }
        }

        var marker = undefined;
        var minX = undefined;
        var maxX = undefined;
        var minY = undefined;
        var maxY = undefined;
        var mapType = undefined;
        var pointCount = 0;
        var extent = new Object();
        var explicitExtent = false;
        for( var node = divDom.firstChild; node; node = node.nextSibling ) {
          if( node.nodeName == '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' )
              explicitExtent = true; // this stays true for this whole map

            var matchll = /\Wll=([-.\d]*),([-.\d]*)/.exec( node.href );
            if( matchll ) {
              ++pointCount;
              var x = parseFloat( matchll[2] );
              var y = parseFloat( matchll[1] );
              var point = new GPoint( x, y );

              if( textContent == 'EXTENT' ) {
                extent.center = point;
              }
              else {
                if( minX == undefined || x < minX ) minX = x;
                if( maxX == undefined || x > maxX ) maxX = x;
                if( minY == undefined || y < minY ) minY = y;
                if( maxY == undefined || y > maxY ) maxY = y;

                var ltr = '';
                var color = 'O';
                var matchltr = /\b[A-J]\b/.exec( textContent );
                if( matchltr )
                  ltr = matchltr[ 0 ];
                var matchcolor = /\b(ORANGE|PURPLE|YELLOW|GREEN|BLUE)\b/.exec(
                  textContent );
                if( matchcolor )
                  color = matchcolor[0].substring( 0, 1 );

                var icon = new GIcon( defaultMarker.icon );
                icon.image =
                  'http://bluweb.com/us/chouser/gmapez/iconEZ/marker'
                  + ltr + '-' + color + '.png';
                marker = new GMarker( point, icon );
                map.centerAndZoom( point, 4 ); // why do I need this?
                map.addOverlay( marker );

                idmarkers[ node.id || node.name ] = marker;
                if( openThisMarker )
                  autoOpen.push( marker );
              }
            }

            if( pointCount == 1 || textContent == 'EXTENT' ) {
              var matchspn = /\Wspn=([-.\d]*),([-.\d]*)/.exec( node.href );
              if( matchspn ) {
                extent.span = new Object();
                extent.span.width  = parseFloat( matchspn[2] );
                extent.span.height = parseFloat( matchspn[1] );
              }

              var matchtype = /\Wt=(.)/.exec( node.href );
              if( matchtype ) {
                switch( matchtype[1] ) {
                  case 'k': mapType = G_SATELLITE_TYPE; break;
                  case 'h': mapType = G_HYBRID_TYPE; break;
                }
              }
            }
          }
          else if( node.nodeName == 'DIV' && marker ) {
            (function(){
              var width = div.offsetWidth * 2 / 3;
              var html = undefined;
              var infoClasses = wordMap( node.className );
              if( 'GMapEZ' in infoClasses ) {
                var localMap = map;
                var matchzoom = /ZOOMLEVEL([-+=]?)(\d+)/.exec( node.innerHTML );
                var infoZoomLevel = undefined;
                var infoZoomOffset = undefined;
                if( matchzoom ) {
                  var num = parseInt( matchzoom[ 2 ] );
                  if( matchzoom[ 1 ] == '-' )
                    infoZoomOffset = num;
                  else if( matchzoom[ 1 ] == '+' )
                    infoZoomOffset = - num;
                  else
                    infoZoomLevel = num;
                }

                var infoMapType = null;
                for( typeName in MapTypeTable ) {
                  if( typeName in infoClasses ) {
                    infoMapType = window[ typeName ];
                    break;
                  }
                }

                marker.doOpen = function() {
                  var zoom = null;
                  if( infoZoomOffset != undefined )
                    zoom = localMap.getZoomLevel() + infoZoomOffset;
                  else if( infoZoomLevel != undefined )
                    zoom = infoZoomLevel;

                  if( zoom >= localMap.spec.numZoomLevels )
                    zoom = localMap.spec.numZoomLevels - 1;
                  else if( zoom < 0 )
                    zoom = 0;

                  this.showMapBlowup( zoom, infoMapType );
                }
              }
              else {
                html = node.outerHTML;
                if( ! html ) {
                  html = '<div';
                  var attrs = node.attributes;
                  for( var j = 0; j < attrs.length; ++j )
                    html += ' ' + attrs[j].name + '="' + attrs[j].value + '"';
                  html += '>' + node.innerHTML + '</div>';
                }
                var fullhtml = '<div style="max-width: ' + width + 'px">' +
                    html + '</div>';
                marker.doOpen = function() {
                  this.openInfoWindowHtml( fullhtml );
                }
              }
            })();
            GEvent.addListener( marker, 'click', marker.doOpen );
          }
        }

        if( ! extent.center ) {
          if( minX == undefined ) {
            map.centerAndZoom( new GPoint(-85.130310, 41.075210), 7 );
          }
          else {
            extent.center = new GPoint( (minX + maxX)/2, (minY + maxY)/2 );
            if( ! explicitExtent && pointCount != 1 ) {
              extent.span = new Object();
              extent.span.width  = maxX - minX;
              extent.span.height = maxY - minY;
            }
          }
        }

        for( typeName in MapTypeTable ) {
          if( typeName in classes ) {
            mapType = window[ typeName ];
            explicitExtent = true;
            break;
          }
        }

        if( pointCount == 1 || explicitExtent ) {
          if( mapType )
            map.setMapType( mapType );
        }

        if( extent.span ) {
          var zoomLevel = map.spec.getLowestZoomLevel(
              extent.center, extent.span, map.viewSize );
          map.centerAndZoom( extent.center, zoomLevel );
        }
      }
    }

    var anchors = document.getElementsByTagName( 'a' );
    for( var i = 0; i < anchors.length; ++i ) {
      var marker = markerForUrl( anchors[ i ].href );
      if( marker )
        GEvent.bindDom( anchors[ i ], "click", marker, marker.doOpen );
    }

    var marker = markerForUrl( document.location );
    if( marker )
      autoOpen.push( marker );

    /*
     * 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 < autoOpen.length; ++i )
     *     autoOpen[ i ].doOpen();
     */
    function chainOpen( i ) {
      if( i < autoOpen.length ) {
        var onOpen = GEvent.bind(
            autoOpen[ i ],
            "infowindowopen",
            null,
            function(){
              GEvent.removeListener( onOpen );
              chainOpen( i + 1 );
            });
        autoOpen[ i ].doOpen();
      }
    };
    chainOpen( 0 );
  }

  function addOnLoad( func ) {
    if( window.onload ) {
      var oldfunc = window.onload;
      window.onload = function() { oldfunc(); func(); }
    }
    else {
      window.onload = func;
    }
  }
  window.addOnLoad = addOnLoad;

  addOnLoad( loadfunc );
})();

