@Override
  public void onListItemClick(ListView parent, View v, int position, long id) {
    final RouteInfoLocation item = ((TransportStopAdapter) getListAdapter()).getItem(position);
    Builder builder = new AlertDialog.Builder(this);
    List<String> items = new ArrayList<String>();
    final List<TransportStop> stops =
        item.getDirection()
            ? item.getRoute().getForwardStops()
            : item.getRoute().getBackwardStops();
    LatLon locationToGo = getLocationToGo();
    LatLon locationToStart = getLocationToStart();
    builder.setTitle(
        getString(R.string.transport_stop_to_go_out)
            + "\n"
            + getInformation(item, stops, getCurrentRouteLocation(), true)); // $NON-NLS-1$
    int ind = 0;
    for (TransportStop st : stops) {
      StringBuilder n = new StringBuilder(50);
      n.append(ind++);
      if (st == item.getStop()) {
        n.append("!! "); // $NON-NLS-1$
      } else {
        n.append(". "); // $NON-NLS-1$
      }
      String name = st.getName(settings.usingEnglishNames());
      if (locationToGo != null) {
        n.append(name).append(" - ["); // $NON-NLS-1$
        n.append(
                OsmAndFormatter.getFormattedDistance(
                    (int) MapUtils.getDistance(locationToGo, st.getLocation()),
                    SearchTransportActivity.this))
            .append("]"); // $NON-NLS-1$
      } else if (locationToStart != null) {
        n.append("[")
            .append(
                OsmAndFormatter.getFormattedDistance(
                    (int) MapUtils.getDistance(locationToStart, st.getLocation()),
                    SearchTransportActivity.this))
            .append("] - "); // $NON-NLS-1$ //$NON-NLS-2$
        n.append(name);
      } else {
        n.append(name);
      }
      items.add(n.toString());
    }
    builder.setItems(
        items.toArray(new String[items.size()]),
        new DialogInterface.OnClickListener() {

          @Override
          public void onClick(DialogInterface dialog, int which) {
            int i = which;
            if (i >= 0) {
              TransportStop stop = stops.get(i);
              showContextMenuOnStop(stop, item, i);
            }
          }
        });
    builder.show();
  }
 private void writeRouteStops(TransportRoute r, List<TransportStop> stops, boolean direction)
     throws SQLException {
   int i = 0;
   for (TransportStop s : stops) {
     if (!visitedStops.contains(s.getId())) {
       transStopsStat.setLong(1, s.getId());
       transStopsStat.setDouble(2, s.getLocation().getLatitude());
       transStopsStat.setDouble(3, s.getLocation().getLongitude());
       transStopsStat.setString(4, s.getName());
       transStopsStat.setString(5, s.getEnName());
       int x = (int) MapUtils.getTileNumberX(24, s.getLocation().getLongitude());
       int y = (int) MapUtils.getTileNumberY(24, s.getLocation().getLatitude());
       addBatch(transStopsStat);
       try {
         transportStopsTree.insert(new LeafElement(new Rect(x, y, x, y), s.getId()));
       } catch (RTreeInsertException e) {
         throw new IllegalArgumentException(e);
       } catch (IllegalValueException e) {
         throw new IllegalArgumentException(e);
       }
       visitedStops.add(s.getId());
     }
     transRouteStopsStat.setLong(1, r.getId());
     transRouteStopsStat.setLong(2, s.getId());
     transRouteStopsStat.setInt(3, direction ? 1 : 0);
     transRouteStopsStat.setInt(4, i++);
     addBatch(transRouteStopsStat);
   }
 }
 @Override
 public synchronized boolean checkCachedObjects(
     double topLatitude,
     double leftLongitude,
     double bottomLatitude,
     double rightLongitude,
     int zoom,
     List<TransportStop> toFill,
     boolean fillFound) {
   boolean inside =
       cTopLatitude >= topLatitude
           && cLeftLongitude <= leftLongitude
           && cRightLongitude >= rightLongitude
           && cBottomLatitude <= bottomLatitude
           && cZoom == zoom;
   boolean noNeedToSearch = inside;
   if ((inside || fillFound) && toFill != null) {
     for (TransportStop a : cachedObjects) {
       LatLon location = a.getLocation();
       if (location.getLatitude() <= topLatitude
           && location.getLongitude() >= leftLongitude
           && location.getLongitude() <= rightLongitude
           && location.getLatitude() >= bottomLatitude) {
         toFill.add(a);
       }
     }
   }
   return noNeedToSearch;
 }
  private TransportStop readTransportStop(
      int shift, int cleft, int cright, int ctop, int cbottom, SearchRequest<TransportStop> req)
      throws IOException {
    int tag = WireFormat.getTagFieldNumber(codedIS.readTag());
    if (OsmandOdb.TransportStop.DX_FIELD_NUMBER != tag) {
      throw new IllegalArgumentException();
    }
    int x = codedIS.readSInt32() + cleft;

    tag = WireFormat.getTagFieldNumber(codedIS.readTag());
    if (OsmandOdb.TransportStop.DY_FIELD_NUMBER != tag) {
      throw new IllegalArgumentException();
    }
    int y = codedIS.readSInt32() + ctop;
    if (req.right < x || req.left > x || req.top > y || req.bottom < y) {
      codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
      return null;
    }

    req.numberOfAcceptedObjects++;
    req.cacheTypes.clear();

    TransportStop dataObject = new TransportStop();
    dataObject.setLocation(
        MapUtils.getLatitudeFromTile(TRANSPORT_STOP_ZOOM, y),
        MapUtils.getLongitudeFromTile(TRANSPORT_STOP_ZOOM, x));
    dataObject.setFileOffset(shift);
    while (true) {
      int t = codedIS.readTag();
      tag = WireFormat.getTagFieldNumber(t);
      switch (tag) {
        case 0:
          dataObject.setReferencesToRoutes(req.cacheTypes.toArray());
          if (dataObject.getEnName().length() == 0) {
            dataObject.setEnName(Junidecode.unidecode(dataObject.getName()));
          }
          return dataObject;
        case OsmandOdb.TransportStop.ROUTES_FIELD_NUMBER:
          req.cacheTypes.add(shift - codedIS.readUInt32());
          break;
        case OsmandOdb.TransportStop.NAME_EN_FIELD_NUMBER:
          dataObject.setEnName("" + ((char) codedIS.readUInt32())); // $NON-NLS-1$
          break;
        case OsmandOdb.TransportStop.NAME_FIELD_NUMBER:
          int i = codedIS.readUInt32();
          dataObject.setName("" + ((char) i)); // $NON-NLS-1$
          break;
        case OsmandOdb.TransportStop.ID_FIELD_NUMBER:
          dataObject.setId(codedIS.readSInt64());
          break;
        default:
          skipUnknownField(t);
          break;
      }
    }
  }
  public String getInformation(
      RouteInfoLocation route, List<TransportStop> stops, int position, boolean part) {
    StringBuilder text = new StringBuilder(200);
    double dist = 0;
    int ind = 0;
    int stInd = stops.size();
    int eInd = stops.size();
    for (TransportStop s : stops) {
      if (s == route.getStart()) {
        stInd = ind;
      }
      if (s == route.getStop()) {
        eInd = ind;
      }
      if (ind > stInd && ind <= eInd) {
        dist += MapUtils.getDistance(stops.get(ind - 1).getLocation(), s.getLocation());
      }
      ind++;
    }
    text.append(getString(R.string.transport_route_distance))
        .append(" ")
        .append(
            OsmAndFormatter.getFormattedDistance(
                (int) dist, (ClientContext) getApplication())); // $NON-NLS-1$/
    if (!part) {
      text.append(", ")
          .append(getString(R.string.transport_stops_to_pass))
          .append(" ")
          .append(eInd - stInd); // $NON-NLS-1$ //$NON-NLS-2$
      LatLon endStop = getEndStop(position - 1);
      if (endStop != null) {
        String before =
            OsmAndFormatter.getFormattedDistance(
                (int) MapUtils.getDistance(endStop, route.getStart().getLocation()),
                (ClientContext) getApplication());
        text.append(", ")
            .append(getString(R.string.transport_to_go_before))
            .append(" ")
            .append(before); // $NON-NLS-2$//$NON-NLS-1$
      }

      LatLon stStop = getStartStop(position + 1);
      if (stStop != null) {
        String after =
            OsmAndFormatter.getFormattedDistance(
                (int) MapUtils.getDistance(stStop, route.getStop().getLocation()),
                (ClientContext) getApplication());
        text.append(", ")
            .append(getString(R.string.transport_to_go_after))
            .append(" ")
            .append(after); // $NON-NLS-1$ //$NON-NLS-2$
      }
    }

    return text.toString();
  }
  /**
   * @param stop
   * @param format {0} - ref, {1} - type, {2} - name, {3} - name_en
   * @return null if something goes wrong
   */
  @Override
  public List<String> getRouteDescriptionsForStop(TransportStop stop, String format) {
    assert acceptTransportStop(stop);
    long now = System.currentTimeMillis();

    MessageFormat f = new MessageFormat(format);
    List<String> res = new ArrayList<String>();
    try {
      List<TransportRoute> routes = file.getTransportRouteDescriptions(stop);
      if (routes != null) {
        for (TransportRoute route : routes) {
          res.add(
              f.format(
                  new String[] {
                    route.getRef() + "",
                    route.getType() + "",
                    route.getName() + "",
                    route.getEnName() + ""
                  })); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
        }
      }
    } catch (IOException e) {
      log.error("Disk error ", e); // $NON-NLS-1$
    }

    if (log.isDebugEnabled()) {
      log.debug(
          String.format(
              "Search for stop %s done in %s ms found %s.", //$NON-NLS-1$
              stop.getId() + "", System.currentTimeMillis() - now, res.size())); // $NON-NLS-1$
    }
    return res;
  }
 private TransportStop readTransportRouteStop(int dx, int dy, long did) throws IOException {
   TransportStop dataObject = new TransportStop();
   boolean end = false;
   while (!end) {
     int t = codedIS.readTag();
     int tag = WireFormat.getTagFieldNumber(t);
     switch (tag) {
       case 0:
         if (dataObject.getEnName().length() == 0) {
           dataObject.setEnName(Junidecode.unidecode(dataObject.getName()));
         }
         end = true;
         break;
       case OsmandOdb.TransportRouteStop.NAME_EN_FIELD_NUMBER:
         dataObject.setEnName("" + ((char) codedIS.readUInt32())); // $NON-NLS-1$
         break;
       case OsmandOdb.TransportRouteStop.NAME_FIELD_NUMBER:
         dataObject.setName("" + ((char) codedIS.readUInt32())); // $NON-NLS-1$
         break;
       case OsmandOdb.TransportRouteStop.ID_FIELD_NUMBER:
         did += codedIS.readSInt64();
         break;
       case OsmandOdb.TransportRouteStop.DX_FIELD_NUMBER:
         dx += codedIS.readSInt32();
         break;
       case OsmandOdb.TransportRouteStop.DY_FIELD_NUMBER:
         dy += codedIS.readSInt32();
         break;
       default:
         skipUnknownField(t);
         break;
     }
   }
   dataObject.setId(did);
   dataObject.setLocation(
       MapUtils.getLatitudeFromTile(TRANSPORT_STOP_ZOOM, dy),
       MapUtils.getLongitudeFromTile(TRANSPORT_STOP_ZOOM, dx));
   return dataObject;
 }
  public net.osmand.data.TransportRoute getTransportRoute(int filePointer, TransportIndex ind)
      throws IOException {
    codedIS.seek(filePointer);
    int routeLength = codedIS.readRawVarint32();
    int old = codedIS.pushLimit(routeLength);
    net.osmand.data.TransportRoute dataObject = new net.osmand.data.TransportRoute();
    boolean end = false;
    int name = -1;
    int nameEn = -1;
    int operator = -1;
    int type = -1;
    long rid = 0;
    int rx = 0;
    int ry = 0;
    long did = 0;
    int dx = 0;
    int dy = 0;
    while (!end) {
      int t = codedIS.readTag();
      int tag = WireFormat.getTagFieldNumber(t);
      switch (tag) {
        case 0:
          end = true;
          break;
        case OsmandOdb.TransportRoute.DISTANCE_FIELD_NUMBER:
          dataObject.setDistance(codedIS.readUInt32());
          break;
        case OsmandOdb.TransportRoute.ID_FIELD_NUMBER:
          dataObject.setId(codedIS.readUInt64());
          break;
        case OsmandOdb.TransportRoute.REF_FIELD_NUMBER:
          dataObject.setRef(codedIS.readString());
          break;
        case OsmandOdb.TransportRoute.TYPE_FIELD_NUMBER:
          type = codedIS.readUInt32();
          break;
        case OsmandOdb.TransportRoute.NAME_EN_FIELD_NUMBER:
          nameEn = codedIS.readUInt32();
          break;
        case OsmandOdb.TransportRoute.NAME_FIELD_NUMBER:
          name = codedIS.readUInt32();
          break;
        case OsmandOdb.TransportRoute.OPERATOR_FIELD_NUMBER:
          operator = codedIS.readUInt32();
          break;
        case OsmandOdb.TransportRoute.REVERSESTOPS_FIELD_NUMBER:
          int length = codedIS.readRawVarint32();
          int olds = codedIS.pushLimit(length);
          TransportStop stop = readTransportRouteStop(dx, dy, did);
          dataObject.getBackwardStops().add(stop);
          did = stop.getId();
          dx =
              (int) MapUtils.getTileNumberX(TRANSPORT_STOP_ZOOM, stop.getLocation().getLongitude());
          dy = (int) MapUtils.getTileNumberY(TRANSPORT_STOP_ZOOM, stop.getLocation().getLatitude());
          codedIS.popLimit(olds);
          break;
        case OsmandOdb.TransportRoute.DIRECTSTOPS_FIELD_NUMBER:
          length = codedIS.readRawVarint32();
          olds = codedIS.pushLimit(length);
          stop = readTransportRouteStop(rx, ry, rid);
          dataObject.getForwardStops().add(stop);
          rid = stop.getId();
          rx =
              (int) MapUtils.getTileNumberX(TRANSPORT_STOP_ZOOM, stop.getLocation().getLongitude());
          ry = (int) MapUtils.getTileNumberY(TRANSPORT_STOP_ZOOM, stop.getLocation().getLatitude());
          codedIS.popLimit(olds);
          break;
        default:
          skipUnknownField(t);
          break;
      }
    }
    codedIS.popLimit(old);
    if (name != -1) {
      dataObject.setName(getStringFromStringTable(ind.stringTable, name));
    }
    if (nameEn != -1) {
      dataObject.setEnName(getStringFromStringTable(ind.stringTable, nameEn));
    } else {
      dataObject.setEnName(Junidecode.unidecode(dataObject.getName()));
    }

    if (operator != -1) {
      dataObject.setOperator(getStringFromStringTable(ind.stringTable, operator));
    }
    if (type != -1) {
      dataObject.setType(getStringFromStringTable(ind.stringTable, type));
    }
    for (int i = 0; i < 2; i++) {
      List<TransportStop> stops =
          i == 0 ? dataObject.getForwardStops() : dataObject.getBackwardStops();
      for (TransportStop s : stops) {
        if (s.getName().length() > 0) {
          s.setName(getStringFromStringTable(ind.stringTable, s.getName().charAt(0)));
        }
        if (s.getEnName().length() > 0) {
          s.setEnName(getStringFromStringTable(ind.stringTable, s.getEnName().charAt(0)));
        } else {
          s.setEnName(Junidecode.unidecode(s.getName()));
        }
      }
    }

    return dataObject;
  }
  protected void searchTransportTreeBounds(
      int pleft, int pright, int ptop, int pbottom, SearchRequest<TransportStop> req)
      throws IOException {
    int init = 0;
    int lastIndexResult = -1;
    int cright = 0;
    int cleft = 0;
    int ctop = 0;
    int cbottom = 0;
    req.numberOfReadSubtrees++;
    while (true) {
      if (req.isInterrupted()) {
        return;
      }
      int t = codedIS.readTag();
      int tag = WireFormat.getTagFieldNumber(t);
      if (init == 0xf) {
        // coordinates are init
        init = 0;
        if (cright < req.left || cleft > req.right || ctop > req.bottom || cbottom < req.top) {
          return;
        } else {
          req.numberOfAcceptedSubtrees++;
        }
      }
      switch (tag) {
        case 0:
          return;
        case OsmandOdb.TransportStopsTree.BOTTOM_FIELD_NUMBER:
          cbottom = codedIS.readSInt32() + pbottom;
          init |= 1;
          break;
        case OsmandOdb.TransportStopsTree.LEFT_FIELD_NUMBER:
          cleft = codedIS.readSInt32() + pleft;
          init |= 2;
          break;
        case OsmandOdb.TransportStopsTree.RIGHT_FIELD_NUMBER:
          cright = codedIS.readSInt32() + pright;
          init |= 4;
          break;
        case OsmandOdb.TransportStopsTree.TOP_FIELD_NUMBER:
          ctop = codedIS.readSInt32() + ptop;
          init |= 8;
          break;
        case OsmandOdb.TransportStopsTree.LEAFS_FIELD_NUMBER:
          int stopOffset = codedIS.getTotalBytesRead();
          int length = codedIS.readRawVarint32();
          int oldLimit = codedIS.pushLimit(length);
          if (lastIndexResult == -1) {
            lastIndexResult = req.searchResults.size();
          }
          req.numberOfVisitedObjects++;
          TransportStop transportStop =
              readTransportStop(stopOffset, cleft, cright, ctop, cbottom, req);
          if (transportStop != null) {
            req.searchResults.add(transportStop);
          }
          codedIS.popLimit(oldLimit);
          break;
        case OsmandOdb.TransportStopsTree.SUBTREES_FIELD_NUMBER:
          // left, ... already initialized
          length = readInt();
          int filePointer = codedIS.getTotalBytesRead();
          if (req.limit == -1 || req.limit >= req.searchResults.size()) {
            oldLimit = codedIS.pushLimit(length);
            searchTransportTreeBounds(cleft, cright, ctop, cbottom, req);
            codedIS.popLimit(oldLimit);
          }
          codedIS.seek(filePointer + length);

          if (lastIndexResult >= 0) {
            throw new IllegalStateException();
          }
          break;
        case OsmandOdb.TransportStopsTree.BASEID_FIELD_NUMBER:
          long baseId = codedIS.readUInt64();
          if (lastIndexResult != -1) {
            for (int i = lastIndexResult; i < req.searchResults.size(); i++) {
              TransportStop rs = req.searchResults.get(i);
              rs.setId(rs.getId() + baseId);
            }
          }
          break;
        default:
          skipUnknownField(t);
          break;
      }
    }
  }
  public void writeBinaryTransportIndex(
      BinaryMapIndexWriter writer, String regionName, Connection mapConnection)
      throws IOException, SQLException {
    try {
      closePreparedStatements(transRouteStat, transRouteStopsStat, transStopsStat);
      mapConnection.commit();
      transportStopsTree.flush();

      visitedStops = null; // allow gc to collect it
      PreparedStatement selectTransportRouteData =
          mapConnection.prepareStatement(
              "SELECT id, dist, name, name_en, ref, operator, type FROM transport_route"); //$NON-NLS-1$
      PreparedStatement selectTransportData =
          mapConnection.prepareStatement(
              "SELECT S.stop, S.direction,"
                  + //$NON-NLS-1$
                  "  A.latitude,  A.longitude, A.name, A.name_en "
                  + //$NON-NLS-1$
                  "FROM transport_route_stop S INNER JOIN transport_stop A ON A.id = S.stop WHERE S.route = ? ORDER BY S.ord asc"); //$NON-NLS-1$

      writer.startWriteTransportIndex(regionName);

      writer.startWriteTransportRoutes();

      // expect that memory would be enough
      Map<String, Integer> stringTable = createStringTableForTransport();
      Map<Long, Long> transportRoutes = new LinkedHashMap<Long, Long>();

      ResultSet rs = selectTransportRouteData.executeQuery();
      List<TransportStop> directStops = new ArrayList<TransportStop>();
      List<TransportStop> reverseStops = new ArrayList<TransportStop>();
      while (rs.next()) {

        long idRoute = rs.getLong(1);
        int dist = rs.getInt(2);
        String routeName = rs.getString(3);
        String routeEnName = rs.getString(4);
        if (routeEnName != null && routeEnName.equals(Junidecode.unidecode(routeName))) {
          routeEnName = null;
        }
        String ref = rs.getString(5);
        String operator = rs.getString(6);
        String type = rs.getString(7);

        selectTransportData.setLong(1, idRoute);
        ResultSet rset = selectTransportData.executeQuery();
        reverseStops.clear();
        directStops.clear();
        while (rset.next()) {
          boolean dir = rset.getInt(2) != 0;
          long idStop = rset.getInt(1);
          String stopName = rset.getString(5);
          String stopEnName = rset.getString(6);
          if (stopEnName != null && stopEnName.equals(Junidecode.unidecode(stopName))) {
            stopEnName = null;
          }
          TransportStop st = new TransportStop();
          st.setId(idStop);
          st.setName(stopName);
          st.setLocation(rset.getDouble(3), rset.getDouble(4));
          if (stopEnName != null) {
            st.setEnName(stopEnName);
          }
          if (dir) {
            directStops.add(st);
          } else {
            reverseStops.add(st);
          }
        }
        writer.writeTransportRoute(
            idRoute,
            routeName,
            routeEnName,
            ref,
            operator,
            type,
            dist,
            directStops,
            reverseStops,
            stringTable,
            transportRoutes);
      }
      rs.close();
      selectTransportRouteData.close();
      selectTransportData.close();
      writer.endWriteTransportRoutes();

      PreparedStatement selectTransportStop =
          mapConnection.prepareStatement(
              "SELECT A.id,  A.latitude,  A.longitude, A.name, A.name_en FROM transport_stop A where A.id = ?"); //$NON-NLS-1$
      PreparedStatement selectTransportRouteStop =
          mapConnection.prepareStatement(
              "SELECT DISTINCT S.route FROM transport_route_stop S WHERE S.stop = ? "); //$NON-NLS-1$
      long rootIndex = transportStopsTree.getFileHdr().getRootIndex();
      rtree.Node root = transportStopsTree.getReadNode(rootIndex);
      Rect rootBounds = calcBounds(root);
      if (rootBounds != null) {
        writer.startTransportTreeElement(
            rootBounds.getMinX(), rootBounds.getMaxX(), rootBounds.getMinY(), rootBounds.getMaxY());
        writeBinaryTransportTree(
            root,
            transportStopsTree,
            writer,
            selectTransportStop,
            selectTransportRouteStop,
            transportRoutes,
            stringTable);
        writer.endWriteTransportTreeElement();
      }
      selectTransportStop.close();
      selectTransportRouteStop.close();

      writer.writeTransportStringTable(stringTable);

      writer.endWriteTransportIndex();
      writer.flush();
    } catch (RTreeException e) {
      throw new IllegalStateException(e);
    }
  }
  public void showContextMenuOnRoute(final RouteInfoLocation route, final int routeInd) {
    Builder b = new AlertDialog.Builder(this);
    List<TransportStop> stops =
        route.getDirection()
            ? route.getRoute().getForwardStops()
            : route.getRoute().getBackwardStops();
    boolean en = settings.usingEnglishNames();

    String info = getInformation(route, stops, routeInd, false);
    StringBuilder txt = new StringBuilder(300);
    txt.append(info);
    boolean start = false;
    for (TransportStop s : stops) {
      if (s == route.getStart()) {
        start = true;
      }
      if (start) {
        txt.append("\n")
            .append(getString(R.string.transport_Stop))
            .append(" : ")
            .append(s.getName(en)); // $NON-NLS-1$ //$NON-NLS-2$
      }
      if (s == route.getStop()) {
        break;
      }
    }

    b.setMessage(txt.toString());
    b.setPositiveButton(getString(R.string.default_buttons_ok), null);
    b.setNeutralButton(
        getString(R.string.transport_search_before),
        new DialogInterface.OnClickListener() {
          @Override
          public void onClick(DialogInterface dialog, int which) {
            int toInsert = routeInd;
            int c = getCurrentRouteLocation();
            if (c >= 0 && c < routeInd) {
              toInsert--;
            }
            intermediateListAdapater.remove(null);
            intermediateListAdapater.insert(null, toInsert);
            zoom = initialZoom;
            searchTransport();
          }
        });
    b.setNegativeButton(
        getString(R.string.transport_search_after),
        new DialogInterface.OnClickListener() {
          @Override
          public void onClick(DialogInterface dialog, int which) {
            int toInsert = routeInd;
            int c = getCurrentRouteLocation();
            if (c > routeInd || c == -1) {
              toInsert++;
            }
            intermediateListAdapater.remove(null);
            intermediateListAdapater.insert(null, toInsert);
            zoom = initialZoom;
            searchTransport();
          }
        });
    b.show();
  }
  @Override
  public List<RouteInfoLocation> searchTransportRouteStops(
      double latitude, double longitude, LatLon locationToGo, int zoom) {
    long now = System.currentTimeMillis();
    final LatLon loc = new LatLon(latitude, longitude);
    double tileNumberX = MapUtils.getTileNumberX(zoom, longitude);
    double tileNumberY = MapUtils.getTileNumberY(zoom, latitude);
    double topLatitude = MapUtils.getLatitudeFromTile(zoom, tileNumberY - 0.5);
    double bottomLatitude = MapUtils.getLatitudeFromTile(zoom, tileNumberY + 0.5);
    double leftLongitude = MapUtils.getLongitudeFromTile(zoom, tileNumberX - 0.5);
    double rightLongitude = MapUtils.getLongitudeFromTile(zoom, tileNumberX + 0.5);
    SearchRequest<TransportStop> req =
        BinaryMapIndexReader.buildSearchTransportRequest(
            MapUtils.get31TileNumberX(leftLongitude),
            MapUtils.get31TileNumberX(rightLongitude),
            MapUtils.get31TileNumberY(topLatitude),
            MapUtils.get31TileNumberY(bottomLatitude),
            -1,
            null);
    List<RouteInfoLocation> listRoutes = new ArrayList<RouteInfoLocation>();
    try {
      List<TransportStop> stops = file.searchTransportIndex(req);

      TIntObjectHashMap<TransportStop> stopsToProcess = new TIntObjectHashMap<TransportStop>();
      for (TransportStop s : stops) {
        for (int ref : s.getReferencesToRoutes()) {
          TransportStop exist = stopsToProcess.get(ref);
          if (exist == null
              || MapUtils.getDistance(loc, s.getLocation())
                  < MapUtils.getDistance(loc, exist.getLocation())) {
            stopsToProcess.put(ref, s);
          }
        }
      }
      TIntObjectHashMap<TransportRoute> transportRoutes =
          file.getTransportRoutes(stopsToProcess.keys());
      for (int ref : stopsToProcess.keys()) {
        TransportRoute route = transportRoutes.get(ref);
        TransportStop s = stopsToProcess.get(ref);
        for (int i = 0; i < 2; i++) {
          boolean direction = i == 0;
          List<TransportStop> stps = direction ? route.getForwardStops() : route.getBackwardStops();
          // load only part

          while (!stps.isEmpty() && (stps.get(0).getId().longValue() != s.getId().longValue())) {
            stps.remove(0);
          }
          if (!stps.isEmpty()) {
            RouteInfoLocation r = new RouteInfoLocation();
            r.setRoute(route);
            r.setStart(stps.get(0));
            r.setDirection(direction);
            if (locationToGo != null) {
              int distToLoc = Integer.MAX_VALUE;
              for (TransportStop st : stps) {
                double ndist = MapUtils.getDistance(locationToGo, st.getLocation());
                if (ndist < distToLoc) {
                  distToLoc = (int) ndist;
                  r.setStop(st);
                  r.setDistToLocation(distToLoc);
                }
              }
            }
            listRoutes.add(r);
          }
        }
      }
      if (log.isDebugEnabled()) {
        log.debug(
            String.format(
                "Search for routes done in %s ms found %s.", //$NON-NLS-1$
                System.currentTimeMillis() - now, listRoutes.size()));
      }

      if (locationToGo != null) {
        Collections.sort(
            listRoutes,
            new Comparator<RouteInfoLocation>() {
              @Override
              public int compare(RouteInfoLocation object1, RouteInfoLocation object2) {
                int x =
                    (int)
                        (MapUtils.getDistance(loc, object1.getStart().getLocation())
                            + object1.getDistToLocation());
                int y =
                    (int)
                        (MapUtils.getDistance(loc, object2.getStart().getLocation())
                            + object2.getDistToLocation());
                return x - y;
              }
            });
      } else {
        Collections.sort(
            listRoutes,
            new Comparator<RouteInfoLocation>() {
              @Override
              public int compare(RouteInfoLocation object1, RouteInfoLocation object2) {
                return Double.compare(
                    MapUtils.getDistance(loc, object1.getStart().getLocation()),
                    MapUtils.getDistance(loc, object2.getStart().getLocation()));
              }
            });
      }
    } catch (IOException e) {
      log.error("Disk error", e); // $NON-NLS-1$
    }
    return listRoutes;
  }