#!/bin/bash

# This script was used to rename the following methods across the
# driving codebase:
#
# * roads::Region::Bounds
# * roads::Region::road_segment
# * roads::Region::road_segments
# * roads::Region::junction_size
# * roads::Region::speed_limit
# * roads::Region::FindInertial
# * roads::RoadSegment::Distance
# * roads::RoadSegment::Evaluate
# * roads::RoadSegment::signal_heads
# * roads::Junction::allows_entry_and_exit
# * roads::Junction::allows_oneway_only
# * roads::Junction::allows_entry_only
# * roads::Junction::allows_exit_only
# * roads::Junction::incoming_lanes_directionalities
# * roads::Junction::get_road_contact
# * roads::Lanes::LaneIdToIdx
# * roads::Lanes::LaneIdIsValid
# * roads::ReferenceLine::<all methods starting with capital> (partially)
# * roads::BoundingBox::Union
#
# Ideally tools like clang-rename are the right way to approach
# this kind of refactoring but I was unable to get clang-rename
# working (I probably did not try hard enough) and just putting
# together this script seemed quicker. This script uses ssed
# (super-sed) for its PCRE support to perform the renaming
#
# Before running this script:
# * Switch to $ZOOX_WORKSPACE_ROOT
# * sudo apt install ssed
# * sudo apt install parallel

function rename() {
  path="$1"
  echo "Renaming inside $path"
  for f in `find "${path}" \( -name "*.h" -o -name "*.cpp" \)`; do
    ssed --regexp-perl --in-place "$f"                             \
      -e 's/(?<!: )\broad_segment(?=\(([^0-9\)]|$))/roadSegment/g' \
      -e 's/\broad_segments\(\)/roadSegments()/g'                  \
      -e 's/\bjunction_size\(\)/junctionSize()/g'                  \
      -e 's/\bsignal_heads\(/signalHeads(/g'                       \
      -e 's/\ballows_entry_and_exit\(/allowsEntryAndExit(/g'       \
      -e 's/\ballows_oneway_only\(/allowsOnewayOnly(/g'            \
      -e 's/\ballows_entry_only\(/allowsEntryOnly(/g'              \
      -e 's/\ballows_exit_only\(/allowsExitOnly(/g'                \
      -e 's/\bincoming_lanes_directionalities\(/incomingLanesDirectionalities(/g' \
      -e 's/\bget_road_contact\(/getRoadContact(/g'                \
      -e 's/\bhas_traffic_lights\(/hasTrafficLights(/g'            \
      -e 's/\bLaneIdToIdx\(/laneIdToIdx(/g'                        \
      -e 's/\bLaneIdIsValid\(/laneIdIsValid(/g'                    \
      -e 's/\b(reference_line\(\)).([A-Z])/\1.\L\2/g'              \
      -e 's/\bUnion\(/merge(/g'                                    \
      -e 's/\bBounds\(\)/bounds()/g'                               \
      -e 's/\bFindInertial\(/findInertial(/g'                      \
      -e 's/\bEvaluate\(/evaluate(/g'                              \
      -e 's/\bDistance\((?=([^\)]|$))/distance(/g'                 \
      -e 's/BuildAnnotation/buildAnnotation/g'                     \
      -e 's/PopulateAnnotations/populateAnnotations/g'             \
      -e 's/MarkEndingLanes/markEndingLanes/g'                     \
      -e 's/BuildJunction\(/buildJunction(/g'                      \
      -e 's/LaneHasConnectionInJunction/laneHasConnectionInJunction/g' \
      -e 's/SetTurnIndicatorsForOffRamps/setTurnIndicatorsForOffRamps/g' \
      -e 's/SetTurnIndicatorBasedOnRoadSegmentAngleDifference/setTurnIndicatorBasedOnRoadSegmentAngleDifference/g' \
      -e 's/BuildRoadSegment/buildRoadSegment/g'                   \
      -e 's/BuildLanes/buildLanes/g'                               \
      -e 's/BuildLanePermissibilityPreCv4/buildLanePermissibilityPreCv4/g' \
      -e 's/BuildLanePermissibilityPostCv4/buildLanePermissibilityPostCv4/g' \
      -e 's/BuildLaneProperties/buildLaneProperties/g' \
      -e 's/BuildLaneSegment/buildLaneSegment/g' \
      -e 's/BuildLaneAnnotationOverlaps/buildLaneAnnotationOverlaps/g' \
      -e 's/\bBuildLink/buildLink/g' \
      -e 's/BuildReferenceLine/buildReferenceLine/g' \
      -e 's/BuildRoadSignals/buildRoadSignals/g' \
      -e 's/BuildRoadSignal\b/buildRoadSignal/g' \
      -e 's/BuildSignalGroup/buildSignalGroup/g' \
      -e 's/BuildSpeedLimit/buildSpeedLimit/g' \
      -e 's/BuildSignalHead/buildSignalHead/g' \
      -e 's/BuildCrosswalkAnnotationInfo/buildCrosswalkAnnotationInfo/g' \
      -e 's/MarkTrafficLightedJunctions/markTrafficLightedJunctions/g' \
      -e 's/AssociateAnnotationsWithJunctions/associateAnnotationsWithJunctions/g' \
      -e 's/ReadRoadNames/readRoadNames/g' \
      -e 's/CountMaxNominallyVehicleDrivableLanes/countMaxNominallyVehicleDrivableLanes/g' \
      -e 's/SetBuildRoadClipper/setBuildRoadClipper/g' \
      -e 's/SetBuildRoadTree/setBuildRoadTree/g' \
      -e 's/SetBuildPositionLookupCache/setBuildPositionLookupCache/g' \
      -e 's/SetBuildPolygonalCrosswalkOverlaps/setBuildPolygonalCrosswalkOverlaps/g' \
      -e 's/\bBuildRegion/buildRegion/g' \
      ;
  done
}

function main() {
  export -f rename
  parallel rename ::: "$(ls -d vehicle/*/)" "prediction" "sim" "vision" "data" "mined_metric" "mapping" "argus"

  # Special cases
  ssed --in-place vehicle/common/roads/python/python_binder.cpp \
    -e 's/Region::road_segments/Region::roadSegments/g'         \
    -e 's/RoadSegment::Evaluate/RoadSegment::evaluate/g'

  ssed --in-place vehicle/common/roads/position.cpp -e 's/Position::position/Position::Position/g'

  # Undo some changes
  git checkout -- argus/chum_to_json_service/plugins/lidar*
  git checkout -- argus/chum_to_json_service/plugins/audio/audio.cpp
  git checkout -- mapping/zrn/editor/map/tile_map.h
  git checkout -- mapping/zrn/rql
  git checkout -- vehicle/common/config/vehicle_config_lidar.cpp
  git checkout -- vehicle/localization
  git checkout -- vision/classification
  git checkout -- vision/tracking
  git checkout -- mapping/common/tests/unit/constraints/test_binary_cost_function.cpp
}

function unittest() {
  echo "Running tests"
  test_dir=$(mktemp -d)

  cat > "${test_dir}/testcases.cpp" << TEST_INPUT
  Foo(RoadSegment* road_segment)
    : road_segment(road_segment) {}
  region->road_segment(RoadId(101))
  region.road_segment(road_id)
  region.road_segment(
    RoadId(324567))
  region.road_segment()
  region.road_segment(0)
  object.directed_road_segment(RoadId(12343))
  road_segment

  road_segments
  region.road_segments()
  region.directed_road_segments()

  junction_size
  junction_size()

  signal_heads
  signal_heads()

  reference_line().Tangent()
  reference_line().curvature()

  Union()

  road_segment_.Distance(
    params)
TEST_INPUT

  cat > "${test_dir}/expected.txt" << TEST_EXPECTED
  Foo(RoadSegment* road_segment)
    : road_segment(road_segment) {}
  region->roadSegment(RoadId(101))
  region.roadSegment(road_id)
  region.roadSegment(
    RoadId(324567))
  region.road_segment()
  region.road_segment(0)
  object.directed_road_segment(RoadId(12343))
  road_segment

  road_segments
  region.roadSegments()
  region.directed_road_segments()

  junction_size
  junctionSize()

  signal_heads
  signalHeads()

  reference_line().tangent()
  reference_line().curvature()

  merge()

  road_segment_.distance(
    params)
TEST_EXPECTED

  rename "${test_dir}"

  diff "${test_dir}/testcases.cpp" "${test_dir}/expected.txt" && echo "Test passed" || echo "Test failed"
  rm -rf "${test_dir}"
}

if [ "$1" = "test" ]; then
  unittest
else
  main
fi
