/** @return a byte array with the vector tile */
  public byte[] encode() {

    VectorTile.Tile tile = new VectorTile.Tile();

    List<VectorTile.Tile.Layer> tileLayers = new ArrayList<VectorTile.Tile.Layer>();
    for (Map.Entry<String, Layer> e : layers.entrySet()) {
      String layerName = e.getKey();
      Layer layer = e.getValue();

      VectorTile.Tile.Layer tileLayer = new VectorTile.Tile.Layer();
      tileLayer.version = 1;
      tileLayer.name = layerName;

      tileLayer.keys = layer.keys();

      List<VectorTile.Tile.Value> values = new ArrayList<VectorTile.Tile.Value>();
      for (Object value : layer.values()) {
        VectorTile.Tile.Value tileValue = new VectorTile.Tile.Value();
        if (value instanceof String) {
          tileValue.setStringValue((String) value);
        } else if (value instanceof Integer) {
          tileValue.setSintValue(((Integer) value).intValue());
        } else if (value instanceof Long) {
          tileValue.setSintValue(((Long) value).longValue());
        } else if (value instanceof Float) {
          tileValue.setFloatValue(((Float) value).floatValue());
        } else if (value instanceof Double) {
          tileValue.setDoubleValue(((Double) value).doubleValue());
        } else {
          tileValue.setStringValue(value.toString());
        }
        values.add(tileValue);
      }
      tileLayer.values = values.toArray(new VectorTile.Tile.Value[values.size()]);

      tileLayer.setExtent(extent);

      List<VectorTile.Tile.Feature> features = new ArrayList<VectorTile.Tile.Feature>();
      for (Feature feature : layer.features) {

        Geometry geometry = feature.geometry;

        VectorTile.Tile.Feature featureBuilder = new VectorTile.Tile.Feature();

        featureBuilder.tags = toIntArray(feature.tags);
        featureBuilder.setType(toGeomType(geometry));
        featureBuilder.geometry = toIntArray(commands(geometry));

        features.add(featureBuilder);
      }

      tileLayer.features = features.toArray(new VectorTile.Tile.Feature[features.size()]);
      tileLayers.add(tileLayer);
    }

    tile.layers = tileLayers.toArray(new VectorTile.Tile.Layer[tileLayers.size()]);

    return MessageNano.toByteArray(tile);
  }