<?xml version="1.0" encoding="UTF-8"?>
<Module>

<!-- Copyright (C) 2007 Michael Kosowsky  All rights reserved. -->

<ModulePrefs
    title="Elevation Contours"
    description="Overlay elevation contours almost anywhere in the world"
    author="Michael Kosowsky"
    author_email="contour_mapplet+nospam@heywhatsthat.com"
    author_location="Lincolnville, Maine, USA"
    author_affiliation="heywhatsthat.com"
    screenshot="http://www.heywhatsthat.com/mapplets/contours-screenshot.png"
    thumbnail="http://www.heywhatsthat.com/mapplets/contours-thumbnail.png"
    scrolling="true"
    >
  <Require feature="sharedmap"/>
  <Require feature="setprefs" />
  <Require feature="analytics"/>
  <Require feature="dynamic-height"/>
</ModulePrefs>
<UserPref name="use_metric"     datatype="hidden" default_value="0" />
<UserPref name="degrees_format" datatype="hidden" default_value="0" />
<UserPref name="color"          datatype="hidden" default_value="834225" />
<UserPref name="other_color"    datatype="hidden" default_value="" />
<UserPref name="intervals_m"    datatype="hidden" default_value="1000|1000|0750|0750|0750|0250|0250|0250|200|100|050|050|025|025|25|10|03|03|03|03|03"/>
<UserPref name="intervals_ft"   datatype="hidden" default_value="2500|2500|2500|2500|2500|1000|1000|1000|500|250|100|100|100|100|50|25|10|10|10|10|10"/>
<UserPref name="show_clicks"    datatype="hidden" default_value="1" />

<Content type="html"><![CDATA[
<style type="text/css">
  .rbutton { text-align: right; color: blue; cursor: pointer; text-decoration: underline; -moz-user-select: none }
  .rbutton:hover { color: black }
  .rbutton:visited { color: blue }
</style>

<div style="font-size:12px">

<div class="rbutton"><a class="rbutton" target="_blank" href="http://www.heywhatsthat.com">HeyWhatsThat</a></div>
<div class="rbutton"><a class="rbutton" target="_blank" href="http://www.heywhatsthat.com/mappletfaq.html">FAQ</a></div>
<div class="rbutton" title="Sign up for HeyWhatsThat email updates" onclick="signup()">Sign up</div>
<script>
document.write('<div class="rbutton"><a class="rbutton" target="_blank" href="mailto:comments-contours-mapplet@hey' + '' + 'what' + 'sthat.com">Comments?</a></div>');
</script>


<form name="q" onsubmit="return false">
<p>
<div id="interval_div"></div>
<p>
Set interval: <input size="10" name="interval" onchange="set_interval(this.value)"></input> <span id="u1"></span>
<br>&nbsp;&nbsp;&nbsp;&nbsp;(for current zoom level <span id="zoomlevel_span"> </span>)
<p>

Color:<br>
<input type="radio" name="color" value="834225" onclick="set_color(this.value)">brown</input>
<input type="radio" name="color" value="0000ff" onclick="set_color(this.value)">blue</input>
<input type="radio" name="color" value="other"  onclick="set_color(document.q.other_color.value)">other</input>
<input size="6" name="other_color" onchange="set_color(this.value)"></input> (rrggbb)
<p>
<center>
<input type="submit" value="Redraw" onclick="go()"></input>
</center>
<p>

<!--
Marker at:<br>
&nbsp;&nbsp;<span id="latlon_div"></span>&nbsp;<span id="elev_div"></span>
<p>
-->

<center>
<table style="font-size:10px">
  <tr>
    <td><input type="radio" name="units" value="0" onclick="set_units(0)">English</input></td>
    <td>&nbsp;&nbsp;&nbsp;</td>
    <td><input type="radio" name="degrees_format" value="0" onclick="set_degrees_format(this.value)">DD.DDDDDD&deg;</input></td>
    <td>&nbsp;&nbsp;&nbsp;</td>
    <td><input type="checkbox" name="show_clicks" onclick="set_show_clicks(this.checked)">show clicks</input></td>
  </tr><tr>
    <td><input type="radio" name="units" value="1" onclick="set_units(1)">Metric</input></td>
    <td></td>
    <td><input type="radio" name="degrees_format" value="1" onclick="set_degrees_format(this.value)">DD&deg; MM.MMMM'</input></td>
  </tr><tr>
    <td></td>
    <td></td>
    <td><input type="radio" name="degrees_format" value="2" onclick="set_degrees_format(this.value)">DD&deg; MM' SS.SS"</input></td>
  </tr>
</table>
<input type="submit" value="Reset to defaults" onclick="reset_defaults()"></input>
</center>
</form>

<p>
Change parameters and hit 'Redraw'.
Click on the map to get a location's elevation.
<p>
The elevation data and algorithms we currently use don't do a very good job at zoom level 17 or higher.
<p>
For nice looking contours, also see <a href="http://www.earthtools.org" target="_blank">EarthTools</a>
<p>
<i>
Visit <a href="http://www.heywhatsthat.com" target="_blank">HeyWhatsThat.com</a>
where we show you the summits you can see from almost anywhere in the world.
<p>
This mapplet runs most reliably on <a href="http://www.mozilla.com/firefox" target="_blank">Firefox 1.5 or later</a> at this time.
</i>
</div>

<script>
_IG_Analytics("UA-2222064-1", "/mapplets/contours");
_IG_AdjustIFrameHeight();  // need this and dynamic-height feature as of about 10/20/07
Array.prototype._foreach = function(f) { for (var i = 0; i < this.length; i++) f(this[i]); };
Array.prototype._bounded = function(i) { return this[i < this.length? i : this.length - 1]; };

function encodeURI_more(s) {
  s = encodeURI(s);
  s = s.replace(/\&/g, '%26');
  s = s.replace(/\=/g, '%3D');
  s = s.replace(/\+/g, '%2B');
  return s;
}

function signup() {
  var email = prompt("Give us an email address and\nwe'll send you news about HeyWhatsThat", '');
  if (email)
    _IG_FetchContent('http://www.heywhatsthat.com/bin/subscribe.cgi?src=contoursmapplet&email=' + encodeURI_more(email),
      function(s) {
        var a = s.replace(/\n/g,'');
	if (a)
          alert(a + ' subscribed.  Thanks.');
        else
	  alert('Subscription failed for ' + email);
      }
    );
}

function radio_set(r, v) {
  for (var i = 0; i < r.length; i++) if (r[i].value == v) { r[i].checked = 1; return 1; }
  return 0;
}
function radio_get(r) {
  for (var i = 0; i < r.length; i++) if (r[i].checked) return r[i].value;
  return null;
}
var METERS_PER_FOOT = .3048;
//function units_to_meters(x) {
//  if (x == '')
//    return x;
//  if (use_metric)
//    return Math.round(x);
//  else
//    return Math.round(x * METERS_PER_FOOT);
//}
function meters_to_units0(x) {
  if (x == '' || use_metric)
    return Math.round(x) + ' m';
  return Math.round(x / METERS_PER_FOOT) + ' ft';
}
function round0(x) {
  return Math.round(x);
}
function round1(x) {
  return Math.round(x * 10)/10;
}
function round2(x) {
  return Math.round(x * 100)/100;
}
function round4(x) {
  return Math.round(x * 10000)/10000;
}
function round6(x) {
  return Math.round(x * 1000000)/1000000;
}

// mode is number of parts - 1, e.g. 0 for DD, 1 for 'DDMM', 2 for 'DDMMSS'
function format_angle(x, mode, pos_char, neg_char, is_html) {
  var a = expand_angle(Math.abs(x), mode);
  var s = '';
  var symbols = [is_html? '&deg;' : '', "'", '"'];
  for (var i = 0; i <= mode; i++)
    s += a[i] + symbols[i] + ' ';
  if (x < 0)
    if (neg_char)
      s += neg_char;
    else
      s = '-' + s;
  else
   s += pos_char;

  return s;
}
function expand_angle(x, mode) {
  if (mode == 0)
    return [round6(x)];
  var d = Math.floor(x);
  x = 60 * (x - d);
  if (mode == 1)
    return [d, round4(x)];
  var m = Math.floor(x);
  x = 60 * (x - m);
  return [d, m, round2(x)];
}
function lat_lon_to_string(lat, lon, is_html) {
  return    format_angle(lat, degrees_format, 'N', 'S', is_html)
          + (is_html? '&nbsp;&nbsp;' : '  ')
          + format_angle(lon, degrees_format, 'E', 'W', is_html);
}


function set_degrees_format(d) {
  degrees_format = d;
  radio_set(document.q.degrees_format, degrees_format);
  prefs.set('degrees_format', degrees_format);
  show_marker_position(0);
}
function set_units(u) {
  use_metric = u;
  radio_set(document.q.units, use_metric);
  prefs.set('use_metric', use_metric);
  document.getElementById("u1").innerHTML = use_metric? 'm' : 'ft';
  show_marker_position(0);
  if (current_zoom != null) reset_interval();
}
function set_other_color(s) {
  document.q.other_color.value = s;
  prefs.set('other_color', s);
}
function set_color(s) {
  if (!radio_set(document.q.color, s)) {
    set_other_color(s);
    radio_set(document.q.color, 'other');
  }
  prefs.set('color', s);
  color = s + '30';  	// transparency 30
}
function set_show_clicks(s) {
  prefs.set('show_clicks', s);
  document.q.show_clicks.checked = s;
  if (s) {
    if (!mapclick_listener)
      mapclick_listener = GEvent.addListener(map, "click", mapclick);
  } else {
    map.closeInfoWindow();
    if (mapclick_listener) {
      GEvent.removeListener(mapclick_listener);
      mapclick_listener = null;
    }
    if (plus_marker) {
       map.removeOverlay(plus_marker);
       plus_marker = null;
    }
  }
}

function set_all_intervals_m(s) {
  intervals_m = [];
  s.split('|')._foreach(function(i) { intervals_m.push(i - 0); });
  prefs.set('intervals_m', intervals_m.join('|'));
}
function set_all_intervals_ft(s) {
  intervals_ft = [];
  s.split('|')._foreach(function(i) { intervals_ft.push(i - 0); });
  prefs.set('intervals_ft', intervals_ft.join('|'));
}
function set_interval_m(zoom, x) {
  if (x < min_intervals_m._bounded(zoom)) {
    alert('Minimum at this zoom is ' + min_intervals_m._bounded(zoom));
    reset_interval();
    return;
  }
  intervals_m[zoom] = x;
  prefs.set('intervals_m', intervals_m.join('|'));
}
function set_interval_ft(zoom, x) {
  if (x < min_intervals_ft._bounded(zoom)) {
    alert('Minimum at this zoom is ' + min_intervals_ft._bounded(zoom));
    reset_interval();
    return;
  }
  intervals_ft[zoom] = x;
  prefs.set('intervals_ft', intervals_ft.join('|'));
}
function set_interval(x) {
  if (isNaN(x - 0))
    x = '';
  if (use_metric)
    set_interval_m(current_zoom, x);
  else
    set_interval_ft(current_zoom, x);
}
function reset_interval() {
  document.q.interval.value = use_metric? intervals_m._bounded(current_zoom) : intervals_ft._bounded(current_zoom);
}

function show_marker_position(open) {
  if (!plus_marker || !marker_lat)
    return;
  var s = lat_lon_to_string(marker_lat, marker_lon, 1);
  if (marker_elev)
    s += '<br>&nbsp;&nbsp;&nbsp;' + meters_to_units0(marker_elev);
  plus_marker.openInfoWindowHtml('<small>' + s + '</small>', { disableGoogleLinks: true });
}


var marker_lat;
var marker_lon;
var marker_elev;
var getelev_timeout;

function mapclick(overlay, point) {
  if (plus_marker && overlay == plus_marker) {
    show_marker_position(1);
    return;
  } 
  if (!point)
    return;

  if (plus_marker) {
    plus_marker.setPoint(point);
  } else {
    plus_marker = new GMarker(point, { icon: icon_plus, clickable: true });
    map.addOverlay(plus_marker);
  }

  marker_lat = point.y;
  marker_lon = point.x;
  marker_elev = null;

  if (getelev_timeout)
    clearTimeout(getelev_timeout);
  getelev_timeout = setTimeout(function() { getelev_timeout = null; show_marker_position(1); }, 1000);

  _IG_FetchContent('http://www.heywhatsthat.com/bin/points.cgi?lat0=' + marker_lat + '&lon0=' + marker_lon,
    function(s) {
      var a = s.split(' ');
      if (Math.abs(a[0] - marker_lat) < .000001 && Math.abs(a[1] - marker_lon) < .000001) {
        if (getelev_timeout) {
	  clearTimeout(getelev_timeout);
	  getelev_timeout = null;
        }
        marker_elev = a[2];
	show_marker_position(1);
	//elev_div.innerHTML = meters_to_units0(marker_elev);
      }
    });
}

function newzoom(oldz, newz) {
  current_zoom = newz;
  document.getElementById('zoomlevel_span').innerHTML = newz;
  reset_interval();
        // BUG: gmaps starts requesting tiles before we get the chance to change the template,
	//  but we can't use 'zoom={Z}' below because the interval would be all wrong
  go();
}

function go() {
  var interval = use_metric? intervals_m._bounded(current_zoom) : round6(intervals_ft._bounded(current_zoom) * METERS_PER_FOOT);
  if (interval <= 0) { // || current_zoom >= 17
    interval_div.innerHTML = '<i>Contours not available at this zoom level</i>';
    return;
  }
  if (tile_overlay)
    map.removeOverlay(tile_overlay);
  tile_overlay = new GTileLayerOverlay(new GTileLayer(copyright_collection, copyright_min_zoom, copyright_max_zoom, {
    tileUrlTemplate: 'http://contour.heywhatsthat.com/bin/contour_tiles.cgi'
               + '?src=contourmapplet'
  	       + '&color='    + color
	       + '&interval=' + interval
	       + '&zoom='     + current_zoom
	       + '&x={X}&y={Y}' }));
  map.addOverlay(tile_overlay);
  interval_div.innerHTML = 'Contour interval ' + meters_to_units0(interval);
}

function reset_defaults() {
  set_degrees_format(0);
  set_other_color('');
  set_color('834225');
  set_all_intervals_m(default_intervals_m);
  set_all_intervals_ft(default_intervals_ft);
  set_units(0);
  set_show_clicks(1);
  go();
}


var map = new GMap2();
var prefs = new _IG_Prefs(__MODULE_ID__);

var latlon_div = document.getElementById('latlon_div');
var elev_div   = document.getElementById('elev_div'); 
var interval_div   = document.getElementById('interval_div');

var current_zoom;
var use_metric;
var degrees_format;
var color;
var intervals_m;
var intervals_ft;

var tile_overlay;

var plus_marker;
var mapclick_listener;

var default_intervals_m  = "1000|1000|0750|0750|0750|0250|0250|0250|200|100|050|050|025|025|25|10|03|03|03|03|03";
var default_intervals_ft = "2500|2500|2500|2500|2500|1000|1000|1000|500|250|100|100|100|100|50|25|10|10|10|10|10";

var min_intervals_m = [];
default_intervals_m.split('|')._foreach(function(i) { min_intervals_m.push(Math.round(.33 * i)); });
var min_intervals_ft = [];
default_intervals_ft.split('|')._foreach(function(i) { min_intervals_ft.push(Math.round(.33 * i)); });

set_degrees_format(prefs.getInt("degrees_format"));
set_other_color(prefs.getString("other_color"));
set_color(prefs.getString("color"));
set_all_intervals_m(prefs.getString("intervals_m"));
set_all_intervals_ft(prefs.getString("intervals_ft"));
set_units(prefs.getInt("use_metric"));
set_show_clicks(prefs.getInt("show_clicks"));

//var copyright_min_zoom = 0;
//var copyright_max_zoom = 17;
//var copyright_collection = new GCopyrightCollection('Contours (C) 2007');
//copyright_collection.addCopyright(new GCopyright(2, new GLatLngBounds(new GLatLng(-54,-180), new GLatLng(60,180)), copyright_min_zoom, 'Michael Kosowsky'));
var copyright_min_zoom = null;
var copyright_max_zoom = null;
var copyright_collection = null;

var icon_plus              = new GIcon();
icon_plus.image            = "http://www.heywhatsthat.com/images/black-plus.png";
icon_plus.shadow           = null;
icon_plus.iconSize         = new GSize(24, 24);
icon_plus.shadowSize       = new GSize(0, 0);
icon_plus.iconAnchor       = new GPoint(12, 12);
icon_plus.infoWindowAnchor = new GPoint(12, 12);

GEvent.addListener(map, "zoomend", newzoom);

map.getZoomAsync(function(zoom) {
  newzoom(0, zoom);
});

</script>

]]></Content>
</Module>
