{% extends "base.html" %}
{% block title %}Cave Entrances and other locations in UTM{% endblock %}

{% block content %}

<style>
th, td {
 padding-left: 5px;
 padding-right: 5px;
}
</style>
<h1>Entrance locations</h1>

<p>This table is of all the survex stations in troggle: i.e. only those survey stations which have been identified with an Entrance by manually editing the Entrance data.</p>

<p>The SRTM altitude is that measured at a nearby reference point. 
The horizontal distance between the survey station and the SRTM reference point is shown in the "SRTM ref" column. 
It is always less than 35m for our dataset. Differences between the recorded altitude 
and the SRTM altitude are in <b>bold</b> if the discrepancy is more than 60m vertically.</p>

<p>Unless otherwise specified data is expressed in UTM in WGS84 datum. Coordinates are expresed in meters.</p>

<p>Click on column headings to sort.</p>

<table cellpadding="6" cellspacing="8" class="table-sort">
<tr><th>Survex Station</th><th>x [m]</th><th>y [m]</th><th>lat. [deg]</th><th>long. [deg]</th><th>alt [m]</th><th>SRTM<br> alt</th><th>SRTM [m]<br> ref</th><th>Used on <br />this Entrance</th><th>Cave</th></tr>
{% for s in stations %}
<tr>
  <td style="text-align:left; " id="{{s.name|safe}}"> <a href="/entrances#{{s.name|safe}}">{{s.name|safe}}</a> </td>
  <td style="text-align:right; width:10"> {{s.x|floatformat:2}} </td>
  <td style="text-align:right; width:10"> {{s.y|floatformat:2}} </td>
 <!--
  <td style="text-align:right; width:10"> <em>{{s.lat|floatformat:6}} </em></td>
  <td style="text-align:right; width:10"> <em>{{s.long|floatformat:6}} </em></td>
 -->

<td>{% if s.lat %}
<a href="https://www.openstreetmap.org/?mlat={{ s.lat|floatformat:7}}&mlon={{s.long|floatformat:7}}"><em>{{s.lat|floatformat:6}} </em>{% endif %}</td>

<td>{% if s.lat %}
<a href="https://www.openstreetmap.org/?mlat={{ s.lat|floatformat:7}}&mlon={{s.long|floatformat:7}}"><em>{{s.long|floatformat:6}} </em>{% endif %}</td>


  <td style="text-align:right; "> {{s.z|floatformat:0}} </td>
  <td style="text-align:right; "> {{s.srtm_diff.0|safe}} </td>
  <td style="text-align:right; "> {{s.srtm_diff.1|floatformat:0}} </td>
  <td style="text-align:right;" > <small><a href="/cave/{{s.entrance.firstcave|safe}}">{{s.entrance|safe}}</a></small> </td>
  <td style="text-align:right;" > <small>
    {% if s.entrance.firstcave.official_name %}
        {{s.entrance.firstcave.official_name|safe}}
    {% else %}
        <em>{{s.entrance.firstcave|safe}}</em>
    {% endif %}</small>
  </td>
</tr>
{% empty %}
  <td colspan="3"> NO STATION DATA - This is due to survex (cavern) failing on the entire dataset.
  <br>See <a href="/dataissues">DataIssues</a> 'survex' section . 
  <br>Resolve the survex errors and do a full databasereset import. 
  <br>You should look at the .log and .err files produced by survex in the :loser: repo folder first.
  <br>
  <br>Probably, the generaton of the .3d file has failed, so the .pos file is not generated.
  <br> Look for a message like this 'Failed to find /mnt/d/EXPO/loser/1623-and-1626-no-schoenberg-hs.3d so aborting generation of new .pos, using old one if present'
  </td>
{% endfor %}
</table>



<h3>These caves have GPS data directly on them, not via survex survey stations</h3>
<p>Because these are only vague locations identified from aerial photos, they have not
been surveyed to. 
<table>
<tr><th>Cave</th>
<th>Alt</th>
<th>GPS Lat</th><th>GPS Long</th>
<th>best Lat</th><th>best Long</th>
</tr>
{% for ent in gpsents %}
<tr>
  <td style="text-align:left">
  {% for c in ent.cavelist %}
    <a href="/{{c.url}}">
    {% if c.official_name %}
        {{c.official_name|safe}}
    {% else %}
        <em>{{c|safe}}</em>
    {% endif %}</a><br>
  {% endfor %}</td>
 
  <td style="text-align:right">{{ent.alt|floatformat:1}}</td>  
  <td style="text-align:right">{{ent.lat_wgs84|floatformat:6}}</td>
  <td style="text-align:right">{{ent.long_wgs84|floatformat:6}}</td>
  <td style="text-align:right">{{ent.lat|floatformat:6}}</td>
  <td style="text-align:right">{{ent.long|floatformat:6}}</td>
 
 </tr>
{% endfor %}
</table>

<h3>All entrances in Trogggle</h3>
<p> See also <a href="/entrances">Entrances list</a>.
<p>But the Entrances - the objects in the troggle system - are not identical to the dataset Survey Stations which is the combined set of survex data. They are only linked - and only implicitly - by the station name, e.g. '1623.gps00.p78' which refers to a *fix line in one of the survex files (in the fixedpts/ folder). Each Entrance can have two stations associated with it: the tag station and the other station.

<p>
Coordinate systems in Austria are explained in:<br>
<a href="/handbook/survey/lasers.htm">Geographical fixed points on Loser</a><br>
<a href="/handbook/survey/coord2.html">GPS and coordinate systems</a><br>
<a href="/handbook/survey/coord.htm">Basic Coordinate Systems</a>.
<br>

<a href="/stations">Troggle UTM and lat./lomg. and altitude report</a><br>
<a href="/entrances">Troggle entrances</a><br>

<h3>These stations have the altitude set equal to SRTM</h3>
{% for s in stations %}
{% if '>0<' in s.srtm_diff.0 %}
{{s}} {{s.srtm_diff.0|safe}} ref={{s.srtm_diff.1|floatformat:0}} <br />
{% endif %} 
{% endfor %}

<!-- 
This script is added for ease of use.
You can safely delete it.

Radost Waszkiewicz (2023)
-->
<script>
/* 
table-sort-js
Author: Lee Wannacott
Licence: MIT License Copyright (c) 2021 Lee Wannacott 
*/

function tableSortJs(testingTableSortJS = false, domDocumentWindow = document) {
  function getHTMLTables() {
    if (testingTableSortJS === true) {
      const getTagTable = domDocumentWindow.getElementsByTagName("table");
      return [getTagTable];
    } else {
      const getTagTable = document.getElementsByTagName("table");
      return [getTagTable];
    }
  }

  const [getTagTable] = getHTMLTables();
  const columnIndexAndTableRow = {};
  const fileSizeColumnTextAndRow = {};
  for (let table of getTagTable) {
    if (table.classList.contains("table-sort")) {
      makeTableSortable(table);
    }
  }

  function makeTableSortable(sortableTable) {
    let createTableHead;
    let tableBody;
    if (sortableTable.getElementsByTagName("thead").length === 0) {
      if (testingTableSortJS === true) {
        createTableHead = domDocumentWindow.createElement("thead");
      } else {
        createTableHead = document.createElement("thead");
      }
      createTableHead.appendChild(sortableTable.rows[0]);
      sortableTable.insertBefore(createTableHead, sortableTable.firstChild);
      if (sortableTable.querySelectorAll("tbody").length > 1) {
        tableBody = sortableTable.querySelectorAll("tbody")[1];
      } else {
        tableBody = sortableTable.querySelector("tbody");
      }
    } else {
      tableBody = sortableTable.querySelector("tbody");
    }

    const tableHead = sortableTable.querySelector("thead");
    const tableHeadHeaders = tableHead.querySelectorAll("th");

    for (let [columnIndex, th] of tableHeadHeaders.entries()) {
      if (!th.classList.contains("disable-sort")) {
        th.style.cursor = "pointer";
        makeEachColumnSortable(th, columnIndex, tableBody, sortableTable);
      }
    }
  }

  function makeEachColumnSortable(th, columnIndex, tableBody, sortableTable) {
    const desc = th.classList.contains("order-by-desc");
    let tableArrows = sortableTable.classList.contains("table-arrows");
    const [arrowUp, arrowDown] = [" ▲", " ▼"];
    const fillValue = "!X!Y!Z!";

    if (desc && tableArrows) {
      th.insertAdjacentText("beforeend", arrowDown);
    } else if (tableArrows) {
      th.insertAdjacentText("beforeend", arrowUp);
    }

    function sortDataAttributes(tableRows, columnData) {
      for (let [i, tr] of tableRows.entries()) {
        const dataAttributeTd = tr.querySelectorAll("td").item(columnIndex)
          .dataset.sort;
        columnData.push(`${dataAttributeTd}#${i}`);
        columnIndexAndTableRow[columnData[i]] = tr.innerHTML;
      }
    }

    function sortFileSize(tableRows, columnData) {
      const numberWithUnitType =
        /[.0-9]+(\s?B|\s?KB|\s?KiB|\s?MB|\s?MiB|\s?GB|\s?GiB|T\s?B|\s?TiB)/i;
      const unitType =
        /(\s?B|\s?KB|\s?KiB|\s?MB|\s?MiB|\s?GB|G\s?iB|\s?TB|\s?TiB)/i;
      const fileSizes = {
        Kibibyte: 1024,
        Mebibyte: 1.049e6,
        Gibibyte: 1.074e9,
        Tebibyte: 1.1e12,
        Pebibyte: 1.126e15,
        Kilobyte: 1000,
        Megabyte: 1e6,
        Gigabyte: 1e9,
        Terabyte: 1e12,
      };
      function removeUnitTypeConvertToBytes(fileSizeTd, _replace, i) {
        fileSizeTd = fileSizeTd.replace(unitType, "");
        fileSizeTd = fileSizeTd.replace(
          fileSizeTd,
          fileSizeTd * fileSizes[_replace]
        );
        if (i) {
          columnData.push(`${fileSizeTd}#${i}`);
        }
        return fileSizeTd;
      }
      for (let [i, tr] of tableRows.entries()) {
        let fileSizeTd = tr
          .querySelectorAll("td")
          .item(columnIndex).textContent;
        if (fileSizeTd.match(numberWithUnitType)) {
          if (fileSizeTd.match(/\s?KB/i)) {
            removeUnitTypeConvertToBytes(fileSizeTd, "Kilobyte", i);
          } else if (fileSizeTd.match(/\s?KiB/i)) {
            removeUnitTypeConvertToBytes(fileSizeTd, "Kibibyte", i);
          } else if (fileSizeTd.match(/\s?MB/i)) {
            // TODO: figure out why refactoring this line breaks test.
            fileSizeTd = removeUnitTypeConvertToBytes(fileSizeTd, "Megabyte");
            columnData.push(`${fileSizeTd}#${i}`);
          } else if (fileSizeTd.match(/\s?MiB/i)) {
            removeUnitTypeConvertToBytes(fileSizeTd, "Mebibyte", i);
          } else if (fileSizeTd.match(/\s?GB/i)) {
            removeUnitTypeConvertToBytes(fileSizeTd, "Gigabyte", i);
          } else if (fileSizeTd.match(/\s?GiB/i)) {
            removeUnitTypeConvertToBytes(fileSizeTd, "Gibibyte", i);
          } else if (fileSizeTd.match(/\s?TB/i)) {
            removeUnitTypeConvertToBytes(fileSizeTd, "Terabyte", i);
          } else if (fileSizeTd.match(/\s?TiB/i)) {
            removeUnitTypeConvertToBytes(fileSizeTd, "Tebibyte", i);
          } else if (fileSizeTd.match(/\s?B/i)) {
            fileSizeTd = fileSizeTd.replace(unitType, "");
            columnData.push(`${fileSizeTd}#${i}`);
          }
        } else {
          columnData.push(`${fillValue}#${i}`);
        }
      }
    }

    let [timesClickedColumn, columnIndexesClicked] = [0, []];

    function rememberSort(timesClickedColumn, columnIndexesClicked) {
      // if user clicked different column from first column reset times clicked.
      columnIndexesClicked.push(columnIndex);
      if (timesClickedColumn === 1 && columnIndexesClicked.length > 1) {
        const lastColumnClicked =
          columnIndexesClicked[columnIndexesClicked.length - 1];
        const secondLastColumnClicked =
          columnIndexesClicked[columnIndexesClicked.length - 2];
        if (lastColumnClicked !== secondLastColumnClicked) {
          timesClickedColumn = 0;
          columnIndexesClicked.shift();
        }
      }
    }

    function getColSpanData(sortableTable, colSpanData, colSpanSum) {
      sortableTable.querySelectorAll("th").forEach((th, index) => {
        colSpanData[index] = th.colSpan;
        if (index === 0) colSpanSum[index] = th.colSpan;
        else colSpanSum[index] = colSpanSum[index - 1] + th.colSpan;
      });
    }

    function getTableData(tableProperties) {
      const {
        tableRows,
        columnData,
        isFileSize,
        isDataAttribute,
        colSpanData,
        colSpanSum,
      } = tableProperties;
      for (let [i, tr] of tableRows.entries()) {
        let tdTextContent = tr
          .querySelectorAll("td")
          .item(
            colSpanData[columnIndex] === 1
              ? colSpanSum[columnIndex] - 1
              : colSpanSum[columnIndex] - colSpanData[columnIndex]
          ).textContent;
        if (tdTextContent.length === 0) {
          tdTextContent = "";
        }
        if (tdTextContent.trim() !== "") {
          if (isFileSize) {
            fileSizeColumnTextAndRow[columnData[i]] = tr.innerHTML;
          }
          if (!isFileSize && !isDataAttribute) {
            columnData.push(`${tdTextContent}#${i}`);
            columnIndexAndTableRow[`${tdTextContent}#${i}`] = tr.innerHTML;
          }
        } else {
          // Fill in blank table cells dict key with filler value.
          columnData.push(`${fillValue}#${i}`);
          columnIndexAndTableRow[`${fillValue}#${i}`] = tr.innerHTML;
        }
      }

      const isPunctSort = th.classList.contains("punct-sort");
      const isAlphaSort = th.classList.contains("alpha-sort");
      function sortAscending(a, b) {
        if (a.includes(`${fillValue}#`)) {
          return 1;
        } else if (b.includes(`${fillValue}#`)) {
          return -1;
        } else {
          return a.localeCompare(
            b,
            navigator.languages[0] || navigator.language,
            { numeric: !isAlphaSort, ignorePunctuation: !isPunctSort }
          );
        }
      }

      function sortDescending(a, b) {
        return sortAscending(b, a);
      }

      function clearArrows(arrowUp = "▲", arrowDown = "▼") {
        th.innerHTML = th.innerHTML.replace(arrowUp, "");
        th.innerHTML = th.innerHTML.replace(arrowDown, "");
      }

      if (columnData[0] === undefined) {
        return;
      }

      function changeTableArrow(arrowDirection) {
        if (tableArrows) {
          clearArrows(arrowUp, arrowDown);
          th.insertAdjacentText("beforeend", arrowDirection);
        }
      }

      function sortColumn(sortDirection) {
        columnData.sort(sortDirection, {
          numeric: !isAlphaSort,
          ignorePunctuation: !isPunctSort,
        });
      }

      if (timesClickedColumn === 1) {
        if (desc) {
          changeTableArrow(arrowDown);
          sortColumn(sortDescending);
        } else {
          changeTableArrow(arrowUp);
          sortColumn(sortAscending);
        }
      } else if (timesClickedColumn === 2) {
        timesClickedColumn = 0;
        if (desc) {
          changeTableArrow(arrowUp);
          sortColumn(sortAscending);
        } else {
          changeTableArrow(arrowDown);
          sortColumn(sortDescending);
        }
      }
    }

    function updateTable(tableProperties) {
      const { tableRows, columnData, isFileSize } = tableProperties;
      for (let [i, tr] of tableRows.entries()) {
        if (isFileSize) {
          tr.innerHTML = fileSizeColumnTextAndRow[columnData[i]];
          let fileSizeInBytesHTML = tr
            .querySelectorAll("td")
            .item(columnIndex).innerHTML;
          const fileSizeInBytesText = tr
            .querySelectorAll("td")
            .item(columnIndex).textContent;
          const fileSizes = {
            Kibibyte: 1024,
            Mebibyte: 1.049e6,
            Gibibyte: 1.074e9,
            Tebibyte: 1.1e12,
            Pebibyte: 1.126e15,
          };
          // Remove the unique identifyer for duplicate values(#number).
          columnData[i] = columnData[i].replace(/#[0-9]*/, "");
          const fileSize = columnData[i];
          if (fileSize < fileSizes.Kibibyte) {
            fileSizeInBytesHTML = fileSizeInBytesHTML.replace(
              fileSizeInBytesText,
              `${parseFloat(fileSize).toFixed(2)} B`
            );
          } else if (
            fileSize >= fileSizes.Kibibyte &&
            fileSize < fileSizes.Mebibyte
          ) {
            fileSizeInBytesHTML = fileSizeInBytesHTML.replace(
              fileSizeInBytesText,
              `${(fileSize / fileSizes.Kibibyte).toFixed(2)} KiB`
            );
          } else if (
            fileSize >= fileSizes.Mebibyte &&
            fileSize < fileSizes.Gibibyte
          ) {
            fileSizeInBytesHTML = fileSizeInBytesHTML.replace(
              fileSizeInBytesText,
              `${(fileSize / fileSizes.Mebibyte).toFixed(2)} MiB`
            );
          } else if (
            fileSize >= fileSizes.Gibibyte &&
            fileSize < fileSizes.Tebibyte
          ) {
            fileSizeInBytesHTML = fileSizeInBytesHTML.replace(
              fileSizeInBytesText,
              `${(fileSize / fileSizes.Gibibyte).toFixed(2)} GiB`
            );
          } else if (
            fileSize >= fileSizes.Tebibyte &&
            fileSize < fileSizes.Pebibyte
          ) {
            fileSizeInBytesHTML = fileSizeInBytesHTML.replace(
              fileSizeInBytesText,
              `${(fileSize / fileSizes.Tebibyte).toFixed(2)} TiB`
            );
          } else {
            fileSizeInBytesHTML = fileSizeInBytesHTML.replace(
              fileSizeInBytesText,
              "NaN"
            );
          }
          tr.querySelectorAll("td").item(columnIndex).innerHTML =
            fileSizeInBytesHTML;
        } else if (!isFileSize) {
          tr.innerHTML = columnIndexAndTableRow[columnData[i]];
        }
      }
    }

    th.addEventListener("click", function () {
      const [columnData, colSpanData, colSpanSum] = [[], {}, {}];

      const visibleTableRows = Array.prototype.filter.call(
        tableBody.querySelectorAll("tr"),
        (tr) => {
          return tr.style.display !== "none";
        }
      );

      const isDataAttribute = th.classList.contains("data-sort");
      if (isDataAttribute) {
        sortDataAttributes(visibleTableRows, columnData);
      }

      const isFileSize = th.classList.contains("file-size-sort");
      if (isFileSize) {
        sortFileSize(visibleTableRows, columnData);
      }

      const isRememberSort = sortableTable.classList.contains("remember-sort");
      if (!isRememberSort) {
        rememberSort(timesClickedColumn, columnIndexesClicked);
      }

      timesClickedColumn += 1;

      getColSpanData(sortableTable, colSpanData, colSpanSum);
      const tableProperties = {
        tableRows: visibleTableRows,
        columnData,
        isFileSize,
        isDataAttribute,
        colSpanData,
        colSpanSum,
      };
      getTableData(tableProperties);
      updateTable(tableProperties);
    });
  }
}

if (
  document.readyState === "complete" ||
  document.readyState === "interactive"
) {
  tableSortJs();
} else if (document.readyState === "loading") {
  document.addEventListener("DOMContentLoaded", tableSortJs, false);
}
if (typeof module == "object") {
  module.exports = tableSortJs;
}
</script>

{% endblock %}
