/**
   * Requires vn to point to a relation element. From there it iterates over all matches of the ap.
   * Puts an empty list for each referenced way.
   */
  private List<Tuple2<WayRole, Long>> extractWayRefs(VTDNav vn, Hashtable<Long, List<Long>> ways)
      throws NavException, XPathEvalException {
    vn.push();

    List<Tuple2<WayRole, Long>> refs = new ArrayList<>();
    for (int j = MEMBER_WAY_PATH.evalXPath(); j != -1; j = MEMBER_WAY_PATH.evalXPath()) {
      long ref = Long.parseLong(vn.toString(vn.getAttrVal("ref")));
      String roleAsString = vn.toString(vn.getAttrVal("role")).toLowerCase();
      WayRole role;
      switch (roleAsString) {
        case "inner":
          role = WayRole.INNER;
          break;
        case "outer":
          role = WayRole.OUTER;
          break;
        default:
          continue;
      }
      refs.add(Tuple.tuple(role, ref));
      ways.put(ref, Collections.emptyList());
    }
    MEMBER_WAY_PATH.resetXPath();

    vn.pop();

    return refs;
  }
  private void extractReferencedWays(
      VTDNav vn, Hashtable<Long, List<Long>> ways, Hashtable<Long, Point2D> nodes)
      throws XPathEvalException, NavException {
    vn.push();

    for (int i = WAY_PATH.evalXPath(); i != -1; i = WAY_PATH.evalXPath()) {
      long id = Long.parseLong(vn.toString(vn.getAttrVal("id")));
      // By checking that we already referenced the id we can reduce memory pressure
      if (ways.containsKey(id)) {
        ways.put(id, extractNodeRefs(vn, nodes));
      }
    }

    vn.pop();
  }
  /**
   * Requires vn to point to a way element. From there it iterates over all matches of the ap. Puts
   * a dummy point into nodes for every node it finds.
   */
  private List<Long> extractNodeRefs(VTDNav vn, Hashtable<Long, Point2D> nodes)
      throws NavException, XPathEvalException {
    vn.push();

    List<Long> refs = new ArrayList<>();
    for (int j = NODE_REF_PATH.evalXPath(); j != -1; j = NODE_REF_PATH.evalXPath()) {
      long ref = Long.parseLong(vn.toString(j + 1));
      refs.add(ref);
      nodes.put(ref, new Point2D(0, 0));
    }
    NODE_REF_PATH.resetXPath();

    vn.pop();

    return refs;
  }
  private List<List<Long>> extractWaysOfBuildings(VTDNav vn, Hashtable<Long, Point2D> nodes)
      throws XPathEvalException, NavException {
    vn.push();

    List<List<Long>> ways = new ArrayList<>();
    for (int i = BUILDING_WAY_PATH.evalXPath(); i != -1; i = BUILDING_WAY_PATH.evalXPath()) {
      // The lambda will put in a dummy value for each encountered node,
      // so that we know later which nodes we need to parse.
      ways.add(extractNodeRefs(vn, nodes));
    }

    vn.pop();

    BUILDING_WAY_PATH.resetXPath();
    return ways;
  }
  private List<List<Tuple2<WayRole, Long>>> extractWayRefsOfMultipolygons(
      VTDNav vn, Hashtable<Long, List<Long>> ways) throws NavException, XPathEvalException {
    vn.push();

    List<List<Tuple2<WayRole, Long>>> multipolygons = new ArrayList<>();
    for (int i = BUILDING_MULTIPOLYGON_PATH.evalXPath();
        i != -1;
        i = BUILDING_MULTIPOLYGON_PATH.evalXPath()) {
      // For an explanation for the lambda see extractWaysOfBuildings
      multipolygons.add(extractWayRefs(vn, ways));
    }

    vn.pop();

    BUILDING_WAY_PATH.resetXPath();

    return multipolygons;
  }
  private void extractReferencedNodes(VTDNav vn, Hashtable<Long, Point2D> nodes)
      throws XPathEvalException, NavException {
    vn.push();

    for (int i = NODE_PATH.evalXPath(); i != -1; i = NODE_PATH.evalXPath()) {
      long id = Long.parseLong(vn.toString(vn.getAttrVal("id")));
      // By checking that we already referenced the id we can reduce memory pressure
      if (nodes.containsKey(id)) {
        nodes.put(
            id,
            new Point2D(
                Double.parseDouble(vn.toString(vn.getAttrVal("lon"))) * (1 << 10),
                Double.parseDouble(vn.toString(vn.getAttrVal("lat"))) * (1 << 10)));
      }
    }

    // Make sure we have all referenced nodes extracted
    // assert !nodes.containsValue(DUMMY_POINT);

    vn.pop();
  }