/**
   * @see com.brantapps.polaris.api.Mappable#addMarker(com.brantapps.polaris.api.MapMarkerOptions)
   */
  @Override
  public MapMarker<?> addMarker(final MapMarkerOptions<?> mapMarkerOptions) {
    if (itemisedOverlay == null) {
      itemisedOverlay =
          new ItemizedOverlayWithFocus<OverlayItem>(
              new ArrayList<OverlayItem>(), this, getResourceProxy());
      itemisedOverlay.setFocusItemsOnTap(true);
      mapView.setUseSafeCanvas(false);
      mapView.getOverlays().add(itemisedOverlay);
    }

    final Marker marker = (Marker) mapMarkerOptions.get();
    final OverlayItem item =
        new OverlayItem(
            marker.title,
            marker.snippet,
            new org.osmdroid.util.GeoPoint(marker.latitude, marker.longitude));
    if (marker.bitmap != null) {
      item.setMarker(new BitmapDrawable(mapView.getResources(), marker.bitmap));
    } else if (marker.icon != 0) {
      item.setMarker(mapView.getResources().getDrawable(marker.icon));
    }
    if (marker.anchor == Marker.Anchor.CENTER) {
      item.setMarkerHotspot(OverlayItem.HotspotPlace.CENTER);
    }

    itemisedOverlay.addItem(item);
    final MapMarker<Marker> osmMapMarker = new OpenStreetMapMarker(marker);
    overlayItemToMarker.put(item, osmMapMarker);
    return osmMapMarker;
  }
  ///////////////////// THIS IS TO DISPLAY PATH WHEN A* ALGORITHM DETERMINES THE
  // PATH/////////////////////////////
  public void showPathForEdges(ArrayList<Edge> pathData) {
    if (pathData == null || pathData.size() == 0) return;

    // HERE WE OBTAIN THE POINTS WHICH TOGETHER REPRESENT THE PATH
    pathPointList.clear();
    ArrayList<GeoPoint> edgeContourList;
    int color = 0;
    Edge edge;

    for (int i = (pathData.size() - 1); i >= 0; i--) {
      edge = pathData.get(i);
      color = edge.getEdgeColor();
      pathPointList.add(
          new PathPoint(
              edge.getToNode().getLatE6(),
              edge.getToNode().getLongE6(),
              color)); // this is the destination node's coords

      edgeContourList = edge.getEdgeContourList(mContext.getContentResolver());
      if (edgeContourList != null) {
        for (GeoPoint p : edgeContourList) {
          pathPointList.add(new PathPoint(p.getLatitudeE6(), p.getLongitudeE6(), color));
        }
      }

      if (i == 0) {
        // add the data of the first point of the first node
        pathPointList.add(
            new PathPoint(edge.getFromNode().getLatE6(), edge.getFromNode().getLongE6(), color));
      }
    }

    // HERE WE GET THE PATH INDICATORS LIST
    pathIndicatorList.clear();
    pathIndicatorOverlays.removeAllItems();
    Node n;
    int currentType = Edge.TYPE_WALK;
    Resources r = mapView.getResources();
    int indicatorCount = 0;
    int prevEdgeType = -1;
    String title = "";
    for (int i = 0; i < pathData.size(); i++) {
      try {
        edge = pathData.get(i);

        if (edge.getEdgeType() == Edge.TYPE_WAIT) {
          // special case: if the final destination is a bus/tram stop
          // we add a final indicator for destination node
          if (i == (pathData.size() - 1)) { // last edge. must display destination
            n = edge.getToNode();
            indicatorCount++;
            OverlayItem item =
                new OverlayItem(
                    indicatorCount + ":path_indicator" + n.getID(),
                    null,
                    "Reach destination at " + n.getTitle(),
                    n.getGeoPoint(),
                    DrawableUtils.numberedPathDirectionDrawable(r, indicatorCount));
            item.setMarkerHotspot(HotspotPlace.BOTTOM_CENTER);
            pathIndicatorOverlays.addItem(item);
            break;
          }

          if (edge.getCostForEdge() > 0) title = edge.getFromNode().getTitle();
          continue;
        }

        if (i == 0) { // first edge. must display start point
          currentType = edge.getEdgeType();
          n = edge.getFromNode();
          if (n.getTitle() != null) title = n.getTitle();
          indicatorCount++;
          String descText = edge.getLineName();
          if (edge.getEdgeType() == Edge.TYPE_WALK) {
            if (edge.getCostForEdge() == Edge.DUMMY_EDGE_COST)
              descText = "Walk from your starting location";
            else descText = descText.replace("Alight", "Start").replace("#NODE_NAME#", title);
          } else {
            descText =
                descText
                    .replace("Board", "Start at " + title + " and board")
                    .replace("#NODE_NAME#", "");
          }

          OverlayItem item =
              new OverlayItem(
                  indicatorCount + ":path_indicator" + n.getID(),
                  null,
                  descText,
                  n.getGeoPoint(),
                  DrawableUtils.numberedPathDirectionDrawable(r, indicatorCount));
          item.setMarkerHotspot(HotspotPlace.BOTTOM_CENTER);
          pathIndicatorOverlays.addItem(item);
        } else {
          if (edge.getEdgeType() != currentType) {
            // if there is a change in the type of edge
            currentType = edge.getEdgeType();
            n = edge.getFromNode();
            if (n.getTitle() != null) title = n.getTitle();
            indicatorCount++;
            String descText = edge.getLineName();
            if (prevEdgeType != Edge.TYPE_WALK && edge.getEdgeType() != Edge.TYPE_WALK)
              descText = descText.replace("Board", "Alight and change to");
            descText = descText.replace("#NODE_NAME#", title);
            OverlayItem item =
                new OverlayItem(
                    indicatorCount + ":path_indicator" + n.getID(),
                    null,
                    descText,
                    n.getGeoPoint(),
                    DrawableUtils.numberedPathDirectionDrawable(r, indicatorCount));
            item.setMarkerHotspot(HotspotPlace.BOTTOM_CENTER);
            pathIndicatorOverlays.addItem(item);
          }
        }

        // add a final indicator for destination node
        if (i == (pathData.size() - 1)) { // last edge. must display destination
          n = edge.getToNode();
          indicatorCount++;
          OverlayItem item =
              new OverlayItem(
                  indicatorCount + ":path_indicator" + n.getID(),
                  null,
                  "Reach destination at " + n.getTitle(),
                  n.getGeoPoint(),
                  DrawableUtils.numberedPathDirectionDrawable(r, indicatorCount));
          item.setMarkerHotspot(HotspotPlace.BOTTOM_CENTER);
          pathIndicatorOverlays.addItem(item);
        }

        prevEdgeType = edge.getEdgeType();
      } catch (Exception ignore) {
        ignore.printStackTrace();
      }
    }

    pathOverlay.setPoints(pathPointList);
    mapView.postInvalidate();
  }
  ///////////////////////////////// THIS INITIALIZES ALL THE MAP
  // OVERLAYS///////////////////////////////////
  private void initializeOverlays(final Context c) {
    // set up location overlay
    locationOverlay = new DirectionLocationOverlay(c, mapView, mResourceProxy);
    locationOverlay.setLocationUpdater(locationUpdateListener);

    // set up path overlay to draw the path as required
    pathOverlay = new CustomPathOverlay(c);
    pathOverlay.setStrokeWidth(STROKE_WIDTH);
    pathOverlay.setTransparency(PATH_TRANSPARENCY);

    MARKER_BASE_OFFSET =
        (int)
            Math.round(
                -1
                    * mapView
                        .getResources()
                        .getDrawable(R.drawable.path_direction_marker)
                        .getIntrinsicHeight()
                    / 1.5);
    pathIndicatorOverlays =
        new ItemizedIconOverlay<OverlayItem>(
            new ArrayList<OverlayItem>(),
            new ItemizedIconOverlay.OnItemGestureListener<OverlayItem>() {
              @Override
              public boolean onItemSingleTapUp(final int index, final OverlayItem item) {
                balloonOverlay.setMarkerBaseOffset(MARKER_BASE_OFFSET);
                balloonOverlay.setBalloonOverlay(item, 2);
                mapView.getController().animateTo(item.mGeoPoint);
                mapView.postInvalidate();
                return true;
              }

              @Override
              public boolean onItemLongPress(final int index, final OverlayItem item) {
                return false;
              }
            },
            mResourceProxy,
            1);

    // three default categories displayed. change/add/modify later as reqd
    categoriesDisplayed.add(Const.ATTRACTION);
    categoriesDisplayed.add(Const.BUS);
    categoriesDisplayed.add(Const.TRAM);
    categoriesDisplayed.add(Const.TRAIN);
    categoriesDisplayed.add(Const.CABLE);
    categoriesDisplayed.add(Const.BUS_INT);
    categoriesDisplayed.add(Const.MRT);
    categoriesDisplayed.add(Const.CABLEWAY);

    // set up the poi markers as required
    float densityFactor =
        TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_DIP, 1, mContext.getResources().getDisplayMetrics());
    markerPointsOverlay =
        new ItemizedIconOverlay<OverlayItem>(
            new ArrayList<OverlayItem>(),
            new ItemizedIconOverlay.OnItemGestureListener<OverlayItem>() {
              @Override
              public boolean onItemSingleTapUp(final int index, final OverlayItem item) {
                balloonOverlay.setMarkerBaseOffset(0);
                balloonOverlay.setBalloonOverlay(item, 1);
                mapView.getController().animateTo(item.mGeoPoint);
                mapView.postInvalidate();
                return true;
              }

              @Override
              public boolean onItemLongPress(final int index, final OverlayItem item) {
                if (IS_DEBUG) {
                  testStartPoint = item.getPoint();
                  Toast.makeText(
                          c,
                          "selected point: "
                              + item.getPoint().getLatitudeE6()
                              + ","
                              + item.getPoint().getLongitudeE6(),
                          Toast.LENGTH_SHORT)
                      .show();
                }
                return false;
              }
            },
            mResourceProxy,
            MARKER_SCALE / densityFactor);

    // set up the balloon overlay to display whenever an attraction/interchange point is tapped
    balloonOverlay =
        new CustomBalloonOverlay(
            c,
            new ItemizedIconOverlay.OnItemGestureListener<OverlayItem>() {
              @Override
              public boolean onItemSingleTapUp(final int index, final OverlayItem item) {
                if (IS_DEBUG)
                  Toast.makeText(
                          c,
                          "Tapped blue arrow '"
                              + item.mTitle
                              + "' (index="
                              + index
                              + ") got single tapped up",
                          Toast.LENGTH_LONG)
                      .show();
                if (item.getUid().contains("path_indicator")) {
                  try {
                    String[] idData = item.getUid().split(":");
                    if (idData.length > 0) {
                      ((MapActivity) mContext).directionsPosition = Integer.parseInt(idData[0]);
                    }

                    if (((MapActivity) mContext).mapDirections != null)
                      ((MapActivity) mContext).mapDirections.performClick();
                  } catch (Exception e) {
                  }
                  return true; // return if it is a path indicator balloon
                }
                Intent intent = new Intent(c, NodeDetailActivity.class);
                intent.putExtra(Const.NODE_ID, Integer.parseInt(item.getUid()));
                intent.putExtra(
                    Const.FlurryStrings.FlurryEventName,
                    Const.FlurryStrings.LocationDetailsSourceMap);
                ((MapActivity) c)
                    .startActivityForResult(intent, MapActivity.ROUTE_DESTINATION_REQUEST_CODE);
                return true;
              }

              @Override
              public boolean onItemLongPress(final int index, final OverlayItem item) {
                return false;
              }
            });

    // Adding overlays
    mapView.getOverlays().add(pathOverlay);
    mapView.getOverlays().add(markerPointsOverlay);
    mapView.getOverlays().add(pathIndicatorOverlays);
    mapView.getOverlays().add(balloonOverlay);
    mapView.getOverlays().add(locationOverlay);
  }