diff --git a/src/main/java/org/mtransit/parser/DefaultAgencyTools.java b/src/main/java/org/mtransit/parser/DefaultAgencyTools.java index 4173cbc..0d9cecc 100644 --- a/src/main/java/org/mtransit/parser/DefaultAgencyTools.java +++ b/src/main/java/org/mtransit/parser/DefaultAgencyTools.java @@ -129,7 +129,7 @@ public class DefaultAgencyTools implements GAgencyTools { private static final SimpleDateFormat DATE_FORMAT = GFieldTypes.makeDateFormat(); - @SuppressWarnings("unused") + @SuppressWarnings({"unused", "WeakerAccess"}) public int getTodayDateInt() { return Integer.parseInt(DATE_FORMAT.format(Calendar.getInstance().getTime())); } @@ -653,10 +653,10 @@ public void setDirectionHeadsign(@NotNull MRoute mRoute, @NotNull MDirection mDi //noinspection DiscouragedApi throw new MTLog.Fatal("Trying to set direction head-sign w/o valid GTFS route (ID: %s)", gTrip.getRouteId()); } - boolean fromStopName = mDirection.getHeadsignType() == MDirection.HEADSIGN_TYPE_STOP_ID; + final boolean fromStopName = mDirection.getHeadsignType() == MDirection.HEADSIGN_TYPE_STOP_ID; if (directionFinderEnabled(mRoute.getId(), gRoute)) { mDirection.setHeadsignString( - cleanDirectionHeadsign(gTrip.getDirectionIdOrDefault(), fromStopName, gTrip.getTripHeadsignOrDefault()), + cleanDirectionHeadsign(gRoute, gTrip.getDirectionIdOrDefault(), fromStopName, gTrip.getTripHeadsignOrDefault()), gTrip.getDirectionIdOrDefault() ); return; @@ -666,7 +666,7 @@ public void setDirectionHeadsign(@NotNull MRoute mRoute, @NotNull MDirection mDi } try { mDirection.setHeadsignString( - cleanDirectionHeadsign(gTrip.getDirectionIdOrDefault(), fromStopName, gTrip.getTripHeadsignOrDefault()), + cleanDirectionHeadsign(gRoute, gTrip.getDirectionIdOrDefault(), fromStopName, gTrip.getTripHeadsignOrDefault()), gTrip.getDirectionIdOrDefault() ); } catch (NumberFormatException nfe) { @@ -739,9 +739,27 @@ public boolean directionOverrideId(long routeId) { return false; } + @Override + public boolean removeRouteLongNameFromDirectionHeadsign() { + return Configs.getRouteConfig().getDirectionHeadsignRemoveRouteLongName(); + } + /** * @param directionId {@link org.mtransit.parser.gtfs.data.GDirectionId} (0 or 1 or missing/generated) */ + @Override + public @NotNull String cleanDirectionHeadsign(@Nullable GRoute gRoute, int directionId, boolean fromStopName, @NotNull String directionHeadSign) { + if (gRoute != null && removeRouteLongNameFromDirectionHeadsign() + && directionHeadSign.equals(gRoute.getRouteLongNameOrDefault())) { + //noinspection deprecation + return cleanDirectionHeadsign(directionId, fromStopName, ""); + } + //noinspection deprecation + return cleanDirectionHeadsign(directionId, fromStopName, directionHeadSign); + } + + @SuppressWarnings("DeprecatedIsStillUsed") + @Deprecated @NotNull @Override public String cleanDirectionHeadsign(int directionId, boolean fromStopName, @NotNull String directionHeadSign) { @@ -1028,9 +1046,25 @@ public String cleanStopName(@NotNull String gStopName) { return org.mtransit.commons.CleanUtils.cleanLabel(getFirstLanguageNN(), gStopName); } + @Override + public boolean removeTripHeadsignFromStopHeadsign() { + return Configs.getRouteConfig().getStopHeadsignRemoveTripHeadsign(); + } + + @Override + public boolean removeRouteLongNameFromStopHeadsign() { + return Configs.getRouteConfig().getStopHeadsignRemoveRouteLongName(); + } + @NotNull @Override public String cleanStopHeadSign(@NotNull GRoute gRoute, @NotNull GTrip gTrip, @NotNull GStopTime gStopTime, @NotNull String stopHeadsign) { + if (removeTripHeadsignFromStopHeadsign() && stopHeadsign.equals(gTrip.getTripHeadsignOrDefault())) { + return cleanStopHeadSign(""); + } + if (removeRouteLongNameFromStopHeadsign() && stopHeadsign.equals(gRoute.getRouteLongNameOrDefault())) { + return cleanStopHeadSign(""); + } return cleanStopHeadSign(stopHeadsign); } diff --git a/src/main/java/org/mtransit/parser/config/gtfs/data/RouteConfig.kt b/src/main/java/org/mtransit/parser/config/gtfs/data/RouteConfig.kt index 9b616d2..7a66470 100644 --- a/src/main/java/org/mtransit/parser/config/gtfs/data/RouteConfig.kt +++ b/src/main/java/org/mtransit/parser/config/gtfs/data/RouteConfig.kt @@ -40,13 +40,15 @@ data class RouteConfig( val tripHeadsignCleaners: List = emptyList(), @SerialName("trip_headsign_remove_via") val tripHeadsignRemoveVia: Boolean = false, // OPT-IN feature - // DIRECTION @SerialName("trip_id_cleanup_regex") val tripIdCleanupRegex: String? = null, // optional @SerialName("trip_id_not_unique_allowed") val tripIdNotUniqueAllowed: Boolean = false, // OPT-IN feature + // DIRECTION @SerialName("direction_headsign_cleaners") val directionHeadsignCleaners: List = emptyList(), + @SerialName("direction_headsign_remove_route_long_name") + val directionHeadsignRemoveRouteLongName: Boolean = false, // OPT-IN feature @SerialName("direction_finder_enabled") val directionFinderEnabled: Boolean = false, // OPT-IN feature // STOP @@ -58,6 +60,11 @@ data class RouteConfig( val useStopCodeForStopId: Boolean = false, // OPT-IN feature @SerialName("stop_code_to_stop_id_configs") val stopCodeToStopIdConfigs: List = emptyList(), + @SerialName("stop_headsign_remove_trip_headsign") + val stopHeadsignRemoveTripHeadsign: Boolean = false, // OPT-IN feature + @SerialName("stop_headsign_remove_route_long_name") + val stopHeadsignRemoveRouteLongName: Boolean = false, // OPT-IN feature + ) { @Serializable diff --git a/src/main/java/org/mtransit/parser/gtfs/GAgencyTools.java b/src/main/java/org/mtransit/parser/gtfs/GAgencyTools.java index a30e8db..efed50c 100644 --- a/src/main/java/org/mtransit/parser/gtfs/GAgencyTools.java +++ b/src/main/java/org/mtransit/parser/gtfs/GAgencyTools.java @@ -37,8 +37,8 @@ public interface GAgencyTools { int getThreadPoolSize(); - @Deprecated // TO BE REMOVED - boolean defaultExcludeEnabled(); + @Deprecated + boolean defaultExcludeEnabled(); // TO BE REMOVED boolean defaultStringsCleanerEnabled(); @@ -52,12 +52,12 @@ public interface GAgencyTools { @Nullable List getSupportedLanguages(); - @Deprecated // TO BE REMOVED - void setAgencyName(@Nullable String agencyName); + @Deprecated + void setAgencyName(@Nullable String agencyName); // TO BE REMOVED - @Deprecated // TO BE REMOVED + @Deprecated @NotNull - String getAgencyName(); + String getAgencyName(); // TO BE REMOVED @NotNull String getAgencyColor(); @@ -177,6 +177,12 @@ public interface GAgencyTools { boolean directionOverrideId(long routeId); + boolean removeRouteLongNameFromDirectionHeadsign(); + + @NotNull + String cleanDirectionHeadsign(@Nullable GRoute gRoute, int directionId, boolean fromStopName, @NotNull String directionHeadSign); + + @Deprecated @NotNull String cleanDirectionHeadsign(int directionId, boolean fromStopName, @NotNull String directionHeadSign); @@ -265,6 +271,10 @@ public interface GAgencyTools { @NotNull String cleanStopName(@NotNull String gStopName); + boolean removeTripHeadsignFromStopHeadsign(); + + boolean removeRouteLongNameFromStopHeadsign(); + @NotNull String cleanStopHeadSign(@NotNull GRoute gRoute, @NotNull GTrip gTrip, @NotNull GStopTime gStopTime, @NotNull String stopHeadsign); diff --git a/src/main/java/org/mtransit/parser/gtfs/GReader.java b/src/main/java/org/mtransit/parser/gtfs/GReader.java index dd2d8e4..18dfc1d 100644 --- a/src/main/java/org/mtransit/parser/gtfs/GReader.java +++ b/src/main/java/org/mtransit/parser/gtfs/GReader.java @@ -532,20 +532,20 @@ private static void processRoute(GAgencyTools agencyTools, GSpec gSpec, HashMap< return; } if (agencyTools.getRouteIdCleanupRegex() != null) { // IF route ID cleanup regex set DO - final GRoute previousRoute = gSpec.getRoute(gRoute.getRouteIdInt()); - if (previousRoute != null && previousRoute.equals(gRoute)) { + final GRoute previousGRoute = gSpec.getRoute(gRoute.getRouteIdInt()); + if (previousGRoute != null && previousGRoute.equals(gRoute)) { return; // ignore if route already exists with same values } - if (previousRoute != null && previousRoute.equalsExceptMergeable(gRoute)) { - final String mergedRouteLongName = GRoute.mergeRouteLongNames(previousRoute.getRouteLongName(), gRoute.getRouteLongName()); - final String mergedRouteColor = GRoute.mergeRouteColors(previousRoute.getRouteColor(), gRoute.getRouteColor()); + if (previousGRoute != null && previousGRoute.equalsExceptMergeable(gRoute)) { + final String mergedRouteLongName = GRoute.mergeRouteLongNames(previousGRoute.getRouteLongName(), gRoute.getRouteLongName()); + final String mergedRouteColor = GRoute.mergeRouteColors(previousGRoute.getRouteColor(), gRoute.getRouteColor()); if (mergedRouteLongName != null) { // merge successful - gSpec.addRoute(previousRoute.clone(mergedRouteLongName, mergedRouteColor), true); + gSpec.addRoute(previousGRoute.clone(mergedRouteLongName, mergedRouteColor), true); return; } } - if (previousRoute != null) { - MTLog.log("Duplicate route ID!\n - %s\n - %s", gRoute.toStringPlus(), previousRoute.toStringPlus()); + if (previousGRoute != null) { + MTLog.log("Duplicate route ID!\n - %s\n - %s", gRoute.toStringPlus(), previousGRoute.toStringPlus()); } } gSpec.addRoute(gRoute); diff --git a/src/main/java/org/mtransit/parser/gtfs/data/GSpec.java b/src/main/java/org/mtransit/parser/gtfs/data/GSpec.java index b832790..33d974f 100644 --- a/src/main/java/org/mtransit/parser/gtfs/data/GSpec.java +++ b/src/main/java/org/mtransit/parser/gtfs/data/GSpec.java @@ -248,7 +248,7 @@ public List getRoutes(@Nullable Long optMRouteId) { if (optMRouteId != null) { final List routes = new ArrayList<>(); for (Integer gRouteIdInt : this.mRouteIdToGRouteIdInts.get(optMRouteId)) { - GRoute gRoute = getRoute(gRouteIdInt); + final GRoute gRoute = getRoute(gRouteIdInt); if (gRoute != null) { routes.add(gRoute); } diff --git a/src/main/java/org/mtransit/parser/mt/MDirectionHeadSignFinder.kt b/src/main/java/org/mtransit/parser/mt/MDirectionHeadSignFinder.kt index 42d4444..fce5fe5 100644 --- a/src/main/java/org/mtransit/parser/mt/MDirectionHeadSignFinder.kt +++ b/src/main/java/org/mtransit/parser/mt/MDirectionHeadSignFinder.kt @@ -62,14 +62,17 @@ object MDirectionHeadSignFinder { val amPmDirectionHeadSigns = mutableMapOf() for ((directionId, _) in directionHeadSigns) { val firstAndLastTime = directionAmPm[directionId] ?: continue + val gRoute = directionRouteIdInts[directionId].takeIf { it?.size == 1 }?.getOrNull(0)?.let { routeGTFS.getRoute(it) } if (GTime.areAM(firstAndLastTime)) { amPmDirectionHeadSigns[directionId] = agencyTools.cleanDirectionHeadsign( + gRoute, directionId, false, "AM" ) } else if (GTime.arePM(firstAndLastTime)) { amPmDirectionHeadSigns[directionId] = agencyTools.cleanDirectionHeadsign( + gRoute, directionId, false, "PM" @@ -88,16 +91,14 @@ object MDirectionHeadSignFinder { MTLog.log("$routeId: Direction head-signs '$directionHeadSigns' not descriptive, using route long name...") val routeDirectionHeadSigns = mutableMapOf() for ((directionId, _) in directionHeadSigns) { - val routeIdInts = directionRouteIdInts[directionId] ?: continue - if (routeIdInts.size != 1) { - continue - } - val route = routeGTFS.getRoute(routeIdInts[0]) ?: continue - val rln = route.routeLongNameOrDefault + val gRoute = directionRouteIdInts[directionId].takeIf { it?.size == 1 }?.getOrNull(0)?.let { routeGTFS.getRoute(it) } + ?: continue + val rln = gRoute.routeLongNameOrDefault if (rln.isBlank()) { continue } routeDirectionHeadSigns[directionId] = agencyTools.cleanDirectionHeadsign( + gRoute, directionId, false, agencyTools.cleanRouteLongName(rln) @@ -118,7 +119,9 @@ object MDirectionHeadSignFinder { val stopIdInt = directionStopIdInts[directionId] ?: continue @Suppress("DEPRECATION") val stop = routeGTFS.getStop(stopIdInt) ?: continue + val gRoute = directionRouteIdInts[directionId].takeIf { it?.size == 1 }?.getOrNull(0)?.let { routeGTFS.getRoute(it) } lastStopDirectionHeadSigns[directionId] = agencyTools.cleanDirectionHeadsign( + gRoute, directionId, true, agencyTools.cleanStopName(stop.stopName) @@ -153,9 +156,11 @@ object MDirectionHeadSignFinder { val stopTimesDirectionHeadSigns = mutableMapOf() for ((directionId, _) in directionHeadSigns) { val stopTimeHeadSigns = distinctDirectionStopTimeHeadSigns[directionId] ?: continue + val gRoute = directionRouteIdInts[directionId].takeIf { it?.size == 1 }?.getOrNull(0)?.let { routeGTFS.getRoute(it) } var cleanDirectionHeadsign: String? = null for (stopTimeHeadSign in stopTimeHeadSigns) { cleanDirectionHeadsign = agencyTools.cleanDirectionHeadsign( + gRoute, directionId, false, stopTimeHeadSign // already cleaned @@ -209,8 +214,9 @@ object MDirectionHeadSignFinder { gTrip.directionIdOrDefault == directionId }.map { gTrip -> val routeIdInt = gTrip.routeIdInt + val gRoute = routeGTFS.getRoute(routeIdInt) val headSign = gTrip.tripHeadsign - ?.let { agencyTools.cleanDirectionHeadsign(directionId, false, it) } ?: EMPTY + ?.let { agencyTools.cleanDirectionHeadsign(gRoute, directionId, false, it) } ?: EMPTY val stopTimes = routeGTFS.getStopTimes(routeId, gTrip.tripIdInt, null, null) Triple(routeIdInt, headSign, stopTimes) }.filterNot { (_, _, stopTimes) -> @@ -1142,6 +1148,7 @@ object MDirectionHeadSignFinder { } private fun logMerge(debug: Boolean = false, format: String, vararg args: Any?) { + @Suppress("SimplifyBooleanWithConstants") if (!LOG_MERGE && debug) { return } diff --git a/src/test/java/org/mtransit/parser/mt/MDirectionHeadSignFinderTest.kt b/src/test/java/org/mtransit/parser/mt/MDirectionHeadSignFinderTest.kt index d146dd0..16cdddf 100644 --- a/src/test/java/org/mtransit/parser/mt/MDirectionHeadSignFinderTest.kt +++ b/src/test/java/org/mtransit/parser/mt/MDirectionHeadSignFinderTest.kt @@ -8,6 +8,7 @@ import org.mockito.ArgumentMatchers.anyBoolean import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.anyString import org.mockito.Mockito.mock +import org.mockito.kotlin.anyOrNull import org.mockito.kotlin.whenever import org.mtransit.parser.gtfs.GAgencyTools import org.mtransit.parser.gtfs.data.GDirectionId @@ -41,9 +42,9 @@ class MDirectionHeadSignFinderTest { @Suppress("DEPRECATION") @Before fun setUp() { - whenever(agencyTools.cleanDirectionHeadsign(anyInt(), anyBoolean(), anyString())) + whenever(agencyTools.cleanDirectionHeadsign(anyOrNull(), anyInt(), anyBoolean(), anyString())) .then { - it.arguments[2] + it.arguments[3] } whenever(agencyTools.cleanStopHeadSign(any(), any(), any(), anyString())) .then {