// jhm_pedometer.js   V3.1
// Implements a dydnamic pedometer on Google Maps
// Part of the JH Map system
// Requires Google Maps  (V2)
// 5/10/09 added onmousemove and display
// 10/12/09 Fixed for Degree symbol in input
// 11/1/09 Added "Delete" processing
// 12/17/09 fixed for lng before lat -- from XTide

// Copyright 2007, 2009, Jeff Hennick jhm_system AT jeff-h.com
// See jhm_inc.php for GPL license details.

//////  Pedometer  //////

function HAddElement(t,p) {  // add a DOM node
 var nel = document.createElement(t);
 for (var i = 2; i < arguments.length; i+=2) {
  nel.setAttribute(arguments[i],arguments[i+1]);
 }
 var pn = document.getElementById(p);
 pn.appendChild (nel);
}

function HAddTextNode(p,t) { // add a text node
 var t = document.createTextNode(t);
 var p = document.getElementById(p);
 p.appendChild(t);
}

function HonLoadPed() {
 GEvent.addListener(map, "click", function(overlay, point) {HAddSegPoint(point)});
 GEvent.addListener(map, "mousemove", function(point) {HmouseMove(point)});
 GEvent.addListener(map, "singlerightclick", function(point,scr,overlay) {alert(point + ', src=' + src)});    ///////////// ????? /////////
}


HOnLoadJ('HonLoadPed');

HPedDisp = 0; // It is not yet displayed.

var HWPD = 0;
var HWPNum = 1;
var HWPNumMk = [];
var HEMark;
var HWPMk = [];

var HTDist = '';
var HWPN = '';

var HPList = [];
var HPLpt = 1;
var HPedSeg = [];
    HPedSeg[0] = 0;
var HTDistMv = 0;
var HWPList = [];  // indexed by points. sparce. value: waypoint number
var HWPDist = [];
    HWPDist[0] = 0;
var HToAddress = "";

var HRecord = 0;
var HWPRecord = 0;

var HMFac = 0.621371192;
var HShowDetails = 0;
var HShowElevation = 0;
var HFDeg = 0;  // 0: D 1: DM 2: DMS

var HElId = 0;
var HRId = 0;
var Hfirstwp = 'Start';

var HAJAXn = 0;
var HTMark = '';
var HeditTr = 0;
var HMoveN;
var HMoveS;

var HMWPm;
var HMWPp = 1;
var HEPoly = '';

var HLastWP = '';

var Hpp = new GPoint(0,0);
var Hzero = Hpp;
var Htotd = 0;
var Hddd = 0;

var HEditSeg;

function HReshow() {
 HElId = 0;
 HRId = 0;
 HPLpt = 1;
 var pts = HPList;
 var wps = HWPList;
 HUndoPed(1);
 HWPNum = 1;
 var oHR = HRecord;
 HRecord = 1;
 var j = 0;
 for(var i=0;i<pts.length;i++) {
  HAddSegPoint(pts[i]);
  if (wps[i] != null) {
   HAddWayPoint(wps[i]);
   j++;
  }
 }
 HEndAdd();
 var exim = document.getElementById('HExIm')
 if (exim) exim.className = (HShowDetails) ? 'HShow' : 'HHide';
 HRecord = oHR;
}

function HTMOver(num, rid) {
 HTMOut(rid);
 if (HPList[num]) {
  HTMark = new GMarker(HPList[num], HWPMarker);
  map.addOverlay(HTMark);
 }
 document.getElementById(rid).style.color = 'red';
 var d = document.getElementById('HPwpDispData');
 var dd = document.getElementById(rid).firstChild.innerHTML.replace(' ', '');
 if (dd == '') dd = '-';
 if (d) d.innerHTML = dd;
}

function HTMOut(rid){
 map.removeOverlay(HTMark);
 document.getElementById(rid).style.color = 'black';
}

function HmouseMove(p) {
var distbox = document.getElementById('Hddd');
  if (Hpp == Hzero) {
  }
  else {
   Hddd = HMFac * Hpp.distanceFrom(p) * .001;
   distbox.innerHTML = Hddd.toFixed(4)  + 'mi (' + parseInt(Hddd * 5280, 10) + "'), " + (Htotd + Hddd).toFixed(4);
  }
}

function HChangeWP(rn) {
 var col = (HShowDetails) ? 4 : 0
 var rid = parseInt(rn, 10);
 rid = 'R' + rid
 var row = document.getElementById(rid);
 var cn = row.getElementsByTagName('td');
 HWPList[rn] = cn[col].firstChild.value;
}

function HAddSegPoint(point){
 if (!point) return;
 if (!isNaN(point.lat())) {
 }
 if (HRecord) {
  HElId++;
  HRId++;
  var rid = 'R' + HRId;
  HPList[HPLpt] = point;
  var x = point.lng().toString().substr(0,9);   // "-" for west
  var y = point.lat().toString().substr(0,8);
  if (HPLpt == 1) {  // Starting the table
   var fwp = HWPList[0] || Hfirstwp;
   HWPNumMk[0] = point;
   HWPMk[0] = HCreateNumMarker(HPList[1],0);
   map.addOverlay(HWPMk[0]);
   if (HShowDetails) {
    HAddElement('tr','HTB','id',rid, 'onmouseover', 'HTMOver("' + HPLpt +'","' +  rid + '")', 'onmouseout', 'HTMOut("' +  rid + '")' );
    HAddElement('td',rid,'id',0 + rid);
    HAddTextNode(0 + rid,HDeg2DMS(y,1) + ", " + HDeg2DMS(x,1));
    HAddElement('td',rid,'id','HE' + HElId,'name','HEl','class','Hml');
    HAddElement('td',rid,'id',1 + rid,'class','Hml');
    HAddTextNode(1 + rid,'0');
    HAddElement('td',rid,'name','HDis','id',2 + rid);
    HAddTextNode(2 + rid,'0');
    var tds = document.getElementById(2 + rid);
    tds.setAttribute('id','HDis');
    HAddElement('td',rid,'id',3 + rid);
    HAddElement('input',3 + rid, 'value', fwp, 'onchange', 'HChangeWP("' + HPLpt + '")');

    HAddElement('td',rid,'id',4 + rid, 'value', 'E', 'onclick', 'HDelWP("' + (HPLpt - 1) + '")');
//GLog.write('217 ' + (4 + rid));
    HAddTextNode(4 + rid,'Delete');
   } // HShowDetails
   else { // !HShowDetails
    HAddElement('tr','HTB','id',rid, 'onmouseover', 'HTMOver("' + HPLpt +'","' +  rid + '")', 'onmouseout', 'HTMOut("' +  rid + '")' );
    HAddElement('td',rid,'name','HDis','id',2 + rid);
    HAddElement('input',2 + rid, 'value', fwp, 'onchange', 'HChangeWP("' + HPLpt + '")');
    var tds = document.getElementById(2 + rid);
    tds.setAttribute('id','HDis');
    HAddElement('td',rid,'id',3 + rid);
    HAddTextNode(3 + rid,'0');
    HAddElement('td',rid,'id',4 + rid);
    HAddTextNode(4 + rid,'0');
   } // !HShowDetails
  }
  else { // not zero point
   var ddm = point.distanceFrom(HPList[HPLpt-1]) * .001;
/*
   if ((isNaN(ddm) || ddm < .01)) {   // automatically remove if close to previous
    HElId--;
    HRId--;
    return
   }
*/
   HWPD += ddm;
   HPedSeg[HPLpt] = ddm;
   HTDistMv += ddm;
   if (HShowDetails) {
    HAddElement('tr','HTB','id',rid, 'onmouseover', 'HTMOver("' + HPLpt +'","' +  rid + '")', 'onmouseout', 'HTMOut("' +  rid + '")' );
    HAddElement('td',rid,'id',0 + rid);
    HAddTextNode(0 + rid,HDeg2DMS(y,1) + ", " + HDeg2DMS(x,1));
    HAddElement('td',rid,'id','HE' + HElId,'name','HEl','class','Hml');
    HAddElement('td',rid,'id',1 + rid,'class','Hml');
    HAddTextNode(1 + rid,(HMFac*ddm).toFixed(2));
    HAddElement('td',rid,'name','HDis','id',2 + rid);
    HAddTextNode(2 + rid,(HMFac*HTDistMv).toFixed(2));
    var tds = document.getElementById(2 + rid);
    tds.setAttribute('id','HDis');
    HAddElement('td',rid,'id',3 + rid);
    HAddElement('input',3 + rid, 'value', 'E', 'onchange', 'HChangeWP("' + HPLpt + '")');

    HAddElement('td',rid,'id',4 + rid, 'value', 'E', 'onclick', 'HDelWP("' + (HPLpt - 1) + '")');
//GLog.write('217 ' + (4 + rid));
    HAddTextNode(4 + rid,'Delete');

    if (HRId > 1) {
     var pr = HRId - 1;
     var tds = document.getElementById("R" + pr).childNodes;
     var inp = tds[4].childNodes;
     if (inp[0].value == 'E') {
        inp[0].value = '';
     }
    }
   } //HShowDetails
   else { // !HShowDetails
    HRId--;
    var tds = document.getElementById("R" + HRId).childNodes
    var inp = tds[0].childNodes;
    if (inp[0].value == 'E') {
     var t = document.getElementById('HTB');
     var r = document.getElementById("R" + HRId);
     t.removeChild(r);
    }
     HAddElement('tr','HTB','id',rid, 'onmouseover', 'HTMOver("' + HPLpt +'","' +  rid + '")', 'onmouseout', 'HTMOut("' +  rid + '")' );
     HAddElement('td',rid,'name','HDis','id',2 + rid);
     HAddElement('input',2 + rid, 'value', 'E', 'onchange', 'HChangeWP("' + HPLpt + '")');
     var tds = document.getElementById(2 + rid);
     tds.setAttribute('id','HDis');
     HAddElement('td',rid,'id',3 + rid);
     HAddTextNode(3 + rid,(HMFac*HWPD).toFixed(2));

     HAddElement('td',rid,'id',4 + rid);
     HAddTextNode(4 + rid,(HMFac*HTDistMv).toFixed(2));

     HRId++;
   } // !HShowDetails
  }
  HPLpt++;
 }
 Hpp = point;
 Htotd += Hddd;
}

function HDelWP(n) {
 n = parseInt(n);
//GLog.write('260 ' + n + ', ' + HPList.length);
// if(n == HPList.length - 2) return;   // workaround becuse can't remove the last listener ???
//GLog.write('258 n = ' + n + ', HPList[n] = ' + HPList[n] + ', HPList[n+1] = ' + HPList[n+1]);
 HEditSeg.deleteVertex(n);
 HPList[n+1] = null;
 var rnum = n + 1;
 var rid = 'R' + rnum;
 document.getElementById(0 + rid).innerHTML = '';
 document.getElementById(4 + rid).innerHTML = '';
 document.getElementById(4 + rid).removeEventListener('onclick',HDelWP,false);
 document.getElementById('HPwpDispData').innerHTML = '-';
}

function HEndAdd() {
 HOverlayList[HsegNum] = new GPolyline(HPList, "#FF0000", 5);
 map.addOverlay(HOverlayList[HsegNum]);
 GEvent.addListener(HOverlayList[HsegNum], "click", function(point) {HTrailClick(point,HsegNum,'')})
 HsegNum++;
 if (HEMark) map.removeOverlay(HEMark);
 if (HPList.length > 0) {
  HEMark = HCreateNumMarker(HPList[HPLpt-1],HWPNum);
  map.addOverlay(HEMark);
 }
 var col = (HShowDetails) ? 4 : 0;
 var pr = HPLpt - 1;
 if (document.getElementById("R" + pr)) {
  var tds = document.getElementById("R" + pr).childNodes;
  var inp = tds[col].childNodes;
  if (inp[0].value == 'E') inp[0].value = (HLastWP == '') ? 'End' : HLastWP;
  if (HShowDetails) {
//   tds[5].removeEventListener('onclick',HDelWP,false);
//GLog.write('289 ' + (4 + "R" + pr));
// document.getElementById(4 + "R" + pr).removeEventListener('onclick',HDelWP,false);
//   tds[5].innerHTML = '';
  }
 }
}

function HAddElevs() {
 var b = document.getElementById('HTB');
 var rows = b.childNodes;
 var latlon = HToText(1).split(',');
 var n = 0;
 for (var i = 0; i < rows.length; i++) {
  if (isNaN(latlon[n])) {
   n++;
   i--;
   continue;
  }
  var cells = rows[i].childNodes;
  if ( cells[1].innerHTML == '') HGetElevation(latlon[n],latlon[n+1],cells[1].id, 'HEl');
  n += 2;
 }
}

function HAddWayPoint(n,line) {
 if (n) while (n[0] == ' ') n = n.substr(1);
 else n = '';
 if (n[0] == '"' || n[0] == "'") {
  if (n[n.length-1] == n[0]) {
   n = n.substr(1,n.length - 2);
  }
 }
 if (line) var rid = 'R' + line;
 else var rid = 'R' + HRId;

 HWPList[HPLpt-1] = n;
 if (HPList[HPLpt-1] != undefined){
  HWPNumMk[HWPNum] = new GLatLng(HPList[HPLpt-1].lat(),HPList[HPLpt-1].lng());
  HWPMk[HWPNum] = HCreateNumMarker(HPList[HPLpt-1],HWPNum);
  if (HEMark) map.removeOverlay(HEMark);
  map.addOverlay(HWPMk[HWPNum]);
  HWPDist[HWPNum] = HMFac*HTDistMv;

  if (HShowDetails) {
   var tds = document.getElementById("R" + HRId).childNodes;
   tds[4].childNodes[0].value = n
  }
  else { //! HShowDetails
   var tds = document.getElementById("R" + HRId).childNodes;
   tds[0].childNodes[0].value = n
  }
  HWPD = 0;
  HWPNum++;
 }
}

function HUndoPed(all) {
 if (all || HPLpt < 1) {
  if (HEMark) map.removeOverlay(HEMark);
  for (var i=0;i<HWPMk.length;i++) {
   map.removeOverlay(HWPMk[i]);
  }
  var b = document.getElementById("Hrec_tab");
  if (b) {
   var th = b.getElementsByTagName("thead");
   var rs = th[0].childNodes;
   if (rs.length > 0) for (var i=rs.length-1;i>-1;i--) {
    th[0].removeChild(rs[i]);
   }
   var th = document.getElementById("HTB");
   var rs = th.childNodes;
   if (rs.length > 0) for (var i=rs.length-1;i>-1;i--) {
    th.removeChild(rs[i]);
   }
   var th = document.getElementById("HTF");
   var rs = th.childNodes;
   if (rs.length > 0) for (var i=rs.length-1;i>-1;i--) {
    th.removeChild(rs[i]);
   }
  }

  HWPD = 0;
  HWPNum = 1;
  HWPNumMk = [];
  HWPMk = [];

  HTDist = '';
  HWPN = '';

  HRId = 0;
  HPList = [];
  HPLpt = 1;
  HPedSeg = [];
  HPedSeg[0] = 0;
  HTDistMv = 0;
  HWPList = [];

  if (HMWPm) map.removeOverlay(HMWPm);
  HMWPm = null;
  HMWPp = 1;

  b = document.getElementById('Hrtd');

  if (HShowDetails) {
   HMakeHeadRow("Latitude, Longitude","\u00a0  Elev. ","\u00a0   Seg.","\u00a0 Tot. ","\u00a0 Way Point ");
   if (b) {
    var o = "<button onclick='HAddElevs()'>Add Elevations<\/button> &nbsp;<button id=HShGrB onclick='HShowGraph()'>Show Graph<\/button> <input type=radio name=Hdms id=HDFcb onclick='HDMS(0)' checked>&deg;<input type=radio name=Hdms onclick='HDMS(1)'>&deg; '<input type=radio name=Hdms onclick='HDMS(2)'>&deg; '";
    o += "\n<br>Track Way Points: <button id=HMWPcbd onclick='HMWP(-1)'>&lt;</button><button id=HMWPcb onclick='HMWP(0)'>WP</button><button id=HMWPcbu onclick=HMWP(1)>&gt;</button>";
    o += "\n<table id=HPwpDisp style=color:red align=center><tr><td id=HPwpDispData>-</td></tr><tr><td></td></tr></table>";
    b.innerHTML = o;
    document.getElementById('HMWPcbd').disabled = true;
    document.getElementById('HMWPcbu').disabled = true;
   }
  }
  else {
   HMakeHeadRow("Way Point","Seg.","Tot.");
   if (b) b.innerHTML = " ";
  }
  HMakeHeadRow(" ");
 }  // one line
/*
 else {  // There are much faster ways of doing this.  Ran into complications of details, waypoints, first lines, etc.
  HPList.pop();
  HTDistMv -= HPedSeg.pop();
  HReshow();

  map.removeOverlay(HPLine);
  if (HPList.length > 0) {
   HPLine = new GPolyline(HPList, "#FF0000", 5);
   map.addOverlay(HPLine);
  }

  map.removeOverlay(HEMark);
  if (HPLpt > 1) {
   HEMark = new GMarker(HPList[HPList.length -1], HEMarker);
   map.addOverlay(HEMark);
  }
 }
*/
}

function HMakeHeadRow() {
 var hr = document.createElement('tr');
 for (var i = 0; i < arguments.length; i++) {
  var h = document.createElement('th');
  var t = document.createTextNode(arguments[i]);
  h.style.textAlign = 'center';
  h.appendChild (t);
  hr.appendChild (h);
 }
 var p = document.getElementById('Hrec_tab');
 if (p) {
  var th = p.firstChild;
  th.appendChild(hr);
 }
}

function HShowGraph() {
 if(HShowDetails) {
  var d = document.getElementsByName('HDis');
  var x = '';
  for (var i = 0; i < d.length; i++) {
   x += "," + d[i].innerHTML;
  }
  x = x.substr(1);

  var y = '';
  var d = document.getElementsByName('HEl');
  for (var i = 0; i < d.length; i++) {
   y += "," + d[i].innerHTML;
  }
  y = y.substr(1);

  var wpd = ''
  var wpn = ''
  var t = document.getElementById('HTB');
  var ra = t.getElementsByTagName('tr');
  var c = 0;
  for (var i = 0; i<ra.length;i++) {
   var cn = ra[i].getElementsByTagName('td');
   if (cn[4] && cn[4].firstChild.value != '') {
    wpd += "," + cn[3].innerHTML;
    wpn += "," + cn[4].firstChild.value;
    c++;
   }
  }

  wpd = wpd.substr(1);
  wpn = wpn.substr(1);
  wpd = wpd.replace(/ */g,'');

  var w = 0;
  var h = 0;
  var d = document.getElementById('HPImg');
  if (d) {
   w = d.width;
   h = d.height;
  }

  if (!w || w == undefined || w == 0) w = 900;
  if (!h || h == undefined || h == 0) h = 400;

  var url = 'jhm_draw_graph.php';

  // Remove old graph
  ne = document.getElementById('HPImg_i');
  if (ne) ne.parentNode.removeChild(ne);

  // Create new image element
  var jsel = document.createElement('IMG');
  jsel.type = 'image/gif';
  jsel.type = 'text/html';
  jsel.height = h;
  jsel.width = w;
  jsel.id = 'HPImg_i';
  jsel.src = url  + '?x=' + x + '&y=' + y + '&wpd=' + wpd + '&wpn=' + wpn + '&h=' + h + '&w=' + w;
  jsel.alt = "Graph of Elevations";

  // Append JS element (therefore executing the 'AJAX' call for the graph)
  d.appendChild (jsel);
 }
}


function HTogRecord(button) {
 if (button == 'HRecBut') {
  HRecord = !HRecord;
  HClickProc = !HClickProc;
 }
 var rb = document.getElementById(button);
 if (HRecord) rb.innerHTML = 'Stop';
 else rb.innerHTML = 'Start';
}

function HGetWayPoints() {
  var wpl = [];
  var t = document.getElementById('HTB');
  var ra = t.getElementsByTagName('tr');
  for (var i = 0; i<ra.length;i++) {
   var cn = ra[i].getElementsByTagName('td');
   if (cn[4] && cn[4].firstChild.value != '') {
    wpl[i] = cn[4].firstChild.value;
   }
  }
  return wpl;
}

function HToText(email) {
 var o = '';
// var w = 0;
 var fsep = ',';
 var ssep = ', ';

 var wwp = document.getElementById('HWithWP').checked;
 var wwpq = document.getElementById('HWithWPq').checked;

 var wpl = []
 if (wwp || wwpq) wpl = HGetWayPoints();

 for(var i=1;i < HPList.length;i++) {
  if (HPList[i] == null) continue;
  var x = parseFloat(HPList[i].lng());    // Why some comes as string???
  var y = parseFloat(HPList[i].lat());
  var t = (wpl[i-1]) ? wpl[i-1].replace("'","\\'") : null;
  o += (email) ? y + ',' + x : HDeg2DMS(y.toFixed(5)) + fsep + HDeg2DMS(x.toFixed(5));
  if (t != null) {
   if (i == 1) {
    o += (wwp) ? ',"' + t + '"': '';
    o = (wwpq) ? "'" + t + "'," + o : o;
   }
   else {
    o += (wwp) ? ',"' + t + '"': '';
    o += (wwpq) ? ",'" + t + "'": '';
   }
  }
  o += ssep;
 }
// if (w == 1) o = o.replace(/'wp0',/, "");
 o = o.substr(0,o.length-2);
 if (email) return o;
 else {
  var b = document.getElementById("HToTextId");
  b.value = o;
 }
}

function HCloseEmail() {
 var b = document.getElementById('HMailBox');
 var p = b.parentNode;
 p.removeChild(b);
}

function HToEmail(toadr) {
 if (!toadr) toadr = '';
 var latlon = HToText(1);
 var o = '';
 o += "<br>Response: <div id=HMailResponse></div>"
 o += "\n<div id=HMailBox style='border:solid red'>";
 o += "\n<span class=centered>Email Selected Path</span>";
 if (latlon.length == 0) o+= "\n<div style='color:red'>Select a path by clicking \"Start\" then clicking on the map. Then click \"Email Path\" again.</div>";
 o += "\n<input type=hidden id=Hlatlon name=Hlatlon value=\"" + latlon + "\">";
 o += "\n<input type=hidden id=Hhtmlreturn name=Hhtmlreturn value=\"" + MapFile + "\">";
 o += "\n<br>To: <input type=text id=Hto name=Hto size=50 maxlength=200 value=" + toadr + ">(Full email address(es), separated by commas.)";
 o += "\n<br>From: <input type=text id=Hfrom name=Hfrom size=50 maxlength=200>(Your email address for CC.)";
 o += "\n<br>Subject: <input type=text id=Hsubject name=Hsubject size=50 maxlength=200 value='Request for map update'>";
 o += "\n<br><br>Group:";

 o += "\n<select id=Hgroup name=Hgroup>\n<option selected>Other (use comments)</option>";
 for (var j in Hl1) {
  o += "\n<option>" + Hl1[j] + "</option>";;
 }
 o += "\n</select>";

 o += "\n<br>Trail Name:";
 o += "<input type=text id=Htrailname name=Htrailname>";
 o += "\n<br><br><label>Color:";
 o += "<select id=Hcolor name=Hcolor>";
 o += "\n<option value='other' selected>Other (use comments)</option>";
 o += "<option value=#000000>Black</option>";
 o += "<option value=#804000>Brown</option>";
 o += "<option value=#ff0000>Red</option>";
 o += "<option value=#ff8040>Orange</option>";
 o += "<option value=#ffff00>Yellow</option>";
 o += "<option value=#00ff00>Green</option>";
 o += "<option value=#0000ff>Blue</option>";
 o += "<option value=#800080>Violet</option>";
 o += "<option value=#808080>Grey</option>";
 o += "<option value=#ffffff>White</option>";
 o += "\n</select></label>";
 o += "\n<br>Transparency: ";
 o += "\n<select id=Hopacity name=Hopacity>";
 o += "\n<option value=.1>10% (very faint)</option>";
 o += "<option value=.2>20%</option>";
 o += "<option value=.3>30%</option>";
 o += "<option value=.4>40%</option>";
 o += "<option value=.5>50%</option>";
 o += "<option value=.6>60%</option>";
 o += "<option value=.7 selected>70%</option>";
 o += "<option value=.8>80%</option>";
 o += "<option value=.9>90%</option>";
 o += "<option value=1>100% (covers anything)</option>";
 o += "\n</select>";
 o += "\n<br>Width (pixels): ";
 o += "\n<select id=Hwidth name=Hwidth>";
 o += "\n<option value=1>1</option>";
 o += "<option value=2>2</option>";
 o += "<option value=3 selected>3 (footpath)</option>";
 o += "<option value=4>4</option>";
 o += "<option value=5>5</option>";
 o += "<option value=6>6</option>";
 o += "<option value=7>7</option>";
 o += "<option value=8>8</option>";
 o += "<option value=9>9 (improved multiuse)</option>";
 o += "\n</select>";
 o += "\n<br><br>InfoWindow (Shown when trail is clicked. Optional):<br><textarea id=HinfoWindow name=HinfoWindow rows=5 cols=40></textarea>";
 o += "\n<br><br>Comments: <textarea id=Hcomments name=Hcomments rows=5 cols=80></textarea>";
 o += "\n<br>Your Name:";
 o += "\n<input type=text id=Hsender name=Hsender size=50>";
 o += "\n<button name='button' onclick='HAjaxPost(\"jhm_mailsender.php\",";
 o += "\"Hlatlon\",\"Hhtmlreturn\",\"Hto\",\"Hfrom\",\"Hsubject\",\"Hgroup\",\"Htrailname\",\"Hcolor\",";
 o += "\"Hopacity\",\"Hwidth\",\"HinfoWindow\",\"Hcomments\",\"Hsender\");HCloseEmail();'>";
 o += "Send</button>"
 o += "\n<button onclick=HEmailCan()>Cancel</button>";

 o += "\n</div>";
 var ms = document.getElementById('HMailDiv');
 if (ms) ms.innerHTML = o;
 ms = document.getElementById('HEmail');
 ms.className = 'HShow';
}

function HEmailCan() {
 ms = document.getElementById('HEmail');
 ms.className = 'HHide';
}

function HToLL(o,wp) {   // Text to LatLon
 var pts_supplied = 0;
 if (!o || o == '') {
  var b = document.getElementById("HToTextId");
  var o = b.value;
  o = o.toLowerCase();
  o = o.replace(/,?\n/g,", ");
 }
 else pts_supplied = 1;

 var hrec = HRecord;
 HRecord = 1;

 var wpa = new Array();
 if(wp) {
  for(;wp != '';) {
   var pc = wp.indexOf(',');
   if (pc == -1) break;
   var y = wp.substr(0, pc);
   wp = wp.substr(pc+1);
   pc = wp.indexOf(',');
   if (pc == -1) {
    var x = wp;
    wp = '';
   }
   else {
    var x = wp.substr(0, pc);
    wp = wp.substr(pc+1);
   }
   x = x.replace(/[+ ]g/, '');
   y = y.replace(/[+ ]g/, '');
   wpa.push(new GLatLng(y,x));
  }
 }

 var firstwp = ''; // delay waypoint if it is first thing
 for(var i=0;o != '';i++) {
  o = trim(o);
  pc = o.indexOf(',');
  if (pc == -1) pc = o.indexOf("\t");
//  if (pc == -1) {pc = o.indexOf("\n");alert("714 " + pc);}
  if (pc == -1) {
   if (o.indexOf("w") > 1) pc = o.indexOf("w") - 1;  // needs generalization, but works for today's input  // ??
   else if (o.indexOf("x:") > -1) {    // OnCOR data
    var px = o.indexOf("x:");
    var py = o.indexOf("y:");
    if (py > -1) {
     if (py > px) {
      var lat = o.substr(py + 3);
      var lon = o.substring(px +3,py);
      pc = (o + ' ').indexOf(' ',py + 3);
      o = lat + ',' + lon + ',' + o.substr(pc)
      pc = o.indexOf(',');
     }
    }
   }
  }
//  if (pc == -1) pc = o.indexOf(' ');
  if (pc == -1) {
   if (o != '') HAddWayPoint(o);
   break;
  }

  var first = o.substr(0, pc);

  if (first.indexOf("w") > -1 || first.indexOf("e") > -1 ) { // lng (x) is first
   o = o.substr(pc+1);
   pc = o.indexOf(',');
   if (pc == -1) pc = o.indexOf("\n");
   if (pc == -1) pc = o.indexOf("\t");
   if (pc == -1) {
    var pn = o.indexOf('n');
    if (pn < 1) pc = o.indexOf(" ");
   }
   var sec = o.substr(0, pc);
   if (sec == '') {
    sec = o;
    o = '';
   }
   o = o.substr(pc+1);
   o = (o == '') ? sec + ',' + first : sec + ',' + first + ',' + o;
   first = sec;
   pc = o.indexOf(',');
  }

  y = HLL(first);
  o = o.substr(pc+1);
  if (firstwp != '') {
   HAddWayPoint(firstwp);
   firstwp = '';
  }
  if (isNaN(y)) {
   if (i == 0) firstwp = y;
   else HAddWayPoint(y);
  }
  else {
   var pc = o.indexOf(',');
   if (pc == -1) {
    x = HLL(o);
    o = '';
   }
   else {
    x = HLL(o.substr(0, pc));
    o = o.substr(pc+1);
   }
   if(!isNaN(x)) {
    HLastWP = '';
    var point = new GLatLng(y,x);
    HAddSegPoint(point);
   }
   else HLastWP = x;
  }

  if(wpa) for (var i = 0; i<wpa.length; i++) {
   if(wpa[i].equals(point)) HAddWayPoint();
  }
 }
 if (HLastWP[0] == "'") HLastWP = HLastWP.substr(1);
 if (HLastWP[HLastWP.length-1] == "'") HLastWP = HLastWP.substr(0,HLastWP.length-1);
 HEndAdd();
 HRecord = hrec;
}

function trim (str) {   // http://blog.stevenlevithan.com/archives/faster-trim-javascript
 var str = str.replace(/^\s\s*/, '');
 var ws = /\s/;
 var i = str.length;
 while (ws.test(str.charAt(--i)));
 return str.slice(0, i + 1);
}


function HLL(n) {    // converts a DMS to DecimalDegrees
 var qp = /^\s*(['"]?)/; // begin with a quote?
 var q = n.match(qp);
 if (q[1] != '') return n;  // get right out

 n = n.replace(/^[+\s]*/, '');  // remove and ignore leading "+" and blanks
 n = n.replace(/\u00B0/g, 'd');  // degree sign

 var d = /\s*([\.\d\-\s'"do]*)([NESW]?)([\.\d\-\s'"d]*)/i; // have a direction letter?
 var f = n.match(d);
                                           //GLog.write('763 f = ' + f);
 var c = f[2].toLowerCase();
 n = f[1] + ' ' + f[3];       // take it out
 var sng = (c == 's' || c == 'w') ? -1 : 1;  // get the +/-

 var m = /([^\-]*)(\-?)(.*)/;   // have a minus sign?
 var ms = n.match(m);
 sng = (ms[2] == '-') ? -sng : sng;   // adjust for it
 n = ms[1] + ' ' + ms[3];        // take it out

 var dms = /\s*([\d\.]*)[\sodO\u00B0]*([\d\.]*)[\s'\u8217]*([\d\.]*)[\s"\u8221]*/  // break into degrees minutes seconds
 var t = n.match(dms);
 var s = (t[3] != '') ? parseFloat(t[3])/3600 : 0;  // convert to degrees
 var m = (t[2] != '') ? parseFloat(t[2])/60 : 0;
 var d = (t[1] != '') ? parseFloat(t[1]) : 0;
 var a = d + m + s;   // add them back to just degrees
 return sng * a;      // put the minus on if needed
}

function HLLm() {    // converts an array of DMS to DecimalDegrees
 var ret = new Array();
 for(var i=0; i<arguments.length; i++)
   ret[i] = HLL(arguments[i]);
 return ret;
}

function HKmMi(n) {
 HMFac = n;
 HReshow(1);
}

function HDeg2DMS(d,mark) {
 var mk = "\u00B0";
 if (HFDeg == 0) return parseFloat(d).toFixed(5);
 var sg = d / Math.abs(d);
 var sng = (sg == 1) ? "": "-";
 d = Math.abs(d);
 var deg = Math.floor(d);
 var f = d - deg;
 var m  = f * 60;
 if (HFDeg == 1) {
  m = m.toFixed(4);
  return sng + deg + mk + " " + m  + "'"
 }
 var min  = Math.floor(m);
 f = m - min;
 var sec = (f * 60).toFixed(3);
 return sng + deg + mk + " " + min + "' " + sec + '"';
}

function HDetail(n) {
 var oHSD = HShowDetails;
 if (n==-1)HShowDetails = !HShowDetails;
 else HShowDetails = n;
 var hdet = document.getElementById('HDet')
 document.getElementById('HDet').checked = HShowDetails;
 if (oHSD != HShowDetails) {
  if (HShowDetails) {
    var t = document.getElementById('HTB');
    var ra = t.getElementsByTagName('tr');
    for (var i = 0; i<ra.length;i++) {
     var cn = ra[i].getElementsByTagName('td');
     if (cn[4] && cn[4].firstChild.value != '') {
      HWPList[i] = cn[4].firstChild.value;
     }
    }
   }
  }
  HReshow();
}

function HDMS(n) {
 var oHFDeg = HFDeg;
 HFDeg = n;
 if (oHFDeg != HFDeg) HReshow();
}

function HPedShow () {
 Hjscss('remove',document.getElementById("HPedDiv"),'HHide');
 Hjscss('add',document.getElementById("HPedBut"),'HHide');
}

function HPedHide () {
 Hjscss('add',document.getElementById("HPedDiv"),'HHide');
 Hjscss('remove',document.getElementById("HPedBut"),'HHide');
}

function HPedometerDisplayJ(toAddress,prompt,style,aclass,footer) {
 if (!toAddress) toAddress = "";
 HPedDisp = 1;
 var o = "";
  o += "\n<button class='" + aclass + "' id=HPedBut onclick='HPedShow();'";
  o += "title='Click to expose the Pedometer to draw and measure a trail'>Pedometer</button>";
  o += "\n<div id=HPedDiv class=HHide>";
  o += "\n<button onclick='HPedHide();' class='" + aclass + "' ";
  o += "title='Click to close the Pedometer'>Hide Pedometer</button>";
  o += "\n<img id=HPreLoad style='display:none' src='icons/icon0.png' alt='0' />";
  o += "\n<table class=HPedClass align=center " + style + ">";
  o += (document.getElementById('HPImg')) ? "" : "<tr><td><div id='HPImg'></div></td></tr>";
  o += "\n<tr><td><table align=center><tr><td>";
    o += "\n<div id=Hddd>0mi (0), 0</div>";
    o += "\n" + prompt;
    o += "<br>";
    o += "\n<button id=HDrawN onclick='HDraw(0)' title='Click to draw a new trail of your own.'>Draw New</button>";
    o += "\n<button id=HEditE onclick='HEditT()' title='Click to edit an existing trail line.'>Edit Existing</button>";
    o += "\n<button id=HEditLE onclick='HList()' title='Click to list an existing trail line.'>List Existing</button>";
    o += "\n<button onclick='HUndoPed(1)' title='Click to erase the trail info below.'>Clear All<\/button>";
    o += "\n<br>Units: <span  title='Click to display in metric units.'><input type=radio name=Hu onclick='HKmMi(1)'>Km &amp; m</span>";
    o += "\n<span title='Click to display in \"English\" units.'><input type=radio id='HMiles' name=Hu checked='checked' onclick='HKmMi(0.621371192)'>Mi &amp; ft</span>";
    o += "\n<br><span title='Check to display all the intermeadiate points.'><input id=HDet type=checkbox name=Hd onclick='HDetail(-1)'>Details (for Elevations and Graph)</span>";
    o += "</tr></table>\n<tr><td>";
    o += "</td></tr><tr><td><\/div><div>";
    o += "\n<div id=Hrtd class=centered></div>"
    o += "<table id='Hrec_tab' align=center style='text-align:right'><thead>";
    o += "\n<\/thead><tbody id='HTB'><\/tbody><tfoot><tr id='HTF'></tr></tfoot><\/table></div>";

  o += "<button onclick='HToEmail(\"" + toAddress + "\")' class=centered title='Click to create an email with this and other information.'>Email Path<\/button>";
  o += "\n<\/td><\/tr>";
  o += "\n<tr id=HEmail class=HHide><td colspan=0>";
  o += "\n<div id=HMailDiv></div></td></tr>";
  o += "\n<tr><td class=centered><div id=HExIm class=HHide><button onclick='HToText()' title='Export the points to the box.'>LatLon to text<\/button>";
  o += "\n<span title='Check to include the waypoint names.'><input type=checkbox id=HWithWP zchecked=checked>with WayPoints</span><br>";
  o += "\n<span title='Check to include the waypoint names.'><input type=checkbox id=HWithWPq checked=checked>with 'WayPoints'</span><br>";
  o += "\n<textarea id=HToTextId rows=6><\/textarea><br>";
  o += "\n<button onclick='HToLL()' title='Import points from the box.'>Text to LatLon<\/button>";
  o += "\n</div><\/td><\/tr>";
  if (footer) o += "<tr><td>" + footer + "</td></tr>";
  o += "<\/table>";
  o += "</div>";
  o += "\n<script type=text/javascript>HUndoPed(1)</" + "script>";
 document.write (o);
 document.close();
 document.getElementById('HEditE').disabled = false;
 document.getElementById('HDrawN').disabled = false;
}

function HGetElevation(y,x,id,n){
 HShowElevation = 1;
//Q: What is the average vertical accuracy of NED?
//
//A: The vertical accuracy is basically +/- 7 to 15 meters. It all depends on the original source DEM and if it was level 1, level 2, or 10m resolution.
 if(n==null) n = id;
 var u = (HMFac == 1) ? 'METERS' : 'FEET';
 var p = (HMFac == 1) ? 1 : 0;

 var url = 'jhm_ll_to_el.php';

 // Create new JS element
 var jsel = document.createElement('SCRIPT');
 jsel.setAttribute("type","text/javascript");
 jsel.setAttribute("id","AJAX" + (HAJAXn++));
 jsel.setAttribute("src",url + '?x=' + parseFloat(x).toFixed(5) + '&y=' + parseFloat(y).toFixed(5) + '&i=' + id + '&n=' + n + '&u=' + u + '&p=' + p);

 // Append JS element (therefore executing the 'AJAX' call for the elevation)

 sp2 = document.body.firstChild;
 document.body.insertBefore(jsel, sp2);
}

function HMWP(d) {
 if (d == 0) {
  if (HMWPm) {
   map.removeOverlay(HMWPm);
   HMWPm = null;
   document.getElementById('R' + HMWPp).style.color = null;
  }
  else if (HPList[1]) {
   HMWPm = new GMarker(HPList[1], HWPMarker);
   map.addOverlay(HMWPm);
   document.getElementById('R1').style.color = 'red';
   HMWPp = 1;
   document.getElementById('HMWPcbd').disabled = false;
   document.getElementById('HMWPcbu').disabled = false;
  }
 }
 else if (HMWPm) {
  document.getElementById('R' + HMWPp).style.color = null;
//GLog.write('start ' + HMWPp + ':' + HPList[HMWPp] + ' :: ' + HPList[HMWPp+1]);
  do {HMWPp += d;} while (HPList[HMWPp] == null && HMWPp > 0 && HMWPp < HPList.length);
//GLog.write('out: ' + HMWPp + ':' + HPList[HMWPp]);
  if (HMWPp < 1) HMWPp = 1;
  if (HMWPp > HPList.length - 1) HMWPp = HPList.length - 1;
  HMWPm.setLatLng(HPList[HMWPp])
  document.getElementById('R' + HMWPp).style.color = 'red';
  var dd = document.getElementById('R' + HMWPp).firstChild.innerHTML.replace(' ', '');
  if (dd == '') dd = ' ';
  document.getElementById('HPwpDispData').innerHTML = dd;
 }
// document.getElementById('HMWPcb').innerHTML = HMWPp;
}

function HDraw() {
 var b = document.getElementById('HDrawN');
 var n = b.innerHTML == 'Draw New';
 if (n) {
  HEPoly = new GPolyline([], "#ff00ff",5,.50);
  map.addOverlay(HEPoly)
  HEPoly.enableDrawing()
  GEvent.addListener(HEPoly, "endline", function() {HEdit(-1)})
 }
 b.innerHTML = (n) ? 'End Draw' : 'Draw New'
 document.getElementById('HEditE').disabled = true;
 if (!n) HEdit(0);
}

function HEditT(narg) {
//GLog.write('993 HEditT(' + narg + '), HMoveS = ' + HMoveS);
 var b = document.getElementById('HEditE');
 var n = narg || b.innerHTML == 'Edit Existing';
 b.innerHTML = (n) ? 'End Edit' : 'Edit Existing'
 if (!n)
//  if (HMoveS) HMoveEnd();
//  else
   HEdit(0);
 HeditTr = n;
 document.getElementById('HDrawN').disabled = (n) ? true : false;
}

function HList() {
 HEdit(0);
 HMoveEnd();
}

function HMove(n) {
//GLog.write('1010 HMove(' + n + '), HeditTr = ' + HeditTr);
 if (HeditTr && n) {
  var marker = HOverlayList[n];
  HMoveN = n;
  HMoveS = marker.getLatLng();
  marker.enableDragging();
  marker.dragCrossMove = false;
 }
}

function HMouseOutMk(n){
 if (HMoveN) HOverlayList[HMoveN].disableDragging();
}

function HMoveEnd() {
//GLog.write('1023 HMoveEnd start');
 HOverlayList[HMoveN].disableDragging();
 HRecord = true;
 HAddSegPoint(HMoveS);
 HAddSegPoint(HOverlayList[HMoveN].getLatLng());
 HEndAdd();
 HMoveS = null;
 HRecord = false;
//GLog.write('1023 HMoveEnd end');
}

function HEdit(n) {
//GLog.write('1042 HEdit(n):  n = ' + n);
  if (n == -1) HEditSeg = HEPoly;
  else if (n != 0) HEditSeg = HOverlayList[n];
  if (n != 0) {
//GLog.write('1046 n = ' + n + ', HEditSeg = ' + HEditSeg + ', VertexCount = ' + HEditSeg.getVertexCount());
   var elist = [];
   for (var i = 0; i < HEditSeg.getVertexCount(); i++) {
    elist[i] = HEditSeg.getVertex(i);
   }
   if (n == -1) map.removeOverlay(HEPoly);
   HEPoly = new GPolyline(elist, "#00ffff",5,.50);
   map.addOverlay(HEPoly);
   HEPoly.enableEditing();
   GEvent.addListener(HEPoly, "endline", function() {HEdit(0)})
  }
  else if(HEPoly) {  // n==0
//GLog.write('1058 n = ' + n + ', HEditSeg = ' + HEditSeg + ', VertexCount = ' + HEditSeg.getVertexCount());
   HEPoly.disableEditing();
   var r_prev = HRecord;
   HRecord = 1;
   for (var i = 0; i < HEPoly.getVertexCount(); i++) {
    HAddSegPoint(HEPoly.getVertex(i));
   }
   HEndAdd();
   map.removeOverlay(HEPoly);
   HRecord = r_prev;
   document.getElementById('HEditE').disabled = false;
  }
//GLog.write('925 Leaving HEdit()');
}

