<?xml version="1.0" encoding="UTF-8" ?>
<Module>
    <ModulePrefs
        title="Nearest Tropos Router (Test)"
        directory_title="__MSG_title__"
        description="__MSG_description__"
        author="Mukesh Gupta and Cyrus Behroozi, using Mark L.'s original code"
        author_affiliation="Tropos Networks, Inc."
        author_location="Sunnyvale, CA"
        author_email="info@tropos.com"
        screenshot="http://www.google.com/ig/modules/mapsearch.png"
        thumbnail="http://www.google.com/ig/modules/mapsearch-thm.png"
        category="tools"
        height="450"
        width="400"
        scrolling="true"
        render_inline="optional"
      >
      <Require feature="setprefs"/>
      <Locale messages="mapsearch_content/en.xml"/>
      <Locale lang="da" messages="mapsearch_content/da.xml"/>
      <Locale lang="de" messages="mapsearch_content/de.xml"/>
      <Locale lang="es" messages="mapsearch_content/es.xml"/>
      <Locale lang="fi" messages="mapsearch_content/fi.xml"/>
      <Locale lang="fr" messages="mapsearch_content/fr.xml"/>
      <Locale lang="it" messages="mapsearch_content/it.xml"/>
      <Locale lang="ja" messages="mapsearch_content/ja.xml"/>
      <Locale lang="ko" messages="mapsearch_content/ko.xml"/>
      <Locale lang="nl" messages="mapsearch_content/nl.xml"/>
      <Locale lang="no" messages="mapsearch_content/no.xml"/>
      <Locale lang="ru" messages="mapsearch_content/ru.xml"/>
      <Locale lang="sv" messages="mapsearch_content/sv.xml"/>
      <Locale lang="zh-CN" messages="mapsearch_content/zh-cn.xml"/>
      <Locale lang="zh-TW" messages="mapsearch_content/zh-tw.xml"/>
      <Locale lang="pt-BR" messages="mapsearch_content/pt-BR.xml"/>
    </ModulePrefs>

    <UserPref
      name="location"
      display_name="__MSG_location__"
      datatype="location"
    />

    <UserPref
      name="largeMapMode"
      display_name="__MSG_large_map__"
      datatype="bool"
      default_value="true"
    />

    <UserPref
      name="stickyMode"
      display_name="Sticky map"
      datatype="bool"
      default_value="false"
    />

    <UserPref name="traffic" datatype="hidden" default_value=""/>
    <UserPref name="locationCacheString" datatype="hidden" default_value=""/>
    <UserPref name="locationCacheLat" datatype="hidden" default_value=""/>
    <UserPref name="locationCacheLng" datatype="hidden" default_value=""/>

    <!-- current map position and zoom s.b. hidden -->
    <UserPref name="currentZoom" datatype="hidden" default_value=""/>
    <UserPref name="currentLat" datatype="hidden" default_value=""/>
    <UserPref name="currentLng" datatype="hidden" default_value=""/>

<Content type="html"> <![CDATA[
    <script src="http://www.google.com/jsapi?key=AIzaSyC-czQTeQNqEF1vs8pVl4Q4N6SCqH6BnR0" type="text/javascript"></script>
    <style type="text/css">
      #map__MODULE_ID__ {
        border : 1px solid #979797;
      }

      .small-map-__MODULE_ID__ {
        height : 100px;
      }

      .large-map-__MODULE_ID__ {
        height : 300px;
      }

      #map__MODULE_ID__ .gmls {
        width : 100%;
      }

      #results__MODULE_ID__ {
        margin-top : 30px;
        margin-bottom : 1px;
      }

      #wrapper__MODULE_ID__ .gmls-search-form {
        padding-top : 2px;
        padding-bottom : 2px;
        padding-left : 0;
        padding-right : 0;
      }

      #results__MODULE_ID__ .gmls-app,
      #map__MODULE_ID__ .gmls-app {
        border : none;
      }

      #wrapper__MODULE_ID__  {
        position : relative;
        overflow : hidden;
      }

      #wrapper__MODULE_ID__ .gs-title b {
        font-weight : normal;
      }
      #wrapper__MODULE_ID__ .gmls-results-controls td {
        background-color : #ffffff;
      }


      #splashScreen__MODULE_ID__.boot-complete-__MODULE_ID__ {
        display : none;
      }
      #splashScreen__MODULE_ID__ {
        position : absolute;
        top : 0px;
        left : 0px;
        z-index : 99;
      }
      #splashFeedback__MODULE_ID__.boot-complete-__MODULE_ID__ {
        display : none;
      }
      #splashFeedback__MODULE_ID__ {
        width : 80%;
        color : #676767;
        position : absolute;
        bottom : 4px;
        left : 0px;
        z-index : 200;
      }
      #splashFeedback__MODULE_ID__ .message__MODULE_ID__{
        margin-left : 2px;
        font-size : 11px;
        color : #676767;
      }
      #splashFeedback__MODULE_ID__ .spinner__MODULE_ID__{
        float : left;
      }
      #header{
        margin-top : 0px;
        height : 60px;
      }
      table{
        width: 100%;
        font-size : 11px;
        color : #676767;
      }
      th{
        font-weight: normal;
        text-align: left;
      }
      tr{
        text-align: right;
      }      
      .black {
        color: #111111;
      }  
    </style>

  <script type="text/javascript">

  function OnLoad__MODULE_ID__() {
    new MapGadget__MODULE_ID__();
  }
  var troposLoc = "Location Unavailable";
  var troposLat = 37.38949;
  var troposLong = -122.08173;
  var troposSNR = 0.0;
  var troposBSSID = "00:00:00:00:00:00";
  var troposClientIP = "0.0.0.0";
  var troposSSID = "None";
  var troposChannel = "0";
  var troposNoise = "0 dBm";
  var troposUplinkRate = "0 Mbps";
  var troposDownlinkRate = "0 Mbps";
  var troposUplinkETT = "0 Mbps";
  var troposDownlinkETT = "0 Mbps";
  var troposClientMAC = "00:00:00:00:00:00";
  
  function displayHeader() {
    var headerString = "<table><tr><th><a class=black>" + troposLoc + "</a>" +
                              "<br>SSID: <a class=black>" + troposSSID + "</a>" +
                              "<br>BSSID: <a class=black>" + troposBSSID + "</a>" +
                              "<br>Channel: <a class=black>" + troposChannel + "</a>" +
                              "<td>Uplink SNR: <a class=black>" + troposSNR + "</a>" +
                              "<br>Node Noise: <a class=black>" + troposNoise + "</a>" +
                              "<br>Uplink Bit Rate: <a class=black>" + troposUplinkRate + "</a>" +
                              "<br>Downlink Bit Rate: <a class=black>" + troposDownlinkRate + "</a>" +
                       "</table>";
    _gel('header').innerHTML = headerString;
  }

  function tropos_client_callback(loc) {
    troposLoc = loc.ClientInfo.RouterLocation;
    troposLat = loc.ClientInfo.RouterLatitude;
    troposLong = loc.ClientInfo.RouterLongitude;
    troposSNR = loc.ClientInfo.SNR;
    troposBSSID = loc.ClientInfo.BSSID;
    troposClientIP = loc.ClientInfo.ClientIPAddr;
    troposSSID = loc.ClientInfo.SSID;
    troposChannel = loc.ClientInfo.Channel;
    troposNoise = loc.ClientInfo.Noise;
    troposUplinkRate = loc.ClientInfo.UplinkRate;
    troposDownlinkRate = loc.ClientInfo.DownlinkRate;
    troposUplinkETT = loc.ClientInfo.UplinkETT;
    troposDownlinkETT = loc.ClientInfo.DownlinkETT;
    troposClientMAC = loc.ClientInfo.ClientMACAddr;
    displayHeader();
  }
              
  function delayedStart() {
    //_gel('header').innerHTML = "This is the header.";
    var url = "http://192.168.168.168/client.pl";
    var scr = document.createElement('script');
    scr.setAttribute('type', 'text/javascript');
    scr.setAttribute('src', url);
    document.getElementsByTagName('body').item(0).appendChild(scr);
    setTimeout('(OnLoad__MODULE_ID__())',2000);
    setTimeout('(displayHeader())',3000);
  }

/**
 * Begin Anonymous Code, exports window.MapGadget__MODULE_ID__
 */
(function () {
  /**
   * The Core Map Gadget Object
   */
  function MapGadget() {
    this.dissolving = false;
    this.browserFun();
    this.prefs = new _IG_Prefs(__MODULE_ID__);
    this.computeCenter();
  }
  MapGadget.BOOT_DELAY = 20;
  MapGadget.WATCHDOG_DELAY = 500;
  window.MapGadget__MODULE_ID__ = MapGadget;

  /**
   * Compute the center point for the map
   *
   * If the location preference IS NOT set, then
   * use GetDefaultCenter
   *
   * Otherwise:
   * - If the preference matches the cached location string, use
   *   the cached lat/lng. IF the cached lat/lng are unset, kill
   *   the cache
   * - If the preference string DOES NOT match the cache, then
   *   geo-code the location string. If this is successful, that
   *   stash the string and lat/lng in the cache. If not, then use
   *   GetDefaultCenter
   */
  MapGadget.prototype.computeCenter = function() {
    var center;
    this.country = this.prefs.getString(".country");
    var stickyMode = this.prefs.getBool("stickyMode");
    if (stickyMode) {

      // old values
      var oldLat = this.prefs.getString("currentLat");
      var oldLng = this.prefs.getString("currentLng");
      var oldZoom = this.prefs.getString("currentZoom");
      if (oldZoom == 0) {
        this.idleZoom = 15;
        this.activeZoom = 15;
      } else {
        this.idleZoom = parseInt(oldZoom);
        this.activeZoom = parseInt(oldZoom);
      }
      center = new fastLatLng(parseFloat(oldLat), parseFloat(oldLng));
    } else {
      this.idleZoom = 15;
      this.activeZoom = 15;
      var locationPref = this.prefs.getString("location");
      if ( locationPref == "" ) {
        // no location preference is set
        // just use the locale specific default
        // center point
        center = GetDefaultCenter(null, this.country);
      } else {
        // preference is set.
        // if it matches the cache, and the cache is valid, then
        // use the cached preference. If it doesn't match, then clear
        // the cache and geocode
        var center = this.checkLocationCache(locationPref);
        if (center == null) {
          // delay-load search and then do a lookup
          var me = this;
          google.load("search", "1",
                      { callback:
                        function() {
                          // fire up a geo-code operation which will eventually
                          // call bootComplete
                          var searcher = new GlocalSearch();
                          searcher.setSearchCompleteCallback(me,
                                                             MapGadget.prototype.geocodeComplete,
                                                             [locationPref, searcher]);
                          searcher.execute(locationPref);
                      }
                    }
                   );
          return;
        }
      }
    }
    this.bootComplete(center);
  }

  /**
   * See Above...
   *
   * If the location cache is set and valid, then use it.
   * Otherwise clear the cache and let the geocoder take
   * over.
   */
  MapGadget.prototype.checkLocationCache = function(locationPref) {
    var returnValue = null;

    var stickyMode = this.prefs.getBool("stickyMode");
    if (stickyMode) {
      var oldLat = this.prefs.getString("currentLat");
      var oldLng = this.prefs.getString("currentLng");
      returnValue = new fastLatLng(parseFloat(oldLat), parseFloat(oldLng));
    }
    var locationCacheString = this.prefs.getString("locationCacheString");
    if (locationCacheString) {
      if (locationCacheString == locationPref) {
        // cache matches, check to see if cached lat/lng is set
        // if so, use. If not, clear the cache
        var lat = this.prefs.getString("locationCacheLat");
        var lng = this.prefs.getString("locationCacheLng");
        if ( lat && lng ) {
          returnValue = new fastLatLng(parseFloat(lat), parseFloat(lng));
        } else {
          this.clearLocationCache();
        }
      } else {
        // cache does not match. clear the cache
        this.clearLocationCache();
      }
    }
    return returnValue;
  }

  MapGadget.prototype.clearLocationCache = function() {
    this.prefs.set("locationCacheString", "");
    this.prefs.set("locationCacheLat", "");
    this.prefs.set("locationCacheLng", "");
  }

  MapGadget.prototype.setLocationCache = function(location, lat, lng) {
    this.prefs.set("locationCacheString", location);
    this.prefs.set("locationCacheLat", lat);
    this.prefs.set("locationCacheLng", lng);
  }

  /**
   * If the location cache is invalid, but the location preference
   * is set, we start a search which completes here. If we end up
   * with valid results, then we cache them and complete the boot
   * process. If not, we use the default center.
   */
  MapGadget.prototype.geocodeComplete = function(locationPref, searcher) {
    var center;
    if ( searcher.results && searcher.results.length > 0 ) {
      var latString = searcher.results[0].lat;
      var lngString = searcher.results[0].lng;
      center = new fastLatLng(parseFloat(latString), parseFloat(lngString));
      this.setLocationCache(locationPref, latString, lngString);
    } else {
      center = GetDefaultCenter(null, this.country);
    }
    this.bootComplete(center);
  }

  /**
   * Center point is computed so now fire up the map, startup the
   * traffic overlay, etc.
   */
  MapGadget.prototype.bootComplete = function(centerPoint) {
    if (centerPoint == null) {
      centerPoint = GetDefaultCenter("en");
    }

    this.bootCenterPoint = centerPoint;
    this.centerPoint = centerPoint;
    this.bootDelay = MapGadget.BOOT_DELAY;
    this.tracking = false;

    this.splashScreen = document.getElementById("splashScreen__MODULE_ID__");
    this.splashFeedback = document.getElementById("splashFeedback__MODULE_ID__");
    this.outerMapContainer = document.getElementById("map__MODULE_ID__");
    this.largeMapMode = this.prefs.getBool("largeMapMode");
    if (this.largeMapMode) {
      this.idleClass = "large-map-__MODULE_ID__";
      this.activeClass = "large-map-__MODULE_ID__";
      this.splashHeight = 301;
    } else {
      this.idleClass = "small-map-__MODULE_ID__";
      this.activeClass = "large-map-__MODULE_ID__";
      this.splashHeight = 101;
    }
    this.cssSetClass(this.outerMapContainer, this.idleClass);
    this.bootCompleteClass = "boot-complete-__MODULE_ID__";
    this.splashWidth = this.outerMapContainer.offsetWidth;
    this.splashZoom = StaticTile.STATIC_MAP_ZOOM_FARTHEST - this.idleZoom;
    this.splashScreen.style.width = this.splashWidth + "px";
    this.splashScreen.style.height = this.splashHeight + "px";

    // create the static map image
    var url = StaticTile.computeStaticMapUrl([centerPoint], this.splashHeight,
                                             this.splashWidth, this.splashZoom);
    this.splashImage = this.createImage(url, this.splashHeight, this.splashWidth);
    this.splashScreen.appendChild(this.splashImage);
    this.setOpacity(this.splashImage, 100);

    // now, delay load the rest and start the Dissolve process
    window.setTimeout(methodCallback(this,this.loadAsyncModules), this.bootDelay);
  }

  if (MapGadget.loadInProgress != true) {
    MapGadget.loadInProgress = false;
  }
  MapGadget.prototype.loadAsyncModules = function() {

      // schedule the load of maps api, local search for maps, and then search
      var me = this;
      MapGadget.loadInProgress = true;
      google.load("maps", "2.x",
                  { callback:
                    function() {
                     google.load("search", "1",
                                 { callback:
                                   function() {
                                     // gmlocalsearch's callback only works once right now
                                     // manually work around this
                                     if (window["google.maps.LocalSearch"]) {
                                      me.mapsLoaded();
                                     } else {
                                       // search and maps are now loaded,
                                       // load gmlocalsearch.js
                                       var randomizer = Math.round(1000000 * Math.random());
                                       var autoloadName = "__autoload____MODULE_ID__" + new Date().getTime() + "__" + randomizer;
                                       var me2 = me;
                                       window[autoloadName] = function() {
                                         me2.mapsLoaded();
                                       }
                                       var lsUrl = "http://www.google.com/uds/solutions/localsearch/gmlocalsearch.js?key=AIzaSyC-czQTeQNqEF1vs8pVl4Q4N6SCqH6BnR0&callback=" + autoloadName;

                                       // inject the script tag
                                       google.loader.writeLoadTag("script", lsUrl, true);
                                     }
                                 }
                               }
                              );
                  }
                }
               );
  }

  /**
   * Center point is computed so now fire up the map, startup the
   * traffic overlay, etc.
   */
  MapGadget.prototype.mapsLoaded = function() {
    // Create and Center a Map
    // Now, convert this.centerPoint from a fastLatLng
    // to a GLatLng
    this.centerPoint = new GLatLng(this.centerPoint.lat, this.centerPoint.lng);

    this.gmap = new GMap2(this.outerMapContainer);

    // with the maps API loaded,
    // bind to the tilesloaded event so that we can Dissolve
    // away the static map
    // Note, we also bind to a watchdog timer in case
    // this event does not fire
    var me = this;
    /**
     * This event isn't stable enough to use yet...
    GEvent.addListener(this.gmap, "tilesloaded", function() {
      if ( !me.dissolving) {
        me.dissolving = true;
        if (me.splashScreen) {
          me.dissolveSplashScreen();
        }
      }
    });
    */

    this.gmap.setCenter(this.centerPoint, this.idleZoom);
    this.smallMapControl = new GSmallMapControl();
    this.gmap.addControl(this.smallMapControl);

    // bind a search control to the map, suppress result list
    var options = new Object();
    options.resultList = document.getElementById("results__MODULE_ID__");
    options.searchFormHint = GetHintString();
    options.onIdleCallback =
      methodCallback(this, MapGadget.prototype.onIdleCallback);
    options.onSearchCompleteCallback =
      methodCallback(this, MapGadget.prototype.onSearchCompleteCallback);

    this.gmap.addControl(new google.maps.LocalSearch(options),
      new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(0,-30)));
    this.cssSetClass(this.splashFeedback,this.bootCompleteClass);

    // add traffic
    // traffic button state
    this.initializeTrafficOverlay();

    // register an unzip callback
    _IG_AddModuleEventHandler(__MODULE_ID__, "unzip", methodCallback(this, MapGadget.prototype.unzipCallback));
  }

  MapGadget.prototype.unzipCallback = function() {
    this.gmap.checkResize();
  }

  MapGadget.prototype.onIdleCallback = function() {
    var me = this;
    if (!this.tracking) {
      this.tracking = true;
      // track the map position in case user wants to
      // pin his center point
      GEvent.addListener(this.gmap, "moveend", function() {
        var current = me;
        var center = current.gmap.getCenter();
        var zoom = parseInt(current.gmap.getZoom());
        var lat = parseFloat(center.lat());
        var lng = parseFloat(center.lng());

        // old values
        var oldLat = current.prefs.getString("currentLat");
        var oldLng = current.prefs.getString("currentLng");
        var oldZoom = current.prefs.getString("currentZoom");

        if (zoom == 0) {
          zoom = oldZoom;
          this.idleZoom = parseInt(oldZoom);
          this.activeZoom = parseInt(oldZoom);
        }
        current.prefs.set("currentZoom", zoom);
        current.prefs.set("currentLat", lat);
        current.prefs.set("currentLng", lng);
      });
    }

    if (this.largeMapMode == false && this.smallMapControl) {
      this.gmap.removeControl(this.smallMapControl);
      this.smallMapControl = null;
    }
    this.cssSetClass(this.outerMapContainer, this.idleClass);
    this.gmap.checkResize();
    this.gmap.setCenter(this.centerPoint, this.idleZoom);

    // if we are not Dissolving, then start up a watchdog timer
    if ( !this.dissolving ) {
      window.setTimeout(function() {
        if ( !me.dissolving ) {
          me.dissolving = true;
          if (me.splashScreen) {
            me.dissolveSplashScreen();
          }
        }
      }, MapGadget.WATCHDOG_DELAY);
    }
  }

  MapGadget.prototype.onSearchCompleteCallback = function(searcher) {
    if (searcher.results && searcher.results.length > 0) {
      if (this.largeMapMode == false && this.smallMapControl == null) {
        this.smallMapControl = new GSmallMapControl();
        this.gmap.addControl(this.smallMapControl);
      }
      this.cssSetClass(this.outerMapContainer, this.activeClass);
      this.gmap.checkResize();
      this.gmap.setZoom(this.activeZoom);
    }
  }

  MapGadget.prototype.cssSetClass = function(el, className) {
    el.className = className;
  }

  MapGadget.prototype.browserFun = function() {
    // Browser fun.
    if (window.ActiveXObject) {
      this.ie = this[window.XMLHttpRequest ? 'ie7' : 'ie6'] = true;
    } else if (window.opera) {
      this.opera = true;
    } else if (document.childNodes && !document.all && !navigator.taintEnabled) {
      this.safari = true;
    } else if (document.getBoxObjectFor != null) {
      this.gecko = true;
    }
  }

  MapGadget.prototype.createImage = function(src, opt_h, opt_w, opt_className) {
    var el = document.createElement("img");
    el.src = src;
    if (opt_w) { el.width = opt_w; }
    if (opt_h) { el.height = opt_h; }
    if (opt_className) { el.className = opt_className; }
    return el;
  }

  MapGadget.prototype.setOpacity = function(image, opacity) {
     if (image == null) return;
     opacity = Math.max(0, Math.min(1, opacity));
     if (opacity == 0) {
       if (image.style.visibility != "hidden") {
         image.style.visibility = "hidden";
       }
     } else {
       if (image.style.visibility != "visible") {
         image.style.visibility = "visible";
       }
     }
     if (this.ie) image.style.filter = "alpha(opacity=" + opacity*100 + ")";
     image.style.opacity = image.opacity = opacity;
  };

  MapGadget.prototype.dissolveSplashScreen = function() {
      // Setup Dissolver
      this.transitionTime = 1000;
      this.transitionStep = 40;
      var ts = (this.transitionTime / this.transitionStep);
      this.delta = Math.min(1, (1.0/ts));
      this.setTransitionTimer();
  }

  MapGadget.timeNow = function() {
    var d = new Date();
    return d.getTime();
  };

  /**
   * Helper method to bind this instance correctly.
   * @param {Object} method function/method to bind.
   * @return {Function}
   * @private
   */
  MapGadget.prototype.bind = function(method) {
    var self = this;
    var opt_args = [].slice.call(arguments, 1);
    return function() {
      var args = opt_args.concat([].slice.call(arguments));
      return method.apply(self, args);
    }
  };

  /**
   * Clear the transition timer. Used to prevent leaks.
   * @private
   */
  MapGadget.prototype.clearTransitionTimer = function() {
    if (this.transition_timer) {
      clearInterval(this.transition_timer);
      this.transition_timer = null;
    }
  };

  /**
   * Sets the transition timer for fadeout.
   * @private
   */
  MapGadget.prototype.setTransitionTimer = function() {
    this.clearTransitionTimer();
    this.lastTick = MapGadget.timeNow();
    var cb = this.bind(this.transitionAnimation);
    this.transition_timer = window.setInterval(cb, this.transitionStep);
  };

  MapGadget.prototype.transitionAnimation = function() {
    if (this.splashImage) {
      var delta = this.delta;
      var ts = this.transitionStep;
      var now = MapGadget.timeNow();
      var tick = now - this.lastTick;
      this.lastTick = now;
      delta *= (tick/ts);
      if (delta < 0) return;

      var cur_op = this.splashImage.opacity - delta;
      this.setOpacity(this.splashImage, cur_op);
      // Still more to go?
      if (cur_op > 0) {
        return;
      }
    }
    // Finished transition.
    this.clearTransitionTimer();
    this.cssSetClass(this.splashScreen,this.bootCompleteClass);

  };
  /**
   * Traffic...
   *
   * Basic idea is that when the current map view contains traffic
   * data, we expose the traffic button (ToggleControl object). If
   * the user clicks on the button, we toggle traffic data on/off,
   * AND we remember the clicked state of the button in a hidden
   * pref.
   *
   * Algorithm:
   *
   * On Boot:
   * - create a ToggleControl (the traffic button) for toggling
   *   traffic on/off (this.trafficControl)
   * - bind to map's moveend event which conditionally shows the
   *   traffic button
   *
   * - create a GTrafficOverlay, add it to the map, and hide it.
   *   We only show the overlay when the traffic button has been
   *   pressed...
   *
   * On MoveEnd:
   * - at the end of a search, or anytime the map is moved, we
   *   call .showHideTrafficButton. This function looks to see if
   *   the current map view contains traffic data. If so, we show
   *   the traffic button. Otherwise, we remove the traffic
   *   button.
   */
  MapGadget.prototype.initializeTrafficOverlay = function() {
      // Note that the ToggleControl is scoped to this function. It needs
      // to be defined at runtime, after Maps API is loaded.
      /**
       * Toggle Control - The button for traffic...
       */
      function ToggleControl(text) {
        this.text_ = text;
        this.textDiv_ = null;
        this.div_ = null;
        this.container_ = null;
        this.trafficOverlay_ = null;
        this.isToggled_ = false;
        this.onClickCallback_ = null;
      }
      ToggleControl.prototype = new GControl();

      ToggleControl.prototype.setOnClick = function(callback) {
        this.onClickCallback_ = callback;
      }

      ToggleControl.prototype.onClick = function() {
        if (this.onClickCallback_) {
          this.onClickCallback_();
        }
      }

      ToggleControl.prototype.initialize = function(map) {
        var me = this;
        var container = document.createElement("div");
        // don't show button until size is known
        container.style.visibility = 'hidden';

        var div = document.createElement("div");
        var style = div.style;
        style.position = 'absolute';
        style.backgroundColor = "white";
        style.border = "1px solid black";
        style.color = "black";
        style.fontFamily = "Arial,sans-serif";
        style.fontSize = "12px";
        style.textAlign = "center";
        style.width = "5em";
        try {
          style.cursor = "pointer";
        } catch (e) {
          style.cursor = "hand";
        }
        container.appendChild(div);

        var textDiv = document.createElement("div");
        div.appendChild(textDiv);
        textDiv.appendChild(document.createTextNode(me.text_));

        me.container_ = container;
        me.div_ = div;
        me.textDiv_ = textDiv;

        map.getContainer().appendChild(container);
        me.setToggled(!!me.isToggled_);

        GEvent.addDomListener(me.textDiv_, "click", function() { me.onClick(); });

        return container;
      }

      ToggleControl.prototype.isToggled = function() {
        return this.isToggled_;
      }

      ToggleControl.prototype.setToggled = function(isToggled) {
        if (this.textDiv_) {
          var style = this.textDiv_.style;
          style["fontWeight"] = isToggled ? "bold" : "";

          // Mimic an impressed button by adding a shadow to the sides of the button
          if (isToggled) {
            style["border"] = "1px solid #6C9DDF";
          } else {
            style["border"] = "1px solid white";
          }

          var shadows = isToggled ? ["Top", "Left"] : ["Bottom", "Right"];
          var shadowColor = isToggled ? "1px solid #345684" :
                                        "1px solid #b0b0b0";
          for (var j = 0; j < shadows.length; j++) {
            style["border" + shadows[j]] = shadowColor;
          }
        }
        this.isToggled_ = isToggled;
      };

      ToggleControl.prototype.isToggled = function() {
        return this.isToggled_;
      }

      ToggleControl.prototype.setSize = function() {
        var div = this.div_;
        if (div) {
          var totalHeight = div.offsetHeight;
          var totalWidth = div.offsetWidth;
          if (totalWidth % 2 == 1) {
            totalWidth++;
          }
          if (totalWidth) {
            var style = this.container_.style;
            style["visibility"] = "";
            style["width"] = totalWidth + "px";
            style["height"] = totalHeight + "px";
          }
        }
      }

    var me = this;

    // button state
    this.traffic = this.prefs.getString("traffic") != "";

    // traffic button
    var trafficPos = new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(0.2, 0.2, "em", "em"));
    me.trafficControl = new ToggleControl("__MSG_traffic__");
    me.trafficControl.setOnClick(function() { me.toggleTraffic(); });

    // traffic overlay
    me.trafficOverlay = new GTrafficOverlay();
    GEvent.addListener(me.trafficOverlay, "changed",
                       function(hasTrafficInView) {
      me.hasTrafficDataInView = hasTrafficInView;
      me.showHideTrafficButton(trafficPos);
    });
    me.gmap.addOverlay(me.trafficOverlay);
    me.trafficOverlay.hide();

    // Tropos router marker
    me.marker = new GMarker(new GLatLng(troposLat, troposLong));
    me.gmap.addOverlay(me.marker);
    
    me.trafficButtonShown = false;
    me.hasTrafficDataInView = false;
    if (me.traffic) {
      me.toggleTraffic();
      me.updateTrafficOverlay();
    }
  }

  /**
   * Called at the end of a map move (or search). This function
   * displays the traffic button if the current view contains
   * traffic data. Otherwise it removes the traffic button.
   */
  MapGadget.prototype.showHideTrafficButton = function(trafficPos) {
    var me = this;
    // timeout to wait for map to be ready
    window.setTimeout(function() {
      if (me.trafficOverlay) {
        var inView = me.hasTrafficDataInView;

        if (inView != me.trafficButtonShown) {
          if (inView) {
            me.gmap.addControl(me.trafficControl, trafficPos);
            me.trafficControl.setSize();
            me.trafficButtonShown = true;
          } else {
            me.gmap.removeControl(me.trafficControl);
            me.trafficButtonShown = false;
          }
        }
      }
    }, 0);
  }

  MapGadget.prototype.toggleTraffic = function() {
    var prevToggle = this.trafficControl.isToggled();
    this.trafficControl.setToggled(!prevToggle);
    this.prefs.set("traffic", !prevToggle ? "1" : "");
    this.updateTrafficOverlay();
  }

  MapGadget.prototype.updateTrafficOverlay = function() {
    // Make sure button size is set correctly. This is a work around to make
    // info windows dodge the button.
    this.trafficControl.setSize();

    if (this.trafficControl.isToggled()) {
      this.trafficOverlay.show();
    } else {
      this.trafficOverlay.hide();
    }
  }


  /**
   * Dynamic Defaults
   *
   * Default Center Point and Search Hint String, Locale
   *
   * Note, these are indexed by both language code AND country
   * code
   */

  // by language
  var DefaultByLanguageCenters = new Array();
  DefaultByLanguageCenters["en"] = new fastLatLng(37.7750, -122.4183);     // san francisco
  DefaultByLanguageCenters["fr"] = new fastLatLng(48.8565, 2.3509);        // paris
  DefaultByLanguageCenters["de"] = new fastLatLng(52.5238, 13.4119);       // berlin
  DefaultByLanguageCenters["es"] = new fastLatLng(40.4167, -3.7032);       // madrid
  DefaultByLanguageCenters["it"] = new fastLatLng(45.4637, 9.1881);        // milan
  DefaultByLanguageCenters["nl"] = new fastLatLng(52.3738, 4.8909);        // amsterdam
  DefaultByLanguageCenters["ja"] = new fastLatLng(35.6699, 139.7700);      // tokyo

  // by country
  var DefaultByCountryCenters = new Array();
  DefaultByCountryCenters["US"] = new fastLatLng(37.7750, -122.4183);     // san francisco
  DefaultByCountryCenters["FR"] = new fastLatLng(48.8565, 2.3509);        // paris
  DefaultByCountryCenters["DE"] = new fastLatLng(52.5238, 13.4119);       // berlin
  DefaultByCountryCenters["ES"] = new fastLatLng(40.4167, -3.7032);       // madrid
  DefaultByCountryCenters["IT"] = new fastLatLng(45.4637, 9.1881);        // milan
  DefaultByCountryCenters["NL"] = new fastLatLng(52.3738, 4.8909);        // amsterdam
  DefaultByCountryCenters["CA"] = new fastLatLng(45.512280, -73.554380);  // montreal
  DefaultByCountryCenters["CH"] = new fastLatLng(47.369023, 8.538032);    // zurich
  DefaultByCountryCenters["DK"] = new fastLatLng(55.676294, 12.568115);   // copenhagen
  DefaultByCountryCenters["FI"] = new fastLatLng(60.160791, 24.952548);   // helsinki
  DefaultByCountryCenters["UK"] = new fastLatLng(51.500152, -0.126236);   // london
  DefaultByCountryCenters["SE"] = new fastLatLng(59.332725, 18.064454);   // stockholm
  DefaultByCountryCenters["NO"] = new fastLatLng(59.913820, 10.738741);   // oslo
  DefaultByCountryCenters["HK"] = new fastLatLng(22.28434, 114.15819);    // Hong Kong
  DefaultByCountryCenters["TW"] = new fastLatLng(25.047697, 121.51705);   // Taipei

  // not in whitelist regions
  DefaultByCountryCenters["IN"] = new fastLatLng(12.908001, 77.641011);   // bangalore  (not in whitelist)
  DefaultByCountryCenters["JP"] = new fastLatLng(35.6699, 139.7700);      // tokyo      (not in whitelist)
  DefaultByCountryCenters["AU"] = new fastLatLng(-33.867139, 151.207114); // sydney     (not in whitelist)

  // good tiles, no search coverage
  DefaultByCountryCenters["NZ"] = new fastLatLng(-41.286480, 174.776217); // wellington (no search coverage)
  DefaultByCountryCenters["RU"] = new fastLatLng(55.755786, 37.617633);   // moscow     (no search coverage)
  DefaultByCountryCenters["IE"] = new fastLatLng(53.344104, -6.267493);   // dublin     (no search coverage)
  DefaultByCountryCenters["BR"] = new fastLatLng(-23.548943, -46.638818); // Sao Paulo  (no search coverage)

  // bad tiles, poor experience
  // DefaultByCountryCenters["KR"] = new fastLatLng(37.532308, 126.957440);  // seoul       (bad map tile coverage)
  // DefaultByCountryCenters["MX"] = new fastLatLng(19.410636, -99.130588);  // mexico city (bad map tile coverage)
  // DefaultByCountryCenters["CN"] = new fastLatLng(39.930000, 116.400001);  // beijing     (bad map tile coverage)

  function GetDefaultCenter(opt_locale, opt_country) {
    var returnValue = new fastLatLng(troposLat, troposLong);
    return returnValue;
  }
    
    
  function GetDefaultCenterOld(opt_locale, opt_country) {
    var locale = "en";
    var country = null;
    if (opt_locale) {
      locale = opt_locale;
    }
    var returnValue;
    if (opt_country) {
      country = opt_country.toUpperCase();
      returnValue = DefaultByCountryCenters[country];
      if (returnValue != undefined) {
        return returnValue;
      }
    }
    returnValue = DefaultByLanguageCenters[locale];
    if (returnValue == undefined) {
      returnValue = DefaultByLanguageCenters["en"];
    }
    return returnValue;
  }

  var DefaultHints = new Array();
  DefaultHints["en"] = "Local Search";
  DefaultHints["fr"] = "Exemples de recherche : Hotels";
  DefaultHints["de"] = "Beispiele f\u00FCr Suchanfragen: Hotels"; // 00fc --> ü
  DefaultHints["es"] = "Ejemplos de b\u00FAsquedas: Hoteles";     // 00fa --> ú
  DefaultHints["it"] = "Esempi di ricerca: Hotels";
  DefaultHints["nl"] = "Voorbeelden van zoekopdrachten: Hotels";
  DefaultHints["pt-BR"] = "por exemplo: hot\u00e9is em S\u00E3o Paulo"; // 00e3 ~a

  function GetHintString(opt_locale) {
    var locale = UDS_CurrentLocale;
    if (opt_locale) {
      locale = opt_locale;
    }
    var returnValue;
    returnValue = DefaultHints[locale];
    if (returnValue == undefined) {
      returnValue = GSearch.strings["search-the-map"];
    }
    return returnValue;
  }

  function methodCallback(object, method) {
    return function() {
      return method.apply(object, arguments);
    }
  }

  function fastLatLng(lat, lng) {
    this.lat = lat;
    this.lng = lng;
  }
    

  /**
   * Resize the staticMapUrl for this result
   *
   */
  function StaticTile() {}
  StaticTile.STATIC_MAP_ZOOM_FARTHEST = 17;
  StaticTile.STATIC_MAP_ZOOM_DEFAULT = 4;
  StaticTile.STATIC_MAP_ZOOM_CLOSEST = 0;
  StaticTile.STATIC_MAP_MAX_POINTS = 8;

  StaticTile.resizeStaticMapUrl = function(res, h, w, opt_z) {
    var url = res.staticMapUrl;
    url = url.replace(/&h=\d*/,"&h=" + h);
    url = url.replace(/&w=\d*/,"&w=" + w);
    if (opt_z && opt_z >= StaticTile.STATIC_MAP_ZOOM_CLOSEST &&
        opt_z <= StaticTile.STATIC_MAP_ZOOM_FARTHEST) {
      url = url.replace(/&zl=\d*/,"&zl=" + opt_z);
    } else if (opt_z && opt_z < StaticTile.STATIC_MAP_ZOOM_CLOSEST ||
               opt_z > StaticTile.STATIC_MAP_ZOOM_FARTHEST) {
      opt_z = StaticTile.STATIC_MAP_ZOOM_DEFAULT + 2;
      url = url.replace(/&zl=\d*/,"&zl=" + opt_z);
    }
    res.staticMapUrl = url;
    return url;
  }

  StaticTile.computeStaticMapUrl = function(results, h, w, opt_z) {
    var pointsTemplate = "&Point=b&Point.latitude_e6=__LAT__&Point.longitude_e6=__LNG__&Point=e";
    var pointsUrl = "";
    var baseUrl = "http://mt.google.com/mapdata?cc=us&tstyp=5&zl=4&w=150&h=100";

    // set up the size and zoom
    var fakeResult = new Object();
    fakeResult.staticMapUrl = baseUrl;
    baseUrl = StaticTile.resizeStaticMapUrl(fakeResult,h, w, opt_z);
    if (opt_z == null) {
      baseUrl = baseUrl.replace(/&zl=\d*/,"");
    }

    var limit = results.length;
    if (limit > StaticTile.STATIC_MAP_MAX_POINTS) {
      limit = StaticTile.STATIC_MAP_MAX_POINTS;
    }
    for (var i=0; i<limit; i++) {
      var lat;
      var lng;
      var obj = results[i];

      // allow the user to pass in:
      // - a standard ajax search result containing lat/lng
      // - any object with a lat/lng property
      // - a GLatLng/GPoint (anything with a .x, .y property)
      if (obj.lat && obj.lng) {
        if (typeof obj.lat == "string") {
          lat = parseFloat(obj.lat);
          lng = parseFloat(obj.lng);
        } else {
          lat = obj.lat;
          lng = obj.lng;
        }
      } else if (obj.x && obj.y) {
        lat = obj.y;
        lng = obj.x;
      } else {
        return null;
      }
      var lat_e6 = lat * 1000000;
      var lng_e6 = lng * 1000000;
      var pointString = pointsTemplate.replace(/__LAT__/, parseInt(lat_e6));
      pointString = pointString.replace(/__LNG__/, parseInt(lng_e6));
      var iconId = 51 + i;
      if (limit == 1) {
        iconId = 15;
      }
      pointsUrl = pointsUrl + pointString;
    }
    var url = baseUrl + pointsUrl;
    return url;
  }
})();
/** END Anonymous Function **/
    
  _IG_RegisterOnloadHandler(delayedStart);
  //_IG_RegisterOnloadHandler(OnLoad__MODULE_ID__);    
  </script>
</head>

<div id="header"></div>
<div id="wrapper__MODULE_ID__">
  <div id="splashScreen__MODULE_ID__"></div>
  <div id="splashFeedback__MODULE_ID__">
    <img class="spinner__MODULE_ID__" src="/ig/modules/mapsearch/mapsearch_content/spinner.gif"/>
    <span class="message__MODULE_ID__">__MSG_loading__</span>
  </div>
  <div id="map__MODULE_ID__" class="small-map-__MODULE_ID__"></div>
  <div id="results__MODULE_ID__"></div>
</div>
    ]]>
    </Content>
</Module>
