<?xml version="1.0" encoding="UTF-8"?>
<Module>
  <!--
  
    hurricane_gadget.xml
    
    Google Gadget mashup of the DaylightMap.com cloud overlay with a tropical cyclone RSS feed
    
    Copyright 2006-8 Udell Enterprises, Inc
  
  -->
  <ModulePrefs title="Hurricane Watcher"
               directory_title="Hurricane Watcher"
               title_url="http://gad.getpla.net/hurricane.php" 
               description="Interactive satellite view of any current tropical cyclone."
               author="Sterling Udell"
               author_email="sterling.udell+gadgets@gmail.com"
               author_location="North Wales, UK"
               author_affiliation="Udell Enterprises, Inc"
               author_photo="http://gad.getpla.net/images/my_photo.jpg"
               author_aboutme="Free-range programmer developing gadgets, map applications, and anything else that catches my interest."
               author_link="http://gad.getpla.net"
               author_quote="Is there no sun in this cursed country?"
               height="310"
               width="300"
               screenshot="http://www.daylightmap.com/clouds/images/hurricane_280.jpg"
               thumbnail="http://www.daylightmap.com/clouds/images/hurricane_120.png">
    <Require feature="setprefs" />
    <Require feature="analytics" />
    <Require feature="dynamic-height"/>
    <Require feature="minimessage" />
  </ModulePrefs>
  <UserPref name="atlantic" display_name="Atlantic / Gulf Mex" datatype="bool" default_value="1" />
  <UserPref name="east_pacific" display_name="Eastern Pacific" datatype="bool" default_value="1" />
  <UserPref name="central_pacific" display_name="Central Pacific" datatype="bool" default_value="1" />
  <UserPref name="west_pacific" display_name="Western Pacific" datatype="bool" default_value="1" />
  <UserPref name="indian" display_name="Indian Ocean" datatype="bool" default_value="1" />
  <UserPref name="units" display_name="Wind Speed" default_value="miles per hour" datatype="enum" >
    <EnumValue value="miles per hour" />
    <EnumValue value="knots" />
    <EnumValue value="kilometers per hour" />
    <EnumValue value="meters per second" />
  </UserPref>
  <Content type="html" view="home,canvas"><![CDATA[
    <div id="ht_text___MODULE_ID__"></div>
    <div id="ht_map___MODULE_ID__"></div>

    <style type="text/css">
    #ht_text___MODULE_ID__ {
      background-color: white;
      z-index: 100;
      position: relative;
      left: 0;
      top: 0;
    }
    table, p {
      width: 100%;
      font-size: 80%;
      border-collapse: collapse;
      margin: 0;
    }
    th {
      font-size: 80%;
      font-weight: normal;
      line-height: 0.7;
    }
    td {
      padding: 1px 1px 1px 3px;
    }
    td.data {
      text-align: center;
    }
    tr td {
      cursor: pointer;
      border-top: 1px solid #EEEEEE;
    }
    .selected td {
      background-color: #FFFE81;
      cursor: default;
    }
    img {
      border: none;
    }

    #ht_map___MODULE_ID__ {
      height: 220px;
      border: 1px solid;
      display: none;
    }
    </style>

    <script type="text/javascript" src="http://maps.google.com/maps?file=api&v=2.89"></script>
    <script type="text/javascript">
      document.write('<script type="text/javascript" src="' + 
        _IG_GetCachedUrl('http://www.daylightmap.com/clouds/clouds.js', {refreshInterval: 300}) + '"><\/script>');

      var textDiv = document.getElementById('ht_text___MODULE_ID__');
      var mapDiv  = document.getElementById('ht_map___MODULE_ID__');
      var map;
      var daylight;
      var prefs = new _IG_Prefs(__MODULE_ID__);
      var stormData = [];
      var focusId = '';
      var crosshair;
      var basins = -1;
      var cachedCloudLayer = function () {};

      var platform = '';
      var referer = document.referrer;
      if (!referer)
        platform = 'other/unknown';
      else if ((referer.indexOf('//maps.google') > -1) ||
               (referer.search(/google\.[.a-z]+\/maps\//) > -1))
        platform = 'gmaps';
      else if (referer.indexOf('//www.google') > -1)
        platform = 'igoogle';
      else if (referer.indexOf('//mail.google') > -1)
        platform = 'gmail';
      else
        platform = 'other/' + document.referrer.split('/')[2];

      _IG_RegisterOnloadHandler(init);
      function init()
      {
        var url = 'http://rss.wunderground.com/auto/rss_full/tropical/index.xml';
        _IG_FetchXmlContent(url, receiveXML, {refreshInterval: 10 * 60});
        
        basins = Number(prefs.getBool('east_pacific')) + 
                 Number(prefs.getBool('west_pacific')) + 
                 Number(prefs.getBool('central_pacific')) + 
                 Number(prefs.getBool('indian')) + 
                 Number(prefs.getBool('atlantic'));
                 
        if (platform != 'igoogle')
        {
          if (window.addEventListener)
            // W3C DOM Level 2 compliant
            window.addEventListener('resize', windowResize, false);
          else if (window.attachEvent)
            // Most versions of IE
            window.attachEvent('onresize', windowResize);
        }

        // Track this gadget using Google Analytics.
        if (getHeight())
          _IG_Analytics('UA-1556555-7', '/hurricane/' + platform + '/');
      };
      
      function receiveXML(response)
      {
        if (response == null ||
            typeof(response) != 'object' ||
            response.firstChild == null)
        {
          textDiv.innerHTML = '<i>Invalid data.</i>';
          return;
        }
//response = GXml.parse(response)

        var prefs = new _IG_Prefs();
        var storms = response.getElementsByTagName('item');
        var strongest = {wind: 0};
        var nodeList, node;
        var visible = 0;
        var textContent = '<table id="storm_table"><tr><th></th><th>Wind</th>';
        if (basins > 1)
          textContent += '<th>Basin</th>';
        textContent += '<th>Info</th></tr>';

        if (prefs.getString('units') == 'kilometers per hour')
        {
          var conversion = 1.609;
          var unit = 'km/h';
        }
        else if (prefs.getString('units') == 'meters per second')
        {
          var conversion = 0.447;
          var unit = 'm/s';
        }
        else if (prefs.getString('units') == 'knots')
        {
          var conversion = 0.869;
          var unit = 'kts';
        }
        else
        {
          var conversion = 1;
          var unit = 'mph';
        }

        for (var i = 0; i < storms.length; i++) 
        {
          stormData[i] = {};
          nodeList = storms.item(i).childNodes;
          for (var j = 0; j < nodeList.length; j++) 
          {
            node = nodeList.item(j);
            stormData[i][node.nodeName] = getText(node);
          }

          try 
          {
            stormData[i].title = stormData[i].title.split(' - ');
            switch (stormData[i].title[1]) 
            {
              case 'East Pacific':    
                stormData[i].title[1] = 'E.Pacific'; 
                if (!prefs.getBool('east_pacific'))
                  continue;
                break;
  
              case 'Western Pacific': 
              case 'Southern Pacific': 
                stormData[i].title[1] = 'W.Pacific'; 
                if (!prefs.getBool('west_pacific'))
                  continue;
                break;
  
              case 'Central Pacific': 
                stormData[i].title[1] = 'C.Pacific'; 
                if (!prefs.getBool('central_pacific'))
                  continue;
                break;
  
              case 'Indian Ocean':
              case 'North Indian Ocean':
              case 'South Indian Ocean':
              case 'Arabian Sea':
                stormData[i].title[1] = 'Indian';
                if (!prefs.getBool('indian'))
                  continue;
                break;
  
              case 'North Atlantic':  
                stormData[i].title[1] = 'Atlantic';
                if (!prefs.getBool('atlantic'))
                  continue;
                break;
              default:
                continue;
            }
  
            stormData[i].details = stormData[i].description.split('strong>');
  
            stormData[i].wind = stormData[i].details[2].replace(/[|< ]/g, '');
            stormData[i].wind = conversion * parseInt(stormData[i].wind.substr(0, stormData[i].wind.length - 3));
  
            stormData[i].textCoords = stormData[i].details[4].replace(/[|<]/g, '');
            stormData[i].coords = parseCoords(stormData[i].textCoords);
          } 
          catch (e) 
          {
            // WUnderground occasionally has bad/missing data for a particular storm
            continue;
          }

          stormData[i].id = stormData[i].title[0].replace(' ', '');

          textContent += '<tr id="' + stormData[i].id + '" onclick="setFocus(' + i + ')">' +
                           '<td><strong>' + stormData[i].title[0] + '</strong></td>' +
                           '<td class="data">' + stormData[i].wind.toFixed(0) + unit + '</td>';
          if (basins > 1)
            textContent += '<td class="data">' + stormData[i].title[1] + '</td>';
          textContent +=   '<td class="data"><a href="' + stormData[i].link + '" target="_blank">' +
                             '<img src="' + _IG_GetImageUrl('http://www.daylightmap.com/clouds/images/external.png') + '" height="10" width="10" />' + 
                           '</a></td>' + 
                         '</tr>';

          if (stormData[i].wind > strongest.wind)
          {
            strongest.wind   = stormData[i].wind;
            strongest.index  = i;
            strongest.coords = stormData[i].coords;
          }

          visible++;
        }

        textContent += '</table>'; 

        if (visible == 0)
        {
          textDiv.innerHTML = '<p id="none_active">There are currently no tropical advisories.</p>';
        }
        else
        {
          textDiv.innerHTML = textContent;
  
          initMap(strongest.coords);

          var icon = new GIcon(null, _IG_GetImageUrl('http://www.daylightmap.com/clouds/images/crosshair.png'));
          icon.iconSize = new GSize(11, 11);
          icon.iconAnchor = new GPoint(6, 6);
          crosshair = new GMarker(strongest.coords, icon);
          map.addOverlay(crosshair);
  
          setFocus(strongest.index);
        }

        _IG_AdjustIFrameHeight();
      };
      
      function initMap(initCenter)
      {
        cachedCloudLayer.inheritsFrom(cloudLayer);
        cachedCloudLayer.prototype.getTileUrl = function(point, zoom)
        {
          var result = cloudLayer.prototype.getTileUrl.call(this, point, zoom);
//        result = result.replace('\/tiles\/', '\/tiles_test\/');
          return _IG_GetImageUrl(result, {refreshInterval: 10 * 60});
        };

        if (mapDiv &&
            GBrowserIsCompatible())
        {
          mapDiv.style.display = 'block';
          windowResize();

          map = new GMap2(mapDiv, {mapTypes: [G_HYBRID_MAP]});
          
          G_HYBRID_MAP.getMaximumResolution = function() {return 5;};
          G_HYBRID_MAP.getMinimumResolution = function() {return 0;};
    
          var initZoom = 4;
          map.setCenter(initCenter, initZoom);
    
          map.addOverlay(new GTileLayerOverlay(new cachedCloudLayer()));

      	  map.enableDoubleClickZoom();
          map.addControl(new GLargeMapControl(), new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(-16, -61)));
          map.addControl(new GScaleControl(), new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(3, 3)));
        }
      };
      
      function parseCoords(coordString)
      {
        var coords = _trim(coordString).split(' ');

        var lat = parseFloat(coords[0].replace(/[NSEW]/, ''));
        var lon = -parseFloat(coords[1].replace(/[NSEW]/, ''));
          
        return new GLatLng(lat, lon);
      };
      
      function setFocus(index)
      {
        if (focusId != '')
        {
          document.getElementById(focusId).className = '';
          crosshair.setPoint(stormData[index].coords);
          map.panTo(stormData[index].coords);
        }
        focusId = stormData[index].id;
        document.getElementById(focusId).className = 'selected';
      };

      function getText(xmlNode)
      {
        // A cross-browser-compatible function to return the inner text of the given
        // XML node. For example, if the node was "<foo>bar</foo>", would return "bar".
        if (xmlNode.text)
          return xmlNode.text;
        if (xmlNode.data)
          return xmlNode.data;
        else if (xmlNode.innerText)
          return xmlNode.innerText;
        else if (xmlNode.textContent)
          return xmlNode.textContent;
        else if (xmlNode.firstChild)
          return getText(xmlNode.firstChild);
        else if (xmlNode.length > 0)
          return getText(xmlNode[0]);
        else
          return '';
      };

      function windowResize()
      {
        mapDiv.style.height = (getHeight() - getHeight(_gel('storm_table')) - 2) + 'px';
      };

      function getHeight(element)
      {
        if (element == null)
          return Math.max(document.body.scrollHeight, document.body.offsetHeight);
        else
        {
          if (element.innerHeight)
          	return element.innerHeight;
          else
            return element.clientHeight;
        }
      };
      
      String.prototype.pack = function()
      {
        return this.replace(/\s+/g, ' ');
      };

      Function.prototype.inheritsFrom = function (parentClass)
      {
        this.prototype = new parentClass();
        this.prototype.constructor = this;
        this.prototype.parent = parentClass.prototype;
      };
    </script>
  ]]></Content>
</Module> 