google.load("maps", "2");

var subAdress = null,
    results = [],
    resultsTm = [],
    filArt = '',
    lastKlick = 0,
    activeTab = '',
    allowedBounds = null,
    zoomSearch = 13,
    austriaPoly = null
    startIndex = 1,
    aktivMarker = null,
    centerSelf = false,
    startList = 0,
    pfadData = '/privat/service_hilfe/Suche/Shop_Finder/',
    routeWnd = false,
    markerMng = [],
    gDIRArray = [],
    toAdress = '',
    offenAdress = '';


var letter = new Array;
var showLetter = new Array;

function initKarte() {
    if(!google.maps.BrowserIsCompatible()) {
        alert("Browser nicht Kompatible!");
        return;
    }else {
        initialize();
    }
}

function initialize() { 
    // google kare laden und im mapDiv anziegen
    map = new google.maps.Map2(document.getElementById("mapDiv"));
    // keyboard steuerung aktivieren
    new google.maps.KeyboardHandler(map);
    // zoom in bie doppelklick auf karte
    map.enableDoubleClickZoom();
    // �sterreich zeigen
    map.setCenter(new google.maps.LatLng(47.38000561,13.51153823), 6, G_NORMAL_MAP);
    // google routenplaner laden
    gdir = new google.maps.Directions(map);
    // ein fehler auftritt bei google routenplaner
    //google.maps.Event.addListener(gdir, "error", handleErrors);

    map.addControl(new google.maps.LargeMapControl());
    map.addControl(new google.maps.ScaleControl());

    var points = [];

        points.push( new google.maps.LatLng(46.79253,11.05517) );	points.push( new google.maps.LatLng(46.98025,11.18701) );	points.push( new google.maps.LatLng(46.97275,11.71435) );	points.push( new google.maps.LatLng(47.09256,12.20874) );	points.push( new google.maps.LatLng(46.98774,12.12084) );	points.push( new google.maps.LatLng(46.87521,12.26367) );	points.push( new google.maps.LatLng(46.67205,12.49438) );	points.push( new google.maps.LatLng(46.55886,13.30737) );	points.push( new google.maps.LatLng(46.49082,13.96655) );	points.push( new google.maps.LatLng(46.38483,14.53784) );	points.push( new google.maps.LatLng(46.65697,15.05419) );	points.push( new google.maps.LatLng(46.68713,15.62548) );	points.push( new google.maps.LatLng(46.67205,16.03198) );	points.push( new google.maps.LatLng(46.87521,16.11987) );	points.push( new google.maps.LatLng(47.01771,16.53735) );	points.push( new google.maps.LatLng(47.39834,16.47143) );	points.push( new google.maps.LatLng(47.47266,16.64721) );	points.push( new google.maps.LatLng(47.62097,16.68017) );	points.push( new google.maps.LatLng(47.66723,16.42529) );	points.push( new google.maps.LatLng(47.75409,16.54339) );
	points.push( new google.maps.LatLng(47.73932,16.71093) );	points.push( new google.maps.LatLng(47.68573,16.76312) );	points.push( new google.maps.LatLng(47.70976,17.08996) );	points.push( new google.maps.LatLng(47.86661,17.02404) );	points.push( new google.maps.LatLng(47.97153,17.0982) );	points.push( new google.maps.LatLng(48.01013,17.16137) );	points.push( new google.maps.LatLng(48.05421,17.07073) );	points.push( new google.maps.LatLng(48.14043,17.057) );	        points.push( new google.maps.LatLng(48.26491,16.95538) );	points.push( new google.maps.LatLng(48.44195,16.8565) );	points.push( new google.maps.LatLng(48.54934,16.94165) );	points.push( new google.maps.LatLng(48.71814,16.90045) );	points.push( new google.maps.LatLng(48.73626,16.67797) );	points.push( new google.maps.LatLng(48.81409,16.5324) );	points.push( new google.maps.LatLng(48.74351,16.39782) );	points.push( new google.maps.LatLng(48.84122,15.90344) );	points.push( new google.maps.LatLng(48.87374,15.78533) );	points.push( new google.maps.LatLng(48.8611,15.6892) );	        points.push( new google.maps.LatLng(48.98742,15.29644) );	points.push( new google.maps.LatLng(48.94595,15.1701) );
	points.push( new google.maps.LatLng(49.01445,15.01354) ); 	points.push( new google.maps.LatLng(48.77972,14.97235) );	points.push( new google.maps.LatLng(48.78334,14.81854) );	points.push( new google.maps.LatLng(48.59114,14.70043) );	points.push( new google.maps.LatLng(48.64198,14.45324) );	points.push( new google.maps.LatLng(48.55843,14.32965) );	points.push( new google.maps.LatLng(48.64742,14.02203) );	points.push( new google.maps.LatLng(48.67826,14.06048) );	points.push( new google.maps.LatLng(48.77067,13.84075) );	points.push( new google.maps.LatLng(48.52206,13.7254) );	points.push( new google.maps.LatLng(48.5657,13.45623) );	points.push( new google.maps.LatLng(48.29233,13.26672) );	points.push( new google.maps.LatLng(48.13126,12.76135) );	points.push( new google.maps.LatLng(47.85003,13.00305) );	points.push( new google.maps.LatLng(47.72454,12.89868) );	points.push( new google.maps.LatLng(47.63393,13.08819) );	points.push( new google.maps.LatLng(47.47266,13.01678) );	points.push( new google.maps.LatLng(47.57096,12.79156) );	points.push( new google.maps.LatLng(47.67093,12.76684) );	points.push( new google.maps.LatLng(47.63948,12.55535) );
	points.push( new google.maps.LatLng(47.74486,12.25872) );	points.push( new google.maps.LatLng(47.62838,12.19006) );	points.push( new google.maps.LatLng(47.58578,11.60778) );	points.push( new google.maps.LatLng(47.50978,11.43749) );	points.push( new google.maps.LatLng(47.40764,11.11889) );	points.push( new google.maps.LatLng(47.52832,10.87994) );	points.push( new google.maps.LatLng(47.55428,10.4652) );	points.push( new google.maps.LatLng(47.44109,10.4707) );	points.push( new google.maps.LatLng(47.27177,10.17956) );	points.push( new google.maps.LatLng(47.37417,10.22351) );	points.push( new google.maps.LatLng(47.36859,10.10266) );	points.push( new google.maps.LatLng(47.4578,10.09167) );	points.push( new google.maps.LatLng(47.5376,9.95983) );	        points.push( new google.maps.LatLng(47.58764,9.78405) );	points.push( new google.maps.LatLng(47.52461,9.70166) );	points.push( new google.maps.LatLng(47.5005,9.56158) );	        points.push( new google.maps.LatLng(47.39091,9.66595) );	points.push( new google.maps.LatLng(47.30903,9.55609) );	points.push( new google.maps.LatLng(47.22702,9.55609) );	points.push( new google.maps.LatLng(47.13181,9.62475) );
	points.push( new google.maps.LatLng(47.05889,9.60278) ); 	points.push( new google.maps.LatLng(47.01584,9.87194) );	points.push( new google.maps.LatLng(46.84516,10.08892) );	points.push( new google.maps.LatLng(46.99149,10.38006) );	points.push( new google.maps.LatLng(46.86019,10.45971) );	points.push( new google.maps.LatLng(46.87521,10.68218) );	points.push( new google.maps.LatLng(46.79441,10.73162) );	points.push( new google.maps.LatLng(46.76808,11.00354) );

	austriaPoly = new google.maps.Polygon(points,"#D8006A", 2, 1, '#D8006A',.2);
    map.addOverlay(austriaPoly) ;
    inAustria = austriaPoly.getBounds();

    google.maps.Event.addListener(map, "zoomend", function () {
        map.removeOverlay(austriaPoly);
        if(map.getZoom() < 14){
            close_window();
        } else {
            if(aktivMarker) {
                currentBound = map.getBounds();
                if(currentBound.contains(aktivMarker.getLatLng()))
                    google.maps.Event.trigger(aktivMarker, 'click');
            }
        }
    });

    var mt = map.getMapTypes();
      // setzen der maximalen zommstufen
      for (var i=0; i<mt.length; i++) {
        mt[i].getMinimumResolution = function() {return 6;}
        mt[i].getMaximumResolution = function() {return 16;}
      }

    mngr = new MarkerManager(map);

    // erzeuge icons
    window.setTimeout(genIcons, 0);
    getIniData();
}

function getIniData() {
    var urlParams = window.location.search.replace('?', '');
    var valPairs = urlParams.split('&');
    var makeShow = 0;
    for(var vP=0; vP < valPairs.length; vP++) {
        var nVal = valPairs[vP].split('=');
        switch(nVal[0].toString()) {
            case 'type':
                for(var i = 0; i <$('type').options.length; i++) {
                   if($('type').options[i].value.toString() == nVal[1].toString())
                       $('type').selectedIndex = i;
               }
               break;
           case 'ort':
               $('searchFieldOrt').value = nVal[1];
               makeShow = 1;
               break;
           case 'plz':
               $('searchFieldPLZ').value = nVal[1];
               makeShow = 1;
               break;
           case 'str':
               $('searchFieldStr').value = nVal[1];
               makeShow = 1;
               break;
        }
    }
    if(makeShow)
        showAddress();
}

function genIcons() {

    icon = new google.maps.Icon();
    icon.image = pfadData+'image/T_gif.gif';
    icon.shadow = pfadData+'image/shadow.png';
    icon.shadowSize = new google.maps.Size(50,29);
    icon.iconSize = new google.maps.Size(42,58);
    icon.iconAnchor = new google.maps.Point(20,58);
    icon.infoWindowAnchor = new google.maps.Point(21,0);
    //Event.observe(icon,'click', function () {alert('hi');});
    letter[1] = icon;
    showLetter[1] = pfadData+'image/listT.gif';


    icon = new google.maps.Icon();
    icon.image = pfadData+'image/BP_gif.gif';
    icon.shadow = pfadData+'image/shadow.png';
    icon.shadowSize = new google.maps.Size(50,29);
    icon.iconSize = new google.maps.Size(43,37);
    icon.iconAnchor = new google.maps.Point(20,37);
    icon.infoWindowAnchor  = new google.maps.Point(20,0);
    letter[2] = icon;
    showLetter[2] = pfadData+'image/listBP.gif';


    icon = new google.maps.Icon();
    icon.image = pfadData+'image/EP_gif.gif';
    icon.shadow = pfadData+'image/shadow.png';
    icon.shadowSize = new google.maps.Size(50,29);
    icon.iconSize = new google.maps.Size(43,37);
    icon.iconAnchor = new google.maps.Point(20,37);
    icon.infoWindowAnchor  = new google.maps.Point(20,0);
    letter[3] = icon;
    showLetter[3] = pfadData+'image/listEP.gif';

    icon = new google.maps.Icon();
    icon.image = pfadData+'image/GO_gif.gif';
    icon.shadow = pfadData+'image/shadow.png';
    icon.shadowSize = new google.maps.Size(50,29);
    icon.iconSize = new google.maps.Size(43,37);
    icon.iconAnchor = new google.maps.Point(20,37);
    icon.infoWindowAnchor  = new google.maps.Point(21,0);
    letter[4] = icon;
    showLetter[4] = pfadData+'image/listGO.gif';

    }

var markerStart = 0,
    startZIndex = 100;

function createMarker(posn, title, mID, tID) {
      markerStart++;
      var marker = new google.maps.Marker(posn,letter[tID]);
      marker.tabContent = new Object();
      marker.tabContent.address = title[0];
      marker.tabContent.services = title[1];
      marker.tabContent.info = title[2];
      marker.tabContent.routeAdr = title[3];
      marker.tabContent.type = tID;
      marker.cssIndex = markerStart;
      google.maps.Event.addListener(marker, "click", function() {
	      map.panTo(marker.getLatLng());
          $('bodyElm').scrollTo();

          if(routeWnd) {
            routeWnd.close();
          }

          new Effect.BlindUp('printRouteDiv', {duration: 1});
          gdir.clear();

	      if(map.getZoom() < 14)
	       map.setZoom(zoomSearch);

	      show_custom_info_window(marker);
	      makeResultClear();

	      if($('location_'+mID)) {
		      $('location_'+mID).onmouseover = function () {};
	          Element.removeClassName('location_'+mID, 'hover');
	          Element.addClassName('location_'+mID, 'activResult');
	          }

          aktivMarker = marker;
          toAdress = marker.tabContent.routeAdr;
          offenAdress =marker.tabContent.services;

          if($('mtgt_unnamed_'+marker.cssIndex))
            $('mtgt_unnamed_'+marker.cssIndex).style.zIndex = startZIndex;

	      startZIndex++;
	  });
      mngr.addMarker(marker, 6,17);
      return marker;
    }

function showAddress() {

    mngr.clearMarkers();
    map.clearOverlays();

    if(routeWnd) {
        routeWnd.close();
    }

    startList = 0;
    $('backChar').hide();

    $('resultDiv').hide();
    $('loading').show();
    $('resEntries').update('');

    var street = $('searchFieldStr').value;
    var PLZ = $('searchFieldPLZ').value;
    var ort = $('searchFieldOrt').value;

    if(street == '' && PLZ == '' && ort == ''){
        $('resultDiv').show();
        $('results').show();
        $('loading').hide();
        $('resEntries').update('Keine Felder ausgef&uuml;llt!');
        return false;
    }

    $('resultDiv').show();

    if(ort != '' && ort.toLowerCase() != 'wien'){
        address = street+', '+ort+', Austria';
    } else {
        address = street+', '+ort+' '+PLZ+', Austria';
    }
    fromAddress = '';

    if(PLZ != ''){
        fromAddress += ' '+PLZ+' ';
    }

    if(ort != '')
        fromAddress += ort;

    if(street != '')
        if(fromAddress != '')
            fromAddress += ', ';
        fromAddress += street;


    if(address != '') {

	    geocoder = new google.maps.ClientGeocoder();
	        if (geocoder) {
	            geocoder.getLatLng(
	                address,
	                function(point) {
	                    if (point) {
	                           if(inAustria.containsLatLng(point)) {
								   if($('type').value == '0'){
										$('resultTmobileDiv').show();
									}
	                               getFilData(point);
        	                       centerSelf =  point;
        		                   map.setCenter(point, 14);
        		                   zoomSearch = 14;

        		                   var persMarker = new google.maps.Marker(point, {zIndexProcess:function () {return 99}});
        		                   google.maps.Event.addListener(persMarker, 'click', function() {
        		                                                                    persMarker.openInfoWindowHtml('Ihr Standort');
        		                                                                    });
        		                   map.addOverlay(persMarker);
        	                       subAdress = point;
	                           } else {
                                    $('resEntries').update('<div style="padding: 10px;">Adresse nicht gefunden</div>');
        	                        $('results').show();
        	                        $('loading').hide();
        	                        $('naviBackFrwd').hide();
	                           }
	                    } else {
	                       $('resEntries').update('<div style="padding: 10px;">Ihre Adresse konnte nicht gefunden werden!</div>');
	                       $('results').show();
	                       $('loading').hide();
	                       $('naviBackFrwd').hide();
	                    }
	                }
	            );
	        }
      } else {
        $('resEntries').update('<div style="padding: 10px;">Es muss zumindest die PLZ aufgef&uuml;llt werden!</div>');
      }
      return;
}

function getFilData(pointData) {
    var searchUrl = pfadData+'getfildata/getFilData.php?lat=' + pointData.lat() + '&lng=' + pointData.lng()+'&filArt='+$('type').value;
    markers = [];
    google.maps.DownloadUrl(searchUrl, function(data) {
        eval(data);
        nurTmobileShops();
        searchLocationsNear();
        
    });

}

function planRoute (lat, lng) {

    close_window();
    gdir.clear();

    new Effect.BlindDown('printRouteDiv', {duration: 1});

    toPoint = new google.maps.LatLng(lat, lng)

    //gDIRArray = [centerSelf, toPoint];
    gdir.loadFromWaypoints(new Array(centerSelf, toPoint), {getSteps:true});
    google.maps.Event.addListener(gdir,"load", function() {
           routeAnz = gdir.getNumRoutes();

    });
}

function nurTmobileShops () {

    var go = true;
    var sidebarTm = $('resEntriesTm');
    sidebarTm.update('');
    sidebarTm.show('');
    $('resultsTm').show();
    filArt = $('type').value;

    var lastLat = 0, versatz = 0.0008;

    $('tMobileMag').update('<strong>Weitere Shops und Partner</strong>');

    if(filArt != '0') {
        $('resultTmobileDiv').hide();
        $('tMobileMag').update('<strong>Suchergebnis</strong>');
        go = false;
    }
    
    if(go) {
        for (var i = 0; i < tmomarkers.length; i++) {

            var newIdx = i+1000;

           var xmlLat = parseFloat(tmomarkers[i].pos[0]);
           var xmlLng = parseFloat(tmomarkers[i].pos[1]);
           
           if(xmlLat == lastLat)
               xmlLat += versatz;

           
           
           resultsTm[newIdx] = new Array;
           resultsTm[newIdx][0] = '<strong>'+tmomarkers[i].name+'</strong><br>'+tmomarkers[i].adr+'<br>Tel: '+tmomarkers[i].tel+'<br><br><p><a href=\'#\' onclick=\'planRoute('+xmlLat+','+xmlLng+'); return false;\'>Route planen</a></p>';
           resultsTm[newIdx][1] = tmomarkers[i].offen;
           resultsTm[newIdx][2] = tmomarkers[i].info;
           resultsTm[newIdx][3] = tmomarkers[i].adrRoute;


           if(i < 3) {

               var beschreibung = '<table width="275" class="partner'+tmomarkers[i].type+'">'+
                                '<tr>'+
                                  '<td width="14">&nbsp;</td>'+
                                  '<td class="letter" valign="top"><img src="'+showLetter[tmomarkers[i].type]+'"></td>'+
                                  '<td class="adress"><b>'+tmomarkers[i].name+'</b><br>'+tmomarkers[i].adr+'<br>Tel: '+tmomarkers[i].tel+'<br><br></td>'+
                                  '<td class="dst" valign="top">'+tmomarkers[i].dist+' km</td>'+
                                  '<td width="14">&nbsp;</td>'+
                                '</tr>'+
                              '</table>';

               if(i < 2)
                   beschreibung += '<hr class="trenner">';

                   var addDiv = createSidebarEntryTM(beschreibung, xmlLat, xmlLng, newIdx);
                   sidebarTm.appendChild(addDiv);
                   new Effect.BlindDown(addDiv, {duration: .5, queue:'end'});
           } else {
                var point = new google.maps.LatLng(xmlLat, xmlLng);
                //posn, title, mID, tID
                createMarker(point, resultsTm[newIdx], newIdx, 1);
           }

           
           
          lastLat = xmlLat;
          lastLng = xmlLng;
          

       }
    }
}

function searchLocationsNear() {
        
       close_window();

       var sidebar = $('resEntries');
           sidebar.update('');
           sidebar.show();
		   
       $('results').show();
		   
       var lastLat = 0,
           versatz = 0.0008;

	   filArt = $('type').value;

           var anzMarker = markers.length;
           if (anzMarker == 0) {
             sidebar.update('Keine Eintr&auml;ge gefunden!');
             $('loading').hide();
             $('naviBackFrwd').hide();
             sidebar.show();
             return false;
           }

           if(centerSelf) {
               var persMarker = new google.maps.Marker(centerSelf, {zIndexProcess:function () {return 99}});
               map.addOverlay(persMarker);
           }

           sidebar.innerHTML = '';

           if(startList < anzMarker) {

    	       for (var i = 0; i < anzMarker; i++) {

    	           if(i >= anzMarker) {
    	               $('frwdChar').hide();
    	               break;
    	           }

    	           var xmlLat = parseFloat(markers[i].pos[0]);
                   var xmlLng = parseFloat(markers[i].pos[1]);

                   if(xmlLat == lastLat)
                       xmlLat += versatz;

                   results[i] = new Array;
                   results[i][0] = '<strong>'+markers[i].name+'</strong><br>'+markers[i].adr+'<br>Tel: '+markers[i].tel+'<br><br><p><a href=\'#\' onclick=\'planRoute('+xmlLat+','+xmlLng+'); return false;\'>Route planen</a></p>';
                   results[i][1] = markers[i].offen;
                   results[i][2] = markers[i].info;
                   results[i][3] = markers[i].adrRoute;


                   var varTreffer = parseInt($('treffer').value)-1;
                   var end = (parseInt(startList)+parseInt(varTreffer));


                   if(i >= startList && i <= end) {
                       
                       var beschreibung = '<table width="275" class="partner'+markers[i].type+'">'+
                                        '<tr>'+
                                          '<td width="14">&nbsp;</td>'+
                                          '<td class="letter" valign="top"><img src="'+showLetter[markers[i].type]+'"></td>'+
                                          '<td class="adress"><b>'+markers[i].name+'</b><br>'+markers[i].adr+'<br>Tel: '+markers[i].tel+'<br><br></td>'+
                                          '<td class="dst" valign="top">'+markers[i].dist+' km</td>'+
                                          '<td width="14">&nbsp;</td>'+
                                        '</tr>'+
                                      '</table>';

                       if((i-startList) != varTreffer)
                           beschreibung += '<hr class="trenner">';
                            var addDiv = createSidebarEntry(beschreibung, xmlLat, xmlLng, i, markers[i].type);
                            sidebar.appendChild(addDiv);
    		           new Effect.BlindDown(addDiv, {duration: .5, queue:'end'});
                   } else {
                       var point = new google.maps.LatLng(xmlLat, xmlLng);
    	               createMarker(point, results[i], i, markers[i].type);
                   }

                  lastLat = xmlLat;
                  lastLng = xmlLng;
    	       }
    	       $('naviBackFrwd').show();

           }
     $('loading').hide();
     mngr.refresh();
     return true;
   }

function printRoute() {


    if(routeAnz) {
        routeWnd = window.open("popRoute/printRoute.html", "RouteDrucken", "width=800,height=500,scrollbars=yes,resizable=yes");
        if (routeWnd.opener == null) {
            routeWnd.opener = window;
        }

        var insertText = '';

        insertText += '<table width="100%" cellpadding="0" cellspacing="0">';
        insertText += '<tr>'+
                        '<td width="20">&nbsp;</td>'+
                        '<td colspan="3"><h3>Routenbeschreibung</h3><br><br></td>'+
                        '<td width="20">&nbsp;</td>'+
                      '</tr>';
        insertText += '<tr>'+
                        '<td width="20">&nbsp;</td>'+
                        '<td colspan="3"><b>Standort</b>:<br>'+fromAddress+'<br><br></td>'+
                        '<td width="20">&nbsp;</td>'+
                      '</tr>';
        insertText += '<tr><td>&nbsp;</td>'+
                          '<td><b>Zielort</b>:<br>'+toAdress+'<br><br></td>'+
                          '<td colspan="2"><div align="right"><div style="width:95px;text-align:left;"><b>&Ouml;ffnungszeiten</b>:</div>'+offenAdress+'</div></td>'+
                          '<td>&nbsp;</td>'+
                      '</tr>';
                      //<br>'+offenAdress+'
        insertText += '<tr><td colspan="5"><div style="border-bottom: 1px solid #000000;"></td></tr>';
        insertText += '<tr><td>&nbsp;</td>'+
                          '<td colspan="3"><p><b>'+gdir.getDistance().html+' (Fahrtstrecke ca. '+gdir.getDuration().html+')</b></p></td>'+
                          '<td>&nbsp;</td>'+
                      '</tr>';

        for(var i=0; i<routeAnz; i++) {
            var steps = gdir.getRoute(i).getNumSteps();
            for(var e=0; e < steps; e++) {

                var zeit = gdir.getRoute(i).getStep(e).getDuration().html.replace('Minuten', 'Min.');
                zeit = zeit.replace('Minute.', 'Min.');
                zeit = zeit.replace('Sekunden', 'Sek.');
                zeit = zeit.replace('Sekunde', 'Sek.');

                insertText += '<tr>'+
                                '<td style="padding: 2px 0;">&nbsp;</td>'+
                                '<td style="padding: 2px 0;" width="350">'+gdir.getRoute(i).getStep(e).getDescriptionHtml()+'</td>'+
                                '<td align="right" style="padding: 2px 0;"><b>'+gdir.getRoute(i).getStep(e).getDistance().html+'</b></td>'+
                                '<td align="right" style="padding: 2px 0;"><b>'+zeit+'</b></td>'+
                                '<td style="padding: 2px 0;">&nbsp;</td>'+
                            '</tr>';
            }
        }
        insertText += '<tr><td colspan="5">&nbsp;</td></tr>'+
                      '<tr><td colspan="5"><div style="border-bottom: 1px solid #000000;"></td></tr>'+
                      '<tr><td colspan="5">&nbsp;</td></tr>'+
                       '<tr>'+
                        '<td>&nbsp;</td>'+
                        '<td colspan="3">'+
                            '<table width="100%"><tr><td><a href="#" class="lnk" onclick="window.close();return false;" style="color:#000000;text-decoration:none;"><img src="../image/bubble/icon_close_gif.gif" alt="schlie&szlig;en"> Fenster schlie&szlig;en</a></td><td align="right"><a href="#" class="lnk" onclick="window.print();return false;" style="color:#000000;text-decoration:none;"><img src="http://www.t-mobile.at/_proving_grounds/Shop_Finder/image/Druckversion.gif" alt="print">&nbsp;Beschreibung&nbsp;drucken</a></td></tr></table>'+
                        '</td>'+
                        '<td>&nbsp;</td>'+
                    '</tr>'+
                    '</table>';

        $('routDetails').update(insertText);
    }
}


function getMore(varType) {

    if(varType == '1') {
        startList += parseInt($('treffer').value);
        $('backChar').show();
    } else {
        startList -= parseInt($('treffer').value);
        if(startList <= 0){
            startList = 0;
            $('backChar').hide();
        }
    }

    new Effect.BlindUp('results', {duration: 0.5, afterFinish:function (o) {
                                                                $('loading').show();
                                                                searchLocationsNear();
                                                              }
    });

}

function makeResultClear() {
    var divElms = $('resEntries').getElementsByTagName('div');
    for(var i=0; i <divElms.length; i++) {
        Element.removeClassName(divElms[i], 'activResult');
        divElms[i].onmouseover = function(){ Element.addClassName(this, 'hover') }
        divElms[i].onmouseout = function(){ Element.removeClassName(this, 'hover') }
    }
    var divElms = $('resEntriesTm').getElementsByTagName('div');
    for(var i=0; i <divElms.length; i++) {
        Element.removeClassName(divElms[i], 'activResult');
        divElms[i].onmouseover = function(){ Element.addClassName(this, 'hover') }
        divElms[i].onmouseout = function(){ Element.removeClassName(this, 'hover') }
    }
}

function createSidebarEntry(name, lat, lng, mID, tID) {
      var div = document.createElement('div');
      div.setAttribute("id", 'location_'+mID);
      div.setAttribute("class", 'locationList');
      div.innerHTML = name;
      div.onmouseover = function(){ Element.addClassName(this, 'hover') }
      div.onmouseout = function(){ Element.removeClassName(this, 'hover') }
      div.style.cursor = 'pointer';
      div.style.display = 'none';
      var point = new google.maps.LatLng(lat, lng);
      var marker = createMarker(point, results[mID], mID, tID);
      google.maps.Event.addDomListener(div, 'click', function() {
        google.maps.Event.trigger(marker, 'click');
        });
      return div;
    }

function createSidebarEntryTM(name, lat, lng, mID) {
      var div = document.createElement('div');
      div.setAttribute("id", 'location_'+mID);
      div.setAttribute("class", 'locationList');
      div.innerHTML = name;
      div.onmouseover = function(){ Element.addClassName(this, 'hover') }
      div.onmouseout = function(){ Element.removeClassName(this, 'hover') }
      div.style.cursor = 'pointer';
      div.style.display = 'none';
      var point = new google.maps.LatLng(lat, lng);
      var marker = createMarker(point, resultsTm[mID], mID, 1);
      google.maps.Event.addDomListener(div, 'click', function() {
        google.maps.Event.trigger(marker, 'click');
        });
      return div;
    }

function handleErrors(){
       if (gdir.getStatus().code == G_GEO_UNKNOWN_ADDRESS)
         alert("No corresponding geographic location could be found for one of the specified addresses. This may be due to the fact that the address is relatively new, or it may be incorrect.");
       else if (gdir.getStatus().code == G_GEO_SERVER_ERROR)
         alert("A geocoding or directions request could not be successfully processed, yet the exact reason for the failure is not known.");

       else if (gdir.getStatus().code == G_GEO_MISSING_QUERY)
         alert("The HTTP q parameter was either missing or had no value. For geocoder requests, this means that an empty address was specified as input. For directions requests, this means that no query was specified in the input.");

       else if (gdir.getStatus().code == G_GEO_BAD_REQUEST)
         alert("A directions request could not be successfully parsed.");

       else alert("Unbekannter Fehler, probieren Sie es sp�ter noch mal");

    }

function showAddSearch() {
    new Effect.toggle('addSearch','blind');
    return false;
    }

// cutom window

function change_tab(element, type){
    var my_window = $('overlay');
    var my_tab = $('overlay_tab');
    var alltabs = my_window.getElementsByTagName('ul')[0];

    Element.removeClassName(alltabs,'tabs2');
    Element.removeClassName(alltabs,'tabs3');
    Element.removeClassName(alltabs,'tabs');

    switch(type) {
        case 'services':
	        Element.addClassName(alltabs,'tabs2');
	        my_tab.innerHTML = my_window.marker.tabContent.services;
	        activeTab = 'tabs2';
        break;
        case 'info':
            Element.addClassName(alltabs,'tabs3');
            my_tab.innerHTML = my_window.marker.tabContent.info;
            activeTab = 'tabs3';
        break;
        case 'address':
            Element.addClassName(alltabs,'tabs');
            my_tab.innerHTML = my_window.marker.tabContent.address;
            activeTab = 'tabs1';
        break;
    }
    position_window(my_window, my_window.marker);

    return false;
}

function close_window(){
    if($('overlay'))
        $('overlay').hide();
    aktivMarker = false;
    return false;
}

function show_custom_info_window(marker){
    activeTab = 'tabs';

    if (!$('overlay')){ // erzeugt das overlay
        var new_obj = document.createElement("div");
        new_obj.style.display = 'none';

        // inhalt kopieren aus dem tmp overlay
        new_obj.innerHTML = $('overlay_temp').innerHTML;
        new_obj.getElementsByTagName('div')[0].id = 'overlay_tab';
        new_obj.id = 'overlay';
        document.body.appendChild(new_obj);
    }

    var my_window = $('overlay');

    // Attach the marker
    my_window.marker = marker;

    // make sure the first tab is in front
    var alltabs = my_window.getElementsByTagName('ul')[0];
    Element.removeClassName(alltabs,'tabs2');
    Element.removeClassName(alltabs,'tabs3');
    Element.addClassName(alltabs,'tabs');


    // ihnalt einf�gen
    var my_tab = $('overlay_tab');
    my_tab.innerHTML = marker.tabContent.address;

    // auf der karte plazieren
    map.getPane(G_MAP_MARKER_PANE).appendChild(my_window);
    my_window.show();

    position_window(my_window, marker);

}

function position_window(my_window, marker){
    var map_point = map.fromLatLngToDivPixel(marker.getPoint());
    // pos von info fenster
    var horiz_loc = parseInt(map_point.x) - 90;
        my_window.style.left = horiz_loc + "px";
    // unterschiedliche pos f�r unterschiedlichen marker h�hen
    if(marker.tabContent.type != 1){
	    var vert_loc = parseInt(map_point.y) - my_window.offsetHeight - 20;
            my_window.style.top = vert_loc  + "px";
	} else {
	   var vert_loc = parseInt(map_point.y) - my_window.offsetHeight - 40;
            my_window.style.top = vert_loc  + "px";
	}
    // damit das fenster im richtigen berich bleibt
    var diff = 0;
        switch(map.getZoom()) {
            case 14:
                diff = 0.004;
            break;
            case 15:
                diff = 0.002;
            break;
            case 16:
                diff = 0.001;
            break;
        }
        map.panTo( new google.maps.LatLng( marker.getLatLng().lat()+diff, marker.getLatLng().lng() ) );

}

google.setOnLoadCallback(initialize);

Event.observe(window, 'load', function() {

    //$('naviBackFrwd').hide();
    //$('results').hide();
    //$('loading').hide();
    //$('resultDiv').hide();
    //$('backChar').hide();

	Event.observe(document, 'keypress', function(e){
		var code;
		if (!e) var e = window.event;
		if (e.keyCode) code = e.keyCode;
		else if (e.which) code = e.which;

		if(code == 13) {
		  showAddress();
		}
		return false;
    });

    var img = ['../image/bubble/bubble_top.png', '../image/bubble/bubble_top-2.png', '../image/bubble/bubble_top-3.png'];
    toLoad = [];

    for(var i=0; i < img.length; i++) {
        toLoad[i] = new Image();
        toLoad[i].src = img[i];
    }

return false;
});

function MarkerManager(map, opt_opts) {
  var me = this;
  me.map_ = map;
  me.mapZoom_ = map.getZoom();
  me.projection_ = map.getCurrentMapType().getProjection();

  opt_opts = opt_opts || {};
  me.tileSize_ = MarkerManager.DEFAULT_TILE_SIZE_;

  var maxZoom = MarkerManager.DEFAULT_MAX_ZOOM_;
  if(opt_opts.maxZoom != undefined) {
    maxZoom = opt_opts.maxZoom;
  }
  me.maxZoom_ = maxZoom;

  me.trackMarkers_ = opt_opts.trackMarkers;

  var padding;
  if (typeof opt_opts.borderPadding == "number") {
    padding = opt_opts.borderPadding;
  } else {
    padding = MarkerManager.DEFAULT_BORDER_PADDING_;
  }
  // The padding in pixels beyond the viewport, where we will pre-load markers.
  me.swPadding_ = new GSize(-padding, padding);
  me.nePadding_ = new GSize(padding, -padding);
  me.borderPadding_ = padding;

  me.gridWidth_ = [];

  me.grid_ = [];
  me.grid_[maxZoom] = [];
  me.numMarkers_ = [];
  me.numMarkers_[maxZoom] = 0;

  GEvent.bind(map, "moveend", me, me.onMapMoveEnd_);

  // NOTE: These two closures provide easy access to the map.
  // They are used as callbacks, not as methods.
  me.removeOverlay_ = function(marker) {
    map.removeOverlay(marker);
    me.shownMarkers_--;
  };
  me.addOverlay_ = function(marker) {
    map.addOverlay(marker);
    me.shownMarkers_++;
  };

  me.resetManager_();
  me.shownMarkers_ = 0;

  me.shownBounds_ = me.getMapGridBounds_();
};

// Static constants:
MarkerManager.DEFAULT_TILE_SIZE_ = 1024;
MarkerManager.DEFAULT_MAX_ZOOM_ = 17;
MarkerManager.DEFAULT_BORDER_PADDING_ = 100;
MarkerManager.MERCATOR_ZOOM_LEVEL_ZERO_RANGE = 256;


/**
 * Initializes MarkerManager arrays for all zoom levels
 * Called by constructor and by clearAllMarkers
 */
MarkerManager.prototype.resetManager_ = function() {
  var me = this;
  var mapWidth = MarkerManager.MERCATOR_ZOOM_LEVEL_ZERO_RANGE;
  for (var zoom = 0; zoom <= me.maxZoom_; ++zoom) {
    me.grid_[zoom] = [];
    me.numMarkers_[zoom] = 0;
    me.gridWidth_[zoom] = Math.ceil(mapWidth/me.tileSize_);
    mapWidth <<= 1;
  }
};

/**
 * Removes all currently displayed markers
 * and calls resetManager to clear arrays
 */
MarkerManager.prototype.clearMarkers = function() {
  var me = this;
  me.processAll_(me.shownBounds_, me.removeOverlay_);
  me.resetManager_();
};


/**
 * Gets the tile coordinate for a given latlng point.
 *
 * @param {LatLng} latlng The geographical point.
 * @param {Number} zoom The zoom level.
 * @param {GSize} padding The padding used to shift the pixel coordinate.
 *               Used for expanding a bounds to include an extra padding
 *               of pixels surrounding the bounds.
 * @return {GPoint} The point in tile coordinates.
 *
 */
MarkerManager.prototype.getTilePoint_ = function(latlng, zoom, padding) {
  var pixelPoint = this.projection_.fromLatLngToPixel(latlng, zoom);
  return new GPoint(
      Math.floor((pixelPoint.x + padding.width) / this.tileSize_),
      Math.floor((pixelPoint.y + padding.height) / this.tileSize_));
};


/**
 * Finds the appropriate place to add the marker to the grid.
 * Optimized for speed; does not actually add the marker to the map.
 * Designed for batch-processing thousands of markers.
 *
 * @param {Marker} marker The marker to add.
 * @param {Number} minZoom The minimum zoom for displaying the marker.
 * @param {Number} maxZoom The maximum zoom for displaying the marker.
 */
MarkerManager.prototype.addMarkerBatch_ = function(marker, minZoom, maxZoom) {
  var mPoint = marker.getPoint();
  // Tracking markers is expensive, so we do this only if the
  // user explicitly requested it when creating marker manager.
  if (this.trackMarkers_) {
    GEvent.bind(marker, "changed", this, this.onMarkerMoved_);
  }

  var gridPoint = this.getTilePoint_(mPoint, maxZoom, GSize.ZERO);

  for (var zoom = maxZoom; zoom >= minZoom; zoom--) {
    var cell = this.getGridCellCreate_(gridPoint.x, gridPoint.y, zoom);
    cell.push(marker);

    gridPoint.x = gridPoint.x >> 1;
    gridPoint.y = gridPoint.y >> 1;
  }
};


/**
 * Returns whether or not the given point is visible in the shown bounds. This
 * is a helper method that takes care of the corner case, when shownBounds have
 * negative minX value.
 *
 * @param {Point} point a point on a grid.
 * @return {Boolean} Whether or not the given point is visible in the currently
 * shown bounds.
 */
MarkerManager.prototype.isGridPointVisible_ = function(point) {
  var me = this;
  var vertical = me.shownBounds_.minY <= point.y &&
      point.y <= me.shownBounds_.maxY;
  var minX = me.shownBounds_.minX;
  var horizontal = minX <= point.x && point.x <= me.shownBounds_.maxX;
  if (!horizontal && minX < 0) {
    // Shifts the negative part of the rectangle. As point.x is always less
    // than grid width, only test shifted minX .. 0 part of the shown bounds.
    var width = me.gridWidth_[me.shownBounds_.z];
    horizontal = minX + width <= point.x && point.x <= width - 1;
  }
  return vertical && horizontal;
}


/**
 * Reacts to a notification from a marker that it has moved to a new location.
 * It scans the grid all all zoom levels and moves the marker from the old grid
 * location to a new grid location.
 *
 * @param {Marker} marker The marker that moved.
 * @param {LatLng} oldPoint The old position of the marker.
 * @param {LatLng} newPoint The new position of the marker.
 */
MarkerManager.prototype.onMarkerMoved_ = function(marker, oldPoint, newPoint) {
  // NOTE: We do not know the minimum or maximum zoom the marker was
  // added at, so we start at the absolute maximum. Whenever we successfully
  // remove a marker at a given zoom, we add it at the new grid coordinates.
  var me = this;
  var zoom = me.maxZoom_;
  var changed = false;
  var oldGrid = me.getTilePoint_(oldPoint, zoom, GSize.ZERO);
  var newGrid = me.getTilePoint_(newPoint, zoom, GSize.ZERO);
  while (zoom >= 0 && (oldGrid.x != newGrid.x || oldGrid.y != newGrid.y)) {
    var cell = me.getGridCellNoCreate_(oldGrid.x, oldGrid.y, zoom);
    if (cell) {
      if (me.removeFromArray(cell, marker)) {
        me.getGridCellCreate_(newGrid.x, newGrid.y, zoom).push(marker);
      }
    }
    // For the current zoom we also need to update the map. Markers that no
    // longer are visible are removed from the map. Markers that moved into
    // the shown bounds are added to the map. This also lets us keep the count
    // of visible markers up to date.
    if (zoom == me.mapZoom_) {
      if (me.isGridPointVisible_(oldGrid)) {
        if (!me.isGridPointVisible_(newGrid)) {
          me.removeOverlay_(marker);
          changed = true;
        }
      } else {
        if (me.isGridPointVisible_(newGrid)) {
          me.addOverlay_(marker);
          changed = true;
        }
      }
    }
    oldGrid.x = oldGrid.x >> 1;
    oldGrid.y = oldGrid.y >> 1;
    newGrid.x = newGrid.x >> 1;
    newGrid.y = newGrid.y >> 1;
    --zoom;
  }
  if (changed) {
    me.notifyListeners_();
  }
};


/**
 * Searches at every zoom level to find grid cell
 * that marker would be in, removes from that array if found.
 * Also removes marker with removeOverlay if visible.
 * @param {GMarker} marker The marker to delete.
 */
MarkerManager.prototype.removeMarker = function(marker) {
  var me = this;
  var zoom = me.maxZoom_;
  var changed = false;
  var point = marker.getPoint();
  var grid = me.getTilePoint_(point, zoom, GSize.ZERO);
  while (zoom >= 0) {
    var cell = me.getGridCellNoCreate_(grid.x, grid.y, zoom);

    if (cell) {
      me.removeFromArray(cell, marker);
    }
    // For the current zoom we also need to update the map. Markers that no
    // longer are visible are removed from the map. This also lets us keep the count
    // of visible markers up to date.
    if (zoom == me.mapZoom_) {
      if (me.isGridPointVisible_(grid)) {
          me.removeOverlay_(marker);
          changed = true;
      }
    }
    grid.x = grid.x >> 1;
    grid.y = grid.y >> 1;
    --zoom;
  }
  if (changed) {
    me.notifyListeners_();
  }
};


/**
 * Add many markers at once.
 * Does not actually update the map, just the internal grid.
 *
 * @param {Array of Marker} markers The markers to add.
 * @param {Number} minZoom The minimum zoom level to display the markers.
 * @param {Number} opt_maxZoom The maximum zoom level to display the markers.
 */
MarkerManager.prototype.addMarkers = function(markers, minZoom, opt_maxZoom) {
  var maxZoom = this.getOptMaxZoom_(opt_maxZoom);
  for (var i = markers.length - 1; i >= 0; i--) {
    this.addMarkerBatch_(markers[i], minZoom, maxZoom);
  }

  this.numMarkers_[minZoom] += markers.length;
};


/**
 * Returns the value of the optional maximum zoom. This method is defined so
 * that we have just one place where optional maximum zoom is calculated.
 *
 * @param {Number} opt_maxZoom The optinal maximum zoom.
 * @return The maximum zoom.
 */
MarkerManager.prototype.getOptMaxZoom_ = function(opt_maxZoom) {
  return opt_maxZoom != undefined ? opt_maxZoom : this.maxZoom_;
}


/**
 * Calculates the total number of markers potentially visible at a given
 * zoom level.
 *
 * @param {Number} zoom The zoom level to check.
 */
MarkerManager.prototype.getMarkerCount = function(zoom) {
  var total = 0;
  for (var z = 0; z <= zoom; z++) {
    total += this.numMarkers_[z];
  }
  return total;
};


/**
 * Add a single marker to the map.
 *
 * @param {Marker} marker The marker to add.
 * @param {Number} minZoom The minimum zoom level to display the marker.
 * @param {Number} opt_maxZoom The maximum zoom level to display the marker.
 */
MarkerManager.prototype.addMarker = function(marker, minZoom, opt_maxZoom) {
  var me = this;
  var maxZoom = this.getOptMaxZoom_(opt_maxZoom);
  me.addMarkerBatch_(marker, minZoom, maxZoom);
  var gridPoint = me.getTilePoint_(marker.getPoint(), me.mapZoom_, google.maps.Size.ZERO);
  if(me.isGridPointVisible_(gridPoint) &&
     minZoom <= me.shownBounds_.z &&
     me.shownBounds_.z <= maxZoom ) {
    me.addOverlay_(marker);
    me.notifyListeners_();
  }
  this.numMarkers_[minZoom]++;
};

/**
 * Returns true if this bounds (inclusively) contains the given point.
 * @param {Point} point  The point to test.
 * @return {Boolean} This Bounds contains the given Point.
 */
/*GBounds.prototype.containsPoint = function(point) {
  var outer = this;
  return (outer.minX <= point.x &&
          outer.maxX >= point.x &&
          outer.minY <= point.y &&
          outer.maxY >= point.y);
}*/

/**
 * Get a cell in the grid, creating it first if necessary.
 *
 * Optimization candidate
 *
 * @param {Number} x The x coordinate of the cell.
 * @param {Number} y The y coordinate of the cell.
 * @param {Number} z The z coordinate of the cell.
 * @return {Array} The cell in the array.
 */
MarkerManager.prototype.getGridCellCreate_ = function(x, y, z) {
  var grid = this.grid_[z];
  if (x < 0) {
    x += this.gridWidth_[z];
  }
  var gridCol = grid[x];
  if (!gridCol) {
    gridCol = grid[x] = [];
    return gridCol[y] = [];
  }
  var gridCell = gridCol[y];
  if (!gridCell) {
    return gridCol[y] = [];
  }
  return gridCell;
};


/**
 * Get a cell in the grid, returning undefined if it does not exist.
 *
 * NOTE: Optimized for speed -- otherwise could combine with getGridCellCreate_.
 *
 * @param {Number} x The x coordinate of the cell.
 * @param {Number} y The y coordinate of the cell.
 * @param {Number} z The z coordinate of the cell.
 * @return {Array} The cell in the array.
 */
MarkerManager.prototype.getGridCellNoCreate_ = function(x, y, z) {
  var grid = this.grid_[z];
  if (x < 0) {
    x += this.gridWidth_[z];
  }
  var gridCol = grid[x];
  return gridCol ? gridCol[y] : undefined;
};


/**
 * Turns at geographical bounds into a grid-space bounds.
 *
 * @param {LatLngBounds} bounds The geographical bounds.
 * @param {Number} zoom The zoom level of the bounds.
 * @param {GSize} swPadding The padding in pixels to extend beyond the
 * given bounds.
 * @param {GSize} nePadding The padding in pixels to extend beyond the
 * given bounds.
 * @return {GBounds} The bounds in grid space.
 */
MarkerManager.prototype.getGridBounds_ = function(bounds, zoom, swPadding,
                                                  nePadding) {
  zoom = Math.min(zoom, this.maxZoom_);

  var bl = bounds.getSouthWest();
  var tr = bounds.getNorthEast();
  var sw = this.getTilePoint_(bl, zoom, swPadding);
  var ne = this.getTilePoint_(tr, zoom, nePadding);
  var gw = this.gridWidth_[zoom];

  // Crossing the prime meridian requires correction of bounds.
  if (tr.lng() < bl.lng() || ne.x < sw.x) {
    sw.x -= gw;
  }
  if (ne.x - sw.x  + 1 >= gw) {
    // Computed grid bounds are larger than the world; truncate.
    sw.x = 0;
    ne.x = gw - 1;
  }
  var gridBounds = new GBounds([sw, ne]);
  gridBounds.z = zoom;
  return gridBounds;
};


/**
 * Gets the grid-space bounds for the current map viewport.
 *
 * @return {Bounds} The bounds in grid space.
 */
MarkerManager.prototype.getMapGridBounds_ = function() {
  var me = this;
  return me.getGridBounds_(me.map_.getBounds(), me.mapZoom_,
                           me.swPadding_, me.nePadding_);
};


/**
 * Event listener for map:movend.
 * NOTE: Use a timeout so that the user is not blocked
 * from moving the map.
 *
 */
MarkerManager.prototype.onMapMoveEnd_ = function() {
  var me = this;
  me.objectSetTimeout_(this, this.updateMarkers_, 0);
};


/**
 * Call a function or evaluate an expression after a specified number of
 * milliseconds.
 *
 * Equivalent to the standard window.setTimeout function, but the given
 * function executes as a method of this instance. So the function passed to
 * objectSetTimeout can contain references to this.
 *    objectSetTimeout(this, function() { alert(this.x) }, 1000);
 *
 * @param {Object} object  The target object.
 * @param {Function} command  The command to run.
 * @param {Number} milliseconds  The delay.
 * @return {Boolean}  Success.
 */
MarkerManager.prototype.objectSetTimeout_ = function(object, command, milliseconds) {
  return window.setTimeout(function() {
    command.call(object);
  }, milliseconds);
};


/**
 * Refresh forces the marker-manager into a good state.
 * <ol>
 *   <li>If never before initialized, shows all the markers.</li>
 *   <li>If previously initialized, removes and re-adds all markers.</li>
 * </ol>
 */
MarkerManager.prototype.refresh = function() {
  var me = this;
  if (me.shownMarkers_ > 0) {
    me.processAll_(me.shownBounds_, me.removeOverlay_);
  }
  me.processAll_(me.shownBounds_, me.addOverlay_);
  me.notifyListeners_();
};


/**
 * After the viewport may have changed, add or remove markers as needed.
 */
MarkerManager.prototype.updateMarkers_ = function() {
  var me = this;
  me.mapZoom_ = this.map_.getZoom();
  var newBounds = me.getMapGridBounds_();

  // If the move does not include new grid sections,
  // we have no work to do:
  if (newBounds.equals(me.shownBounds_) && newBounds.z == me.shownBounds_.z) {
    return;
  }

  if (newBounds.z != me.shownBounds_.z) {
    me.processAll_(me.shownBounds_, me.removeOverlay_);
    me.processAll_(newBounds, me.addOverlay_);
  } else {
    // Remove markers:
    me.rectangleDiff_(me.shownBounds_, newBounds, me.removeCellMarkers_);

    // Add markers:
    me.rectangleDiff_(newBounds, me.shownBounds_, me.addCellMarkers_);
  }
  me.shownBounds_ = newBounds;

  me.notifyListeners_();
};


/**
 * Notify listeners when the state of what is displayed changes.
 */
MarkerManager.prototype.notifyListeners_ = function() {
  google.maps.Event.trigger(this, "changed", this.shownBounds_, this.shownMarkers_);
};


/**
 * Process all markers in the bounds provided, using a callback.
 *
 * @param {Bounds} bounds The bounds in grid space.
 * @param {Function} callback The function to call for each marker.
 */
MarkerManager.prototype.processAll_ = function(bounds, callback) {
  for (var x = bounds.minX; x <= bounds.maxX; x++) {
    for (var y = bounds.minY; y <= bounds.maxY; y++) {
      this.processCellMarkers_(x, y,  bounds.z, callback);
    }
  }
};


/**
 * Process all markers in the grid cell, using a callback.
 *
 * @param {Number} x The x coordinate of the cell.
 * @param {Number} y The y coordinate of the cell.
 * @param {Number} z The z coordinate of the cell.
 * @param {Function} callback The function to call for each marker.
 */
MarkerManager.prototype.processCellMarkers_ = function(x, y, z, callback) {
  var cell = this.getGridCellNoCreate_(x, y, z);
  if (cell) {
    for (var i = cell.length - 1; i >= 0; i--) {
      callback(cell[i]);
    }
  }
};


/**
 * Remove all markers in a grid cell.
 *
 * @param {Number} x The x coordinate of the cell.
 * @param {Number} y The y coordinate of the cell.
 * @param {Number} z The z coordinate of the cell.
 */
MarkerManager.prototype.removeCellMarkers_ = function(x, y, z) {
  this.processCellMarkers_(x, y, z, this.removeOverlay_);
};


/**
 * Add all markers in a grid cell.
 *
 * @param {Number} x The x coordinate of the cell.
 * @param {Number} y The y coordinate of the cell.
 * @param {Number} z The z coordinate of the cell.
 */
MarkerManager.prototype.addCellMarkers_ = function(x, y, z) {
  this.processCellMarkers_(x, y, z, this.addOverlay_);
};


/**
 * Use the rectangleDiffCoords function to process all grid cells
 * that are in bounds1 but not bounds2, using a callback, and using
 * the current MarkerManager object as the instance.
 *
 * Pass the z parameter to the callback in addition to x and y.
 *
 * @param {Bounds} bounds1 The bounds of all points we may process.
 * @param {Bounds} bounds2 The bounds of points to exclude.
 * @param {Function} callback The callback function to call
 *                   for each grid coordinate (x, y, z).
 */
MarkerManager.prototype.rectangleDiff_ = function(bounds1, bounds2, callback) {
  var me = this;
  me.rectangleDiffCoords(bounds1, bounds2, function(x, y) {
    callback.apply(me, [x, y, bounds1.z]);
  });
};


/**
 * Calls the function for all points in bounds1, not in bounds2
 *
 * @param {Bounds} bounds1 The bounds of all points we may process.
 * @param {Bounds} bounds2 The bounds of points to exclude.
 * @param {Function} callback The callback function to call
 *                   for each grid coordinate.
 */
MarkerManager.prototype.rectangleDiffCoords = function(bounds1, bounds2, callback) {
  var minX1 = bounds1.minX;
  var minY1 = bounds1.minY;
  var maxX1 = bounds1.maxX;
  var maxY1 = bounds1.maxY;
  var minX2 = bounds2.minX;
  var minY2 = bounds2.minY;
  var maxX2 = bounds2.maxX;
  var maxY2 = bounds2.maxY;

  for (var x = minX1; x <= maxX1; x++) {  // All x in R1
    // All above:
    for (var y = minY1; y <= maxY1 && y < minY2; y++) {  // y in R1 above R2
      callback(x, y);
    }
    // All below:
    for (var y = Math.max(maxY2 + 1, minY1);  // y in R1 below R2
         y <= maxY1; y++) {
      callback(x, y);
    }
  }

  for (var y = Math.max(minY1, minY2);
       y <= Math.min(maxY1, maxY2); y++) {  // All y in R2 and in R1
    // Strictly left:
    for (var x = Math.min(maxX1 + 1, minX2) - 1;
         x >= minX1; x--) {  // x in R1 left of R2
      callback(x, y);
    }
    // Strictly right:
    for (var x = Math.max(minX1, maxX2 + 1);  // x in R1 right of R2
         x <= maxX1; x++) {
      callback(x, y);
    }
  }
};


/**
 * Removes value from array. O(N).
 *
 * @param {Array} array  The array to modify.
 * @param {any} value  The value to remove.
 * @param {Boolean} opt_notype  Flag to disable type checking in equality.
 * @return {Number}  The number of instances of value that were removed.
 */
MarkerManager.prototype.removeFromArray = function(array, value, opt_notype) {
  var shift = 0;
  for (var i = 0; i < array.length; ++i) {
    if (array[i] === value || (opt_notype && array[i] == value)) {
      array.splice(i--, 1);
      shift++;
    }
  }
  return shift;
};

var Popup = Class.create();
Popup.prototype =
{
  initialize: function(options)
  {
    this.options = {
      url: '#',
      width: 300,
      height: 300
    }
    Object.extend(this.options, options || {});
    return window.open(this.options.url, '', 'width='+this.options.width+',height='+this.options.height);
  }
}

function showLayer(varId) {
  if($('popup'+varId))
      $('popup'+varId).show();
}

function closeLayer(varId) {
  if($('popup'+varId))
      $('popup'+varId).hide();
}


Event.observe(window, 'unload', function() {
    //GUnload();
    google.maps.Unload();
});

