diff --git a/src/main/java/org/mtransit/parser/DefaultAgencyTools.java b/src/main/java/org/mtransit/parser/DefaultAgencyTools.java index ead9bc8..0a2b803 100644 --- a/src/main/java/org/mtransit/parser/DefaultAgencyTools.java +++ b/src/main/java/org/mtransit/parser/DefaultAgencyTools.java @@ -35,6 +35,8 @@ import org.mtransit.parser.mt.data.MRoute; import org.mtransit.parser.mt.data.MRouteSNToIDConverter; import org.mtransit.parser.mt.data.MServiceDate; +import org.mtransit.parser.mt.data.MServiceId; +import org.mtransit.parser.mt.data.MServiceIds; import org.mtransit.parser.mt.data.MSpec; import org.mtransit.parser.mt.data.MDirection; @@ -151,6 +153,8 @@ public void start(@NotNull String[] args) { MTLog.log("Generating data..."); MTLog.logDebug("Args [%d]: %s.", args.length, Arrays.asList(args)); final List lastServiceDates = MReader.loadServiceDates(args[2]); + final List lastServiceIds = MReader.loadServiceIds(args[2]); + MServiceIds.addAll(lastServiceIds); this.serviceIdInts = extractUsefulServiceIdInts(args, this, true, lastServiceDates); final String inputUrl = args.length >= 5 ? args[4] : null; if (excludingAll()) { @@ -1317,7 +1321,7 @@ public static HashSet extractUsefulServiceIdInts( MTLog.log("* Generated on %s | NEXT Schedules from %s to %s.", usefulPeriod.getTodayStringInt(), usefulPeriod.getStartDate(), usefulPeriod.getEndDate()); MTLog.log("------------------------------"); } - HashSet serviceIds = getPeriodServiceIds(usefulPeriod.getStartDate(), usefulPeriod.getEndDate(), gCalendars, gCalendarDates); + final HashSet serviceIds = getPeriodServiceIds(usefulPeriod.getStartDate(), usefulPeriod.getEndDate(), gCalendars, gCalendarDates); improveUsefulPeriod(usefulPeriod, c, gCalendars, gCalendarDates); MTLog.log("Extracting useful service IDs... DONE"); //noinspection UnusedAssignment // FIXME @@ -1448,7 +1452,8 @@ && diffLowerThan(DATE_FORMAT, c, pPrevious.getStartDate(), pPrevious.getEndDate( private static boolean refreshStartEndDatesFromCalendarDates( Period p, HashSet serviceIds, - List gCalendarDates) { + List gCalendarDates + ) { boolean newDates = false; for (GCalendarDate gCalendarDate : gCalendarDates) { if (gCalendarDate.isServiceIdInts(serviceIds)) { diff --git a/src/main/java/org/mtransit/parser/db/DumpDbUtils.kt b/src/main/java/org/mtransit/parser/db/DumpDbUtils.kt index f6bec61..c5857ef 100644 --- a/src/main/java/org/mtransit/parser/db/DumpDbUtils.kt +++ b/src/main/java/org/mtransit/parser/db/DumpDbUtils.kt @@ -1,5 +1,6 @@ package org.mtransit.parser.db +import org.mtransit.commons.FeatureFlags import org.mtransit.commons.GTFSCommons import org.mtransit.parser.FileUtils import java.io.File @@ -30,12 +31,18 @@ object DumpDbUtils { SQLUtils.executeUpdate(statement, GTFSCommons.T_STOP_SQL_DROP) SQLUtils.executeUpdate(statement, GTFSCommons.T_DIRECTION_SQL_DROP) SQLUtils.executeUpdate(statement, GTFSCommons.T_ROUTE_SQL_DROP) + if (FeatureFlags.F_EXPORT_SERVICE_ID_INTS) { + SQLUtils.executeUpdate(statement, GTFSCommons.T_SERVICE_IDS_SQL_DROP) + } SQLUtils.executeUpdate(statement, GTFSCommons.T_SERVICE_DATES_SQL_DROP) // CREATE SQLUtils.executeUpdate(statement, GTFSCommons.T_ROUTE_SQL_CREATE) SQLUtils.executeUpdate(statement, GTFSCommons.T_DIRECTION_SQL_CREATE) SQLUtils.executeUpdate(statement, GTFSCommons.T_STOP_SQL_CREATE) SQLUtils.executeUpdate(statement, GTFSCommons.T_DIRECTION_STOPS_SQL_CREATE) + if (FeatureFlags.F_EXPORT_SERVICE_ID_INTS) { + SQLUtils.executeUpdate(statement, GTFSCommons.T_SERVICE_IDS_SQL_CREATE) + } SQLUtils.executeUpdate(statement, GTFSCommons.T_SERVICE_DATES_SQL_CREATE) } } diff --git a/src/main/java/org/mtransit/parser/gtfs/data/GAgency.kt b/src/main/java/org/mtransit/parser/gtfs/data/GAgency.kt index e2b9a1b..d3126c8 100644 --- a/src/main/java/org/mtransit/parser/gtfs/data/GAgency.kt +++ b/src/main/java/org/mtransit/parser/gtfs/data/GAgency.kt @@ -38,14 +38,12 @@ data class GAgency( agencyEmail, ) - @Discouraged(message = "Not memory efficient") @Suppress("unused") - val agencyId = _agencyId + @get:Discouraged(message = "Not memory efficient") + val agencyId: AgencyId get() = _agencyId private val _agencyId: AgencyId - get() { - return GIDs.getString(agencyIdInt) - } + get() = GIDs.getString(agencyIdInt) @Suppress("unused") fun isDifferentAgency(otherAgencyIdInt: Int): Boolean = agencyIdInt != otherAgencyIdInt diff --git a/src/main/java/org/mtransit/parser/gtfs/data/GCalendar.kt b/src/main/java/org/mtransit/parser/gtfs/data/GCalendar.kt index 1fd5da6..a064929 100644 --- a/src/main/java/org/mtransit/parser/gtfs/data/GCalendar.kt +++ b/src/main/java/org/mtransit/parser/gtfs/data/GCalendar.kt @@ -3,7 +3,6 @@ package org.mtransit.parser.gtfs.data import androidx.annotation.Discouraged import org.mtransit.parser.MTLog import org.mtransit.parser.db.SQLUtils.escape -import org.mtransit.parser.gtfs.GAgencyTools import java.util.Calendar // https://developers.google.com/transit/gtfs/reference#calendar_fields @@ -68,14 +67,12 @@ data class GCalendar( endDate ) - @Discouraged(message = "Not memory efficient") @Suppress("unused") - val serviceId = _serviceId + @get:Discouraged(message = "Not memory efficient") + val serviceId: String get() = _serviceId private val _serviceId: String - get() { - return GIDs.getString(serviceIdInt) - } + get() = GIDs.getString(serviceIdInt) val escapedServiceId: String get() = _serviceId.escape() @@ -83,11 +80,6 @@ data class GCalendar( val escapedServiceIdInt: Int get() = escapedServiceId.toGIDInt() - @Suppress("unused") - fun getCleanServiceId(agencyTools: GAgencyTools): String { - return agencyTools.cleanServiceId(_serviceId) - } - val dates: List by lazy { initAllDates( serviceIdInt, @@ -264,7 +256,7 @@ data class GCalendar( sunday: Boolean, startDate: Int, endDate: Int, - exceptionType: GCalendarDatesExceptionType = GCalendarDatesExceptionType.SERVICE_ADDED, + exceptionType: GCalendarDatesExceptionType = GCalendarDatesExceptionType.SERVICE_DEFAULT, ) = buildList { try { val dateFormat = GFieldTypes.makeDateFormat() diff --git a/src/main/java/org/mtransit/parser/gtfs/data/GCalendarDate.kt b/src/main/java/org/mtransit/parser/gtfs/data/GCalendarDate.kt index ebfe013..ec6ee9b 100644 --- a/src/main/java/org/mtransit/parser/gtfs/data/GCalendarDate.kt +++ b/src/main/java/org/mtransit/parser/gtfs/data/GCalendarDate.kt @@ -40,14 +40,12 @@ data class GCalendarDate( GCalendarDatesExceptionType.parse(exceptionTypeInt) ) - @Discouraged(message = "Not memory efficient") @Suppress("unused") - val serviceId = _serviceId + @get:Discouraged(message = "Not memory efficient") + val serviceId: String get() = _serviceId private val _serviceId: String - get() { - return GIDs.getString(serviceIdInt) - } + get() = GIDs.getString(serviceIdInt) val escapedServiceId: String get() = _serviceId.escape() @@ -55,11 +53,6 @@ data class GCalendarDate( val escapedServiceIdInt: Int get() = escapedServiceId.toGIDInt() - @Suppress("unused") - fun getCleanServiceId(agencyTools: GAgencyTools): String { - return agencyTools.cleanServiceId(_serviceId) - } - val uID by lazy { getNewUID(date, serviceIdInt) } @Suppress("unused") diff --git a/src/main/java/org/mtransit/parser/gtfs/data/GDirection.kt b/src/main/java/org/mtransit/parser/gtfs/data/GDirection.kt index 167cdda..45f7157 100644 --- a/src/main/java/org/mtransit/parser/gtfs/data/GDirection.kt +++ b/src/main/java/org/mtransit/parser/gtfs/data/GDirection.kt @@ -25,14 +25,12 @@ data class GDirection( destination = destination, ) - @Discouraged(message = "Not memory efficient") @Suppress("unused") - val routeId = _routeId + @get:Discouraged(message = "Not memory efficient") + val routeId: String get() = _routeId private val _routeId: String - get() { - return GIDs.getString(routeIdInt) - } + get() = GIDs.getString(routeIdInt) @Suppress("unused") fun toStringPlus(): String { diff --git a/src/main/java/org/mtransit/parser/gtfs/data/GFrequency.kt b/src/main/java/org/mtransit/parser/gtfs/data/GFrequency.kt index 2edd0af..be85746 100644 --- a/src/main/java/org/mtransit/parser/gtfs/data/GFrequency.kt +++ b/src/main/java/org/mtransit/parser/gtfs/data/GFrequency.kt @@ -31,46 +31,34 @@ data class GFrequency( exactTimes, ) - @Discouraged(message = "Not memory efficient") @Suppress("unused") - val tripId = _tripId + @get:Discouraged(message = "Not memory efficient") + val tripId: String get() = _tripId @Suppress("unused") private val _tripId: String - get() { - return GIDs.getString(tripIdInt) - } + get() = GIDs.getString(tripIdInt) val startTime: Int = _startTime @Suppress("unused") val startTimeDate: Date - get() { - return GTime.toDate(_startTime) - } + get() = GTime.toDate(_startTime) val startTimeMs: Long - get() { - return GTime.toMs(_startTime) - } + get() = GTime.toMs(_startTime) val endTime: Int = _endTime @Suppress("unused") val endTimeDate: Date - get() { - return GTime.toDate(_endTime) - } + get() = GTime.toDate(_endTime) val endTimeMs: Long - get() { - return GTime.toMs(_endTime) - } + get() = GTime.toMs(_endTime) val headwayMs: Long - get() { - return TimeUnit.SECONDS.toMillis(headwaySecs.toLong()) - } + get() = TimeUnit.SECONDS.toMillis(headwaySecs.toLong()) @Suppress("unused") fun toStringPlus(): String { diff --git a/src/main/java/org/mtransit/parser/gtfs/data/GRoute.kt b/src/main/java/org/mtransit/parser/gtfs/data/GRoute.kt index efaf795..680cec7 100644 --- a/src/main/java/org/mtransit/parser/gtfs/data/GRoute.kt +++ b/src/main/java/org/mtransit/parser/gtfs/data/GRoute.kt @@ -67,34 +67,30 @@ data class GRoute( @Suppress("unused") fun isDifferentAgency(otherAgencyId: String): Boolean = isDifferentAgency(GIDs.getInt(otherAgencyId)) - @Discouraged(message = "Not memory efficient") @Suppress("unused") - val agencyIdOrDefault: AgencyId = _agencyId + @get:Discouraged(message = "Not memory efficient") + val agencyIdOrDefault: AgencyId get() = _agencyId - @Discouraged(message = "Not memory efficient") @Suppress("unused") - val agencyId: AgencyId = _agencyId + @get:Discouraged(message = "Not memory efficient") + val agencyId: AgencyId get() = _agencyId private val _agencyId: AgencyId get() = GIDs.getString(agencyIdInt) - @Discouraged(message = "Not memory efficient") @Suppress("unused") - val routeId = _routeId + @get:Discouraged(message = "Not memory efficient") + val routeId: RouteId get() = _routeId private val _routeId: RouteId - get() { - return GIDs.getString(routeIdInt) - } + get() = GIDs.getString(routeIdInt) - @Discouraged(message = "Not memory efficient") @Suppress("unused") - val originalRouteId = _originalRouteId + @get:Discouraged(message = "Not memory efficient") + val originalRouteId: String get() = _originalRouteId private val _originalRouteId: String - get() { - return GIDs.getString(originalRouteIdInt) - } + get() = GIDs.getString(originalRouteIdInt) @Suppress("unused") val shortestRouteName = routeShortName.ifEmpty { routeLongName } diff --git a/src/main/java/org/mtransit/parser/gtfs/data/GSpecExt.kt b/src/main/java/org/mtransit/parser/gtfs/data/GSpecExt.kt index bef2ff1..e4816a8 100644 --- a/src/main/java/org/mtransit/parser/gtfs/data/GSpecExt.kt +++ b/src/main/java/org/mtransit/parser/gtfs/data/GSpecExt.kt @@ -1,5 +1,3 @@ package org.mtransit.parser.gtfs.data -fun GSpec.getRoute(gTrip: GTrip): GRoute? { - return this.getRoute(gTrip.routeIdInt) -} \ No newline at end of file +fun GSpec.getRoute(gTrip: GTrip) = this.getRoute(gTrip.routeIdInt) diff --git a/src/main/java/org/mtransit/parser/gtfs/data/GStop.kt b/src/main/java/org/mtransit/parser/gtfs/data/GStop.kt index 07fb54c..a26769b 100644 --- a/src/main/java/org/mtransit/parser/gtfs/data/GStop.kt +++ b/src/main/java/org/mtransit/parser/gtfs/data/GStop.kt @@ -42,23 +42,19 @@ data class GStop( GWheelchairBoardingType.parse(wheelchairBoarding), ) - @Discouraged(message = "Not memory efficient") @Suppress("unused") - val stopId = _stopId + @get:Discouraged(message = "Not memory efficient") + val stopId: StopId get() = _stopId private val _stopId: StopId - get() { - return GIDs.getString(stopIdInt) - } + get() = GIDs.getString(stopIdInt) - @Discouraged(message = "Not memory efficient") @Suppress("unused") - val parentStationId = _parentStationId + @get:Discouraged(message = "Not memory efficient") + val parentStationId: StopId? get() = _parentStationId private val _parentStationId: StopId? - get() { - return parentStationIdInt?.let { GIDs.getString(it) } - } + get() = parentStationIdInt?.let { GIDs.getString(it) } @JvmOverloads @Suppress("unused") diff --git a/src/main/java/org/mtransit/parser/gtfs/data/GStopTime.kt b/src/main/java/org/mtransit/parser/gtfs/data/GStopTime.kt index cd5d2b3..87f57cb 100644 --- a/src/main/java/org/mtransit/parser/gtfs/data/GStopTime.kt +++ b/src/main/java/org/mtransit/parser/gtfs/data/GStopTime.kt @@ -88,23 +88,19 @@ data class GStopTime( timePoint = timePoint, ) - @Discouraged(message = "Not memory efficient") @Suppress("unused") - val tripId = _tripId + @get:Discouraged(message = "Not memory efficient") + val tripId: String get() = _tripId private val _tripId: String - get() { - return GIDs.getString(tripIdInt) - } + get() = GIDs.getString(tripIdInt) - @Discouraged(message = "Not memory efficient") @Suppress("unused") - val stopId = _stopId + @get:Discouraged(message = "Not memory efficient") + val stopId: String get() = _stopId private val _stopId: String - get() { - return GIDs.getString(stopIdInt) - } + get() = GIDs.getString(stopIdInt) val arrivalTime: Int = _arrivalTime @@ -112,30 +108,22 @@ data class GStopTime( @Suppress("unused") val arrivalTimeMs: Long - get() { - return GTime.toMs(_arrivalTime) - } + get() = GTime.toMs(_arrivalTime) @Suppress("unused") val arrivalTimeDate: Date - get() { - return GTime.toDate(_arrivalTime) - } + get() = GTime.toDate(_arrivalTime) val departureTime: Int = _departureTime fun hasDepartureTime() = _departureTime >= 0 val departureTimeMs: Long - get() { - return GTime.toMs(_departureTime) - } + get() = GTime.toMs(_departureTime) @Suppress("unused") val departureTimeDate: Date - get() { - return GTime.toDate(_departureTime) - } + get() = GTime.toDate(_departureTime) val uID by lazy { getNewUID(tripIdInt, stopIdInt, stopSequence) } diff --git a/src/main/java/org/mtransit/parser/gtfs/data/GTrip.kt b/src/main/java/org/mtransit/parser/gtfs/data/GTrip.kt index edcb5f8..a6b25f0 100644 --- a/src/main/java/org/mtransit/parser/gtfs/data/GTrip.kt +++ b/src/main/java/org/mtransit/parser/gtfs/data/GTrip.kt @@ -71,47 +71,34 @@ data class GTrip( val uID by lazy { getNewUID(routeIdInt, tripIdInt) } - @Discouraged(message = "Not memory efficient") @Suppress("unused") - val routeId = _routeId + @get:Discouraged(message = "Not memory efficient") + val routeId: String get() = _routeId private val _routeId: String - get() { - return GIDs.getString(routeIdInt) - } + get() = GIDs.getString(routeIdInt) - @Discouraged(message = "Not memory efficient") @Suppress("unused") - val originalRouteId = _originalRouteId + @get:Discouraged(message = "Not memory efficient") + val originalRouteId: String get() = _originalRouteId private val _originalRouteId: String - get() { - return GIDs.getString(originalRouteIdInt) - } + get() = GIDs.getString(originalRouteIdInt) - @Discouraged(message = "Not memory efficient") @Suppress("unused") - val serviceId = _serviceId + @get:Discouraged(message = "Not memory efficient") + val serviceId: String get() = _serviceId private val _serviceId: String - get() { - return GIDs.getString(serviceIdInt) - } + get() = GIDs.getString(serviceIdInt) @Suppress("unused") - private fun getCleanServiceId(agencyTools: GAgencyTools): String { - return agencyTools.cleanServiceId(_serviceId) - } - - @Discouraged(message = "Not memory efficient") - @Suppress("unused") - val tripId = _tripId + @get:Discouraged(message = "Not memory efficient") + val tripId: String get() = _tripId @Suppress("unused") private val _tripId: String - get() { - return GIDs.getString(tripIdInt) - } + get() = GIDs.getString(tripIdInt) fun isServiceIdInts(serviceIdInts: Collection): Boolean { return serviceIdInts.contains(serviceIdInt) diff --git a/src/main/java/org/mtransit/parser/gtfs/data/GTripStop.kt b/src/main/java/org/mtransit/parser/gtfs/data/GTripStop.kt index 4c2227e..4542bde 100644 --- a/src/main/java/org/mtransit/parser/gtfs/data/GTripStop.kt +++ b/src/main/java/org/mtransit/parser/gtfs/data/GTripStop.kt @@ -2,7 +2,6 @@ package org.mtransit.parser.gtfs.data import androidx.annotation.Discouraged -// https://developers.google.com/transit/gtfs/reference#stop_timestxt // https://gtfs.org/reference/static#stop_timestxt // -_trip_id field // - stop_id field @@ -50,24 +49,20 @@ data class GTripStop( val uID by lazy { getNewUID(routeIdInt, tripIdInt, stopIdInt, stopSequence) } - @Discouraged(message = "Not memory efficient") @Suppress("unused") - val tripId = _tripId + @get:Discouraged(message = "Not memory efficient") + val tripId: String get() = _tripId @Suppress("unused") private val _tripId: String - get() { - return GIDs.getString(tripIdInt) - } + get() = GIDs.getString(tripIdInt) - @Discouraged(message = "Not memory efficient") @Suppress("unused") - val stopId = _stopId + @get:Discouraged(message = "Not memory efficient") + val stopId: String get() = _stopId private val _stopId: String - get() { - return GIDs.getString(stopIdInt) - } + get() = GIDs.getString(stopIdInt) @Suppress("unused") fun toStringPlus(): String { diff --git a/src/main/java/org/mtransit/parser/mt/GenerateMObjectsTask.java b/src/main/java/org/mtransit/parser/mt/GenerateMObjectsTask.java index a5e8df2..7095f65 100644 --- a/src/main/java/org/mtransit/parser/mt/GenerateMObjectsTask.java +++ b/src/main/java/org/mtransit/parser/mt/GenerateMObjectsTask.java @@ -24,16 +24,15 @@ import org.mtransit.parser.gtfs.data.GTrip; import org.mtransit.parser.gtfs.data.GTripStop; import org.mtransit.parser.mt.data.MAgency; -import org.mtransit.parser.mt.data.MCalendarExceptionType; +import org.mtransit.parser.mt.data.MDirection; import org.mtransit.parser.mt.data.MDirectionCardinalType; +import org.mtransit.parser.mt.data.MDirectionStop; import org.mtransit.parser.mt.data.MFrequency; import org.mtransit.parser.mt.data.MRoute; import org.mtransit.parser.mt.data.MSchedule; import org.mtransit.parser.mt.data.MServiceDate; import org.mtransit.parser.mt.data.MSpec; import org.mtransit.parser.mt.data.MStop; -import org.mtransit.parser.mt.data.MDirection; -import org.mtransit.parser.mt.data.MDirectionStop; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -147,42 +146,14 @@ private MSpec doCall() { if (!serviceIdInts.contains(gCalendarDate.getServiceIdInt())) { continue; } - switch (gCalendarDate.getExceptionType()) { - case SERVICE_REMOVED: // keep list of removed service for calendars processing - mServiceDates.add(new MServiceDate( - gCalendarDate.getServiceIdInt(), - gCalendarDate.getDate(), - MCalendarExceptionType.REMOVED - )); - break; - case SERVICE_ADDED: - mServiceDates.add(new MServiceDate( - gCalendarDate.getServiceIdInt(), - gCalendarDate.getDate(), - MCalendarExceptionType.ADDED - )); - break; - case SERVICE_DEFAULT: - mServiceDates.add(new MServiceDate( - gCalendarDate.getServiceIdInt(), - gCalendarDate.getDate(), - MCalendarExceptionType.DEFAULT - )); - break; - default: - throw new MTLog.Fatal("%s: Unexpected calendar date exception type '%s'!", this.routeId, gCalendarDate.getExceptionType()); - } + mServiceDates.add(MServiceDate.fromCalendarDate(gCalendarDate)); } for (GCalendar gCalendar : routeGTFS.getAllCalendars()) { if (!serviceIdInts.contains(gCalendar.getServiceIdInt())) { continue; } for (GCalendarDate gCalendarDate : gCalendar.getDates()) { - mServiceDates.add(new MServiceDate( - gCalendarDate.getServiceIdInt(), - gCalendarDate.getDate(), - MCalendarExceptionType.DEFAULT - )); + mServiceDates.add(MServiceDate.fromCalendarDate(gCalendarDate)); } } MDirection mDirection; diff --git a/src/main/java/org/mtransit/parser/mt/MDataChangedManager.kt b/src/main/java/org/mtransit/parser/mt/MDataChangedManager.kt index 453cc01..540d2b5 100644 --- a/src/main/java/org/mtransit/parser/mt/MDataChangedManager.kt +++ b/src/main/java/org/mtransit/parser/mt/MDataChangedManager.kt @@ -108,7 +108,6 @@ object MDataChangedManager { val (lastCalendarsServiceDates, lastCalendarDatesServiceDates) = if (ALL_CALENDARS_IN_CALENDAR_DATES) emptyList() to lastServiceDates // calendar dates only else lastServiceDates.partition { it.exceptionType == MCalendarExceptionType.DEFAULT.id } - @Suppress("DEPRECATION") val allCalendarsWithDays = if (ALL_CALENDARS_IN_CALENDAR_DATES) emptyList() else gtfs.allCalendars.filter { it.hasDays() } MTLog.log("> Service IDS from '${GCalendar.FILENAME}':") //noinspection DiscouragedApi diff --git a/src/main/java/org/mtransit/parser/mt/MGenerator.java b/src/main/java/org/mtransit/parser/mt/MGenerator.java index 417c7b8..9c3e570 100644 --- a/src/main/java/org/mtransit/parser/mt/MGenerator.java +++ b/src/main/java/org/mtransit/parser/mt/MGenerator.java @@ -8,6 +8,7 @@ import org.jetbrains.annotations.Nullable; import org.mtransit.commons.Cleaner; import org.mtransit.commons.CloseableUtils; +import org.mtransit.commons.FeatureFlags; import org.mtransit.commons.GTFSCommons; import org.mtransit.commons.SourceUtils; import org.mtransit.commons.StringUtils; @@ -29,6 +30,8 @@ import org.mtransit.parser.mt.data.MRoute; import org.mtransit.parser.mt.data.MSchedule; import org.mtransit.parser.mt.data.MServiceDate; +import org.mtransit.parser.mt.data.MServiceId; +import org.mtransit.parser.mt.data.MServiceIds; import org.mtransit.parser.mt.data.MSpec; import org.mtransit.parser.mt.data.MStop; import org.mtransit.parser.mt.data.MDirection; @@ -92,32 +95,29 @@ public static MSpec generateMSpec(@NotNull GSpec gtfs, @NotNull GAgencyTools age for (Future future : list) { try { MSpec mRouteSpec = future.get(); - MTLog.logDebug("%s: Generating routes, trips, trip stops & stops objects... (merging...)", mRouteSpec.getFirstRoute().getId()); + final long mRouteId = mRouteSpec.getFirstRoute().getId(); + MTLog.logDebug("%s: Generating routes, trips, trip stops & stops objects... (merging...)", mRouteId); if (mRouteSpec.hasStops() && mRouteSpec.hasServiceDates()) { mAgencies.addAll(mRouteSpec.getAgencies()); mRoutes.addAll(mRouteSpec.getRoutes()); mDirections.addAll(mRouteSpec.getDirections()); mDirectionStops.addAll(mRouteSpec.getDirectionStops()); - MTLog.logDebug("%s: Generating routes, trips, trip stops & stops objects... (merging stops...)", mRouteSpec.getFirstRoute().getId()); + logMerging("stops...", mRouteId); for (MStop mStop : mRouteSpec.getStops()) { if (mStops.containsKey(mStop.getId())) { if (!mStops.get(mStop.getId()).equals(mStop)) { - MTLog.log("Stop ID '%s' already in list! (%s instead of %s)", mStop.getId(), mStops.get(mStop.getId()), mStop); + MTLog.log("%s: Stop ID '%s' already in list! (%s instead of %s)", mRouteId, mStop.getId(), mStops.get(mStop.getId()), mStop); } continue; } mStops.put(mStop.getId(), mStop); } - MTLog.logDebug("%s: Generating routes, trips, trip stops & stops objects... (merging stops... DONE)", mRouteSpec.getFirstRoute() - .getId()); - MTLog.logDebug("%s: Generating routes, trips, trip stops & stops objects... (merging service dates...)", mRouteSpec.getFirstRoute() - .getId()); + logMerging("stops... DONE", mRouteId); + logMerging("service dates...", mRouteId); mServiceDates.addAll(mRouteSpec.getServiceDates()); - MTLog.logDebug("%s: Generating routes, trips, trip stops & stops objects... (merging service dates... DONE)", mRouteSpec - .getFirstRoute().getId()); + logMerging("service dates... DONE", mRouteId); if (mRouteSpec.hasStopSchedules()) { - MTLog.logDebug("%s: Generating routes, trips, trip stops & stops objects... (merging stop schedules...)", mRouteSpec - .getFirstRoute().getId()); + logMerging("stop schedules...", mRouteId); if (mRouteSpec.getSchedules() != null) { DBUtils.setAutoCommit(false); for (MSchedule mSchedule : mRouteSpec.getSchedules()) { @@ -126,12 +126,10 @@ public static MSpec generateMSpec(@NotNull GSpec gtfs, @NotNull GAgencyTools age DBUtils.setAutoCommit(true); // true => commit() } mRouteSpec.setSchedules(null); // clear - MTLog.logDebug("%s: Generating routes, trips, trip stops & stops objects... (merging stop schedules... DONE)", mRouteSpec - .getFirstRoute().getId()); + logMerging("stop schedules... DONE", mRouteId); } if (mRouteSpec.hasRouteFrequencies()) { - MTLog.logDebug("%s: Generating routes, trips, trip stops & stops objects... (merging route frequencies...)", mRouteSpec - .getFirstRoute().getId()); + logMerging("route frequencies...", mRouteId); for (Entry> routeFrequenciesEntry : mRouteSpec.getRouteFrequencies().entrySet()) { if (routeFrequenciesEntry.getValue() == null || routeFrequenciesEntry.getValue().isEmpty()) { continue; @@ -141,8 +139,7 @@ public static MSpec generateMSpec(@NotNull GSpec gtfs, @NotNull GAgencyTools age } mRouteFrequencies.get(routeFrequenciesEntry.getKey()).addAll(routeFrequenciesEntry.getValue()); } - MTLog.logDebug("%s: Generating routes, trips, trip stops & stops objects... (merging route frequencies... DONE)", mRouteSpec - .getFirstRoute().getId()); + logMerging("route frequencies... DONE", mRouteId); } if (firstTimestamp < 0L || mRouteSpec.getFirstTimestamp() < firstTimestamp) { firstTimestamp = mRouteSpec.getFirstTimestamp(); @@ -151,9 +148,9 @@ public static MSpec generateMSpec(@NotNull GSpec gtfs, @NotNull GAgencyTools age lastTimestamp = mRouteSpec.getLastTimestamp(); } } else { - MTLog.logDebug("%s: Generating routes, trips, trip stops & stops objects... (EMPTY)", mRouteSpec.getFirstRoute().getId()); + MTLog.logDebug("%s: Generating routes, trips, trip stops & stops objects... (EMPTY)", mRouteId); } - MTLog.logDebug("%s: Generating routes, trips, trip stops & stops objects... (merging... DONE)", mRouteSpec.getFirstRoute().getId()); + MTLog.logDebug("%s: Generating routes, trips, trip stops & stops objects... (merging... DONE)", mRouteId); } catch (Throwable t) { threadPoolExecutor.shutdownNow(); throw new MTLog.Fatal(t, t.getMessage()); @@ -161,17 +158,17 @@ public static MSpec generateMSpec(@NotNull GSpec gtfs, @NotNull GAgencyTools age } MTLog.log("Generating routes, trips, trip stops & stops objects... (all routes completed)"); threadPoolExecutor.shutdown(); - ArrayList mAgenciesList = new ArrayList<>(mAgencies); + final ArrayList mAgenciesList = new ArrayList<>(mAgencies); Collections.sort(mAgenciesList); - ArrayList mStopsList = new ArrayList<>(mStops.values()); + final ArrayList mStopsList = new ArrayList<>(mStops.values()); Collections.sort(mStopsList); - ArrayList mRoutesList = new ArrayList<>(mRoutes); + final ArrayList mRoutesList = new ArrayList<>(mRoutes); Collections.sort(mRoutesList); - ArrayList mTripsList = new ArrayList<>(mDirections); + final ArrayList mTripsList = new ArrayList<>(mDirections); Collections.sort(mTripsList); - ArrayList mDirectionStopsList = new ArrayList<>(mDirectionStops); + final ArrayList mDirectionStopsList = new ArrayList<>(mDirectionStops); Collections.sort(mDirectionStopsList); - ArrayList mServiceDatesList = new ArrayList<>(mServiceDates); + final ArrayList mServiceDatesList = new ArrayList<>(mServiceDates); Collections.sort(mServiceDatesList); MTLog.log("Generating routes, trips, trip stops & stops objects... DONE"); MTLog.log("- Agencies: %d", mAgenciesList.size()); @@ -179,6 +176,7 @@ public static MSpec generateMSpec(@NotNull GSpec gtfs, @NotNull GAgencyTools age MTLog.log("- Trips: %d", mTripsList.size()); MTLog.log("- Trip stops: %d", mDirectionStopsList.size()); MTLog.log("- Stops: %d", mStopsList.size()); + MTLog.log("- Service Ids: %d", MServiceIds.getAll().size()); MTLog.log("- Service Dates: %d", mServiceDatesList.size()); MTLog.log("- Route with Frequencies: %d", mRouteFrequencies.size()); MTLog.log("- First timestamp: %s", MTLog.formatDateTime(firstTimestamp)); @@ -196,8 +194,16 @@ public static MSpec generateMSpec(@NotNull GSpec gtfs, @NotNull GAgencyTools age ); } + private static final boolean DEBUG_LOG_MERGING = false; // Set to true to enable merging logs + + private static void logMerging(@NotNull String msg, long routeId) { + if (!DEBUG_LOG_MERGING) return; + MTLog.logDebug("%s: Generating routes, trips, trip stops & stops objects... (merging %s)", routeId, msg); + } + private static final String GTFS_SCHEDULE = "gtfs_schedule"; private static final String GTFS_SCHEDULE_SERVICE_DATES = GTFS_SCHEDULE + "_service_dates"; // DB + private static final String GTFS_SCHEDULE_SERVICE_IDS = GTFS_SCHEDULE + "_service_ids"; // DB private static final String GTFS_SCHEDULE_STOP = GTFS_SCHEDULE + "_stop_"; // file private static final String GTFS_FREQUENCY = "gtfs_frequency"; private static final String GTFS_FREQUENCY_ROUTE = GTFS_FREQUENCY + "_route_"; // file @@ -274,6 +280,8 @@ public static void dumpFiles(@NotNull GAgencyTools gAgencyTools, dumpScheduleStops(gAgencyTools, mSpec, fileBase, deleteAll, rawDirF); // FREQUENCY ROUTES dumpFrequencyRoutes(gAgencyTools, mSpec, fileBase, deleteAll, rawDirF); + // SERVICE IDS + dumpServiceIds(mSpec, fileBase, deleteAll, dataDirF, rawDirF, dbConnection); // AFTER SCHEDULE STOPS & FREQUENCY ROUTES if (deleteAll) { dumpValues(rawDirF, fileBase, null, null, null, null, null, -1, -1, null, true); } else { @@ -513,6 +521,53 @@ private static Pair, Pair> dumpRDSStops(@Nu return minMaxLatLng; } + private static void dumpServiceIds( + @Nullable MSpec mSpec, + @NotNull String fileBase, + boolean deleteAll, + @NotNull File dataDirF, + @NotNull File rawDirF, + @Nullable Connection dbConnection) { + if (!FeatureFlags.F_EXPORT_SERVICE_ID_INTS) return; + if (!deleteAll + && (mSpec == null || !mSpec.isValid() || (F_PRE_FILLED_DB && dbConnection == null))) { + throw new MTLog.Fatal("Generated data invalid (agencies: %s)!", mSpec); + } + if (F_PRE_FILLED_DB) { + FileUtils.deleteIfExist(new File(rawDirF, fileBase + GTFS_SCHEDULE_SERVICE_IDS)); // migration from src/main/res/raw to data + } + File file = new File(F_PRE_FILLED_DB ? dataDirF : rawDirF, fileBase + GTFS_SCHEDULE_SERVICE_IDS); + FileUtils.deleteIfExist(file); // delete previous + try (BufferedWriter ow = new BufferedWriter(new FileWriter(file))) { + if (!deleteAll) { + MTLog.logPOINT(); // LOG + Statement dbStatement = null; + String sqlInsert = null; + if (F_PRE_FILLED_DB) { + SQLUtils.setAutoCommit(dbConnection, false); // START TRANSACTION + dbStatement = dbConnection.createStatement(); + sqlInsert = GTFSCommons.getT_SERVICE_IDS_SQL_INSERT(); + } + for (MServiceId mServiceId : MServiceIds.getAll()) { + final String serviceIdsInsert = mServiceId.toFile(); + if (F_PRE_FILLED_DB) { + SQLUtils.executeUpdate( + dbStatement, + String.format(sqlInsert, serviceIdsInsert) + ); + } + ow.write(serviceIdsInsert); + ow.write(Constants.NEW_LINE); + } + if (F_PRE_FILLED_DB) { + SQLUtils.setAutoCommit(dbConnection, true); // END TRANSACTION == commit() + } + } + } catch (Exception ioe) { + throw new MTLog.Fatal(ioe, "I/O Error while writing service IDs file!"); + } + } + @NotNull private static Pair dumpScheduleServiceDates(@NotNull GAgencyTools gAgencyTools, @Nullable MSpec mSpec, @@ -803,6 +858,7 @@ private static String getLastModified(String gtfsDir) { private static final String GTFS_RDS_AGENCY_EXTENDED_TYPE = "gtfs_rts_agency_extended_type"; // do not change to avoid breaking compat w/ old modules private static final String GTFS_RDS_TIMEZONE = "gtfs_rts_timezone"; // do not change to avoid breaking compat w/ old modules private static final String GTFS_RDS_COLOR = "gtfs_rts_color"; // do not change to avoid breaking compat w/ old modules + private static final String GTFS_RDS_SERVICE_ID_CLEANUP_REGEX = "gtfs_rts_service_id_cleanup_regex"; // do not change to avoid breaking compat w/ old modules private static final String GTFS_RDS_ROUTE_ID_CLEANUP_REGEX = "gtfs_rts_route_id_cleanup_regex"; // do not change to avoid breaking compat w/ old modules private static final String GTFS_RDS_TRIP_ID_CLEANUP_REGEX = "gtfs_rts_trip_id_cleanup_regex"; // do not change to avoid breaking compat w/ old modules private static final String GTFS_RDS_STOP_ID_CLEANUP_REGEX = "gtfs_rts_stop_id_cleanup_regex"; // do not change to avoid breaking compat w/ old modules @@ -852,6 +908,10 @@ private static void dumpCommonValues(File dumpDirF, GAgencyTools gAgencyTools, M ow.write(Constants.NEW_LINE); ow.write(getRESOURCES_STRING(GTFS_RDS_COLOR, mSpec.getFirstAgency().getColor())); ow.write(Constants.NEW_LINE); + if (gAgencyTools.getServiceIdCleanupRegex() != null) { + ow.write(getRESOURCES_STRING(GTFS_RDS_SERVICE_ID_CLEANUP_REGEX, escapeResString(gAgencyTools.getServiceIdCleanupRegex()))); + ow.write(Constants.NEW_LINE); + } if (gAgencyTools.getRouteIdCleanupRegex() != null) { ow.write(getRESOURCES_STRING(GTFS_RDS_ROUTE_ID_CLEANUP_REGEX, escapeResString(gAgencyTools.getRouteIdCleanupRegex()))); ow.write(Constants.NEW_LINE); diff --git a/src/main/java/org/mtransit/parser/mt/MReader.kt b/src/main/java/org/mtransit/parser/mt/MReader.kt index 7613d9d..daecf66 100644 --- a/src/main/java/org/mtransit/parser/mt/MReader.kt +++ b/src/main/java/org/mtransit/parser/mt/MReader.kt @@ -13,6 +13,7 @@ import org.mtransit.parser.MTLog import org.mtransit.parser.Pair import org.mtransit.parser.gtfs.data.GFieldTypes import org.mtransit.parser.mt.data.MServiceDate +import org.mtransit.parser.mt.data.MServiceId import java.io.File import java.util.TimeZone @@ -140,4 +141,27 @@ object MReader { } // endregion + + // region service IDs + + private const val GTFS_SCHEDULE_SERVICE_IDS = "gtfs_schedule_service_ids" + + @JvmStatic + fun loadServiceIds(fileBase: String) = try { + File(getResDirName(fileBase) + "/$RAW/${fileBase}$GTFS_SCHEDULE_SERVICE_IDS") + .takeIf { it.exists() } + ?.readLines() + ?.mapNotNull { line -> + MServiceId.fromFileLine(line) + } + ?: run { + MTLog.log("File not found '${"/$RAW/${fileBase}$GTFS_SCHEDULE_SERVICE_IDS"}'!") + null + } + } catch (e: Exception) { + MTLog.logNonFatal(e, "Error while reading '$fileBase' service ids!") + null + } + + // endregion } \ No newline at end of file diff --git a/src/main/java/org/mtransit/parser/mt/data/MAgency.kt b/src/main/java/org/mtransit/parser/mt/data/MAgency.kt index 3e6d118..b541adf 100644 --- a/src/main/java/org/mtransit/parser/mt/data/MAgency.kt +++ b/src/main/java/org/mtransit/parser/mt/data/MAgency.kt @@ -29,9 +29,9 @@ data class MAgency( agencyTools.agencyRouteType, ) - @Discouraged(message = "Not memory efficient") @Suppress("unused") - val id = _id + @get:Discouraged(message = "Not memory efficient") + val id: String get() = _id private val _id: String get() { diff --git a/src/main/java/org/mtransit/parser/mt/data/MFrequency.kt b/src/main/java/org/mtransit/parser/mt/data/MFrequency.kt index 2efccc0..c63de4d 100644 --- a/src/main/java/org/mtransit/parser/mt/data/MFrequency.kt +++ b/src/main/java/org/mtransit/parser/mt/data/MFrequency.kt @@ -1,6 +1,7 @@ package org.mtransit.parser.mt.data import androidx.annotation.Discouraged +import org.mtransit.commons.FeatureFlags import org.mtransit.parser.Constants import org.mtransit.parser.db.SQLUtils.quotesEscape import org.mtransit.parser.gtfs.GAgencyTools @@ -14,54 +15,35 @@ data class MFrequency( private val headwayInSec: Int ) : Comparable { - @Discouraged(message = "Not memory efficient") @Suppress("unused") - val serviceId = _serviceId + @get:Discouraged(message = "Not memory efficient") + val serviceId: String get() = _serviceId private val _serviceId: String - get() { - return GIDs.getString(serviceIdInt) - } - - private fun getCleanServiceId(agencyTools: GAgencyTools): String { - return agencyTools.cleanServiceId(_serviceId) - } + get() = GIDs.getString(serviceIdInt) val uID by lazy { getNewUID(serviceIdInt, directionId, startTime, endTime) } - fun toFile(agencyTools: GAgencyTools) = listOf( - getCleanServiceId(agencyTools).quotesEscape(), // service ID - directionId.toString(), // direction ID - startTime.toString(), // start time - endTime.toString(), // end time - headwayInSec.toString(), // headway in seconds - ).joinToString(Constants.COLUMN_SEPARATOR_) + fun toFile(agencyTools: GAgencyTools) = buildList { + if (FeatureFlags.F_EXPORT_SERVICE_ID_INTS) { + add(MServiceIds.getInt(agencyTools.cleanServiceId(_serviceId))) + } else { + add(agencyTools.cleanServiceId(_serviceId).quotesEscape()) + } + add(directionId.toString()) + add(startTime.toString()) + add(endTime.toString()) + add(headwayInSec.toString()) + }.joinToString(Constants.COLUMN_SEPARATOR_) override fun compareTo(other: MFrequency?): Int { return when { - other !is MFrequency -> { - +1 - } - - serviceIdInt != other.serviceIdInt -> { - _serviceId.compareTo(other._serviceId) - } - - directionId != other.directionId -> { - directionId.compareTo(other.directionId) - } - - startTime != other.startTime -> { - startTime - other.startTime - } - - endTime != other.endTime -> { - endTime - other.endTime - } - - else -> { - headwayInSec - other.headwayInSec - } + other !is MFrequency -> +1 + serviceIdInt != other.serviceIdInt -> _serviceId.compareTo(other._serviceId) + directionId != other.directionId -> directionId.compareTo(other.directionId) + startTime != other.startTime -> startTime - other.startTime + endTime != other.endTime -> endTime - other.endTime + else -> headwayInSec - other.headwayInSec } } diff --git a/src/main/java/org/mtransit/parser/mt/data/MSchedule.kt b/src/main/java/org/mtransit/parser/mt/data/MSchedule.kt index 1af0fc4..a5956f3 100644 --- a/src/main/java/org/mtransit/parser/mt/data/MSchedule.kt +++ b/src/main/java/org/mtransit/parser/mt/data/MSchedule.kt @@ -1,6 +1,7 @@ package org.mtransit.parser.mt.data import androidx.annotation.Discouraged +import org.mtransit.commons.FeatureFlags import org.mtransit.parser.Constants import org.mtransit.parser.DefaultAgencyTools import org.mtransit.parser.MTLog @@ -44,23 +45,19 @@ data class MSchedule( accessible = accessible, ) - @Discouraged(message = "Not memory efficient") @Suppress("unused") - val serviceId = _serviceId + @get:Discouraged(message = "Not memory efficient") + val serviceId: String get() = _serviceId private val _serviceId: String - get() { - return GIDs.getString(serviceIdInt) - } + get() = GIDs.getString(serviceIdInt) - @Discouraged(message = "Not memory efficient") @Suppress("unused") - val tripId = _tripId + @get:Discouraged(message = "Not memory efficient") + val tripId: String get() = _tripId private val _tripId: String - get() { - return GIDs.getString(tripIdInt) - } + get() = GIDs.getString(tripIdInt) fun setHeadsign(newHeadsignType: Int, newHeadsignValue: String?) { if (newHeadsignValue.isNullOrBlank() @@ -101,10 +98,14 @@ data class MSchedule( } fun toFileNewServiceIdAndDirectionId(agencyTools: GAgencyTools) = buildList { - add(agencyTools.cleanServiceId(_serviceId).quotesEscape()) // service ID + if (FeatureFlags.F_EXPORT_SERVICE_ID_INTS) { + add(MServiceIds.getInt(agencyTools.cleanServiceId(_serviceId))) + } else { + add(agencyTools.cleanServiceId(_serviceId).quotesEscape()) + } // no route ID, just for file split - add(directionId.toString()) // direction ID - add(departure.toString()) // departure + add(directionId.toString()) + add(departure.toString()) if (DefaultAgencyTools.EXPORT_TRIP_ID) { @Suppress("ControlFlowWithEmptyBody") if (arrivalBeforeDeparture > 0) { @@ -113,13 +114,13 @@ data class MSchedule( add(arrivalBeforeDeparture.takeIf { it > 0 }?.toString() ?: Constants.EMPTY) // arrival before departure add(_tripId.quotesEscape()) } - add(headsignType.takeIf { it >= 0 }?.toString() ?: Constants.EMPTY) // HEADSIGN TYPE - add((headsignValue ?: Constants.EMPTY).quotesEscape()) // HEADSIGN STRING + add(headsignType.takeIf { it >= 0 }?.toString() ?: Constants.EMPTY) + add((headsignValue ?: Constants.EMPTY).quotesEscape()) add(accessible.toString()) }.joinToString(Constants.COLUMN_SEPARATOR_) fun toFileSameServiceIdAndDirectionId(lastSchedule: MSchedule?) = buildList { - add((departure - (lastSchedule?.departure ?: 0)).toString()) // departure + add((departure - (lastSchedule?.departure ?: 0)).toString()) if (DefaultAgencyTools.EXPORT_TRIP_ID) { @Suppress("ControlFlowWithEmptyBody") if (arrivalBeforeDeparture > 0) { @@ -129,11 +130,11 @@ data class MSchedule( add(_tripId.quotesEscape()) } if (headsignType == MDirection.HEADSIGN_TYPE_NO_PICKUP) { - add(MDirection.HEADSIGN_TYPE_NO_PICKUP.toString()) // HEADSIGN TYPE - add(Constants.EMPTY.quotes()) // HEADSIGN STRING + add(MDirection.HEADSIGN_TYPE_NO_PICKUP.toString()) + add(Constants.EMPTY.quotes()) } else { - add(headsignType.takeIf { it >= 0 }?.toString() ?: Constants.EMPTY) // HEADSIGN TYPE - add((headsignValue ?: Constants.EMPTY).quotesEscape()) // HEADSIGN STRING + add(headsignType.takeIf { it >= 0 }?.toString() ?: Constants.EMPTY) + add((headsignValue ?: Constants.EMPTY).quotesEscape()) } add(accessible.toString()) }.joinToString(Constants.COLUMN_SEPARATOR_) @@ -164,25 +165,11 @@ data class MSchedule( override fun compareTo(other: MSchedule): Int { // sort by route_id => service_id => direction_id => stop_id => departure return when { - routeId != other.routeId -> { - routeId.compareTo(other.routeId) - } - - serviceIdInt != other.serviceIdInt -> { - _serviceId.compareTo(other._serviceId) - } - - directionId != other.directionId -> { - directionId.compareTo(other.directionId) - } - - stopId != other.stopId -> { - stopId - other.stopId - } - - else -> { - departure - other.departure - } + routeId != other.routeId -> routeId.compareTo(other.routeId) + serviceIdInt != other.serviceIdInt -> _serviceId.compareTo(other._serviceId) + directionId != other.directionId -> directionId.compareTo(other.directionId) + stopId != other.stopId -> stopId - other.stopId + else -> departure - other.departure } } diff --git a/src/main/java/org/mtransit/parser/mt/data/MServiceDate.kt b/src/main/java/org/mtransit/parser/mt/data/MServiceDate.kt index eaae0a8..ae6615a 100644 --- a/src/main/java/org/mtransit/parser/mt/data/MServiceDate.kt +++ b/src/main/java/org/mtransit/parser/mt/data/MServiceDate.kt @@ -1,6 +1,7 @@ package org.mtransit.parser.mt.data import androidx.annotation.Discouraged +import org.mtransit.commons.FeatureFlags import org.mtransit.parser.Constants import org.mtransit.parser.db.SQLUtils.quotesEscape import org.mtransit.parser.db.SQLUtils.unquotes @@ -15,7 +16,7 @@ data class MServiceDate( val exceptionType: Int, ) : Comparable { - constructor( + private constructor( serviceIdInt: Int, calendarDate: Int, exceptionType: MCalendarExceptionType @@ -25,14 +26,12 @@ data class MServiceDate( exceptionType.id ) - @Discouraged(message = "Not memory efficient") + @get:Discouraged(message = "Not memory efficient") @Suppress("unused") - val serviceId = _serviceId + val serviceId: String get() = _serviceId private val _serviceId: String - get() { - return GIDs.getString(serviceIdInt) - } + get() = GIDs.getString(serviceIdInt) override fun compareTo(other: MServiceDate): Int = compareBy( MServiceDate::calendarDate, @@ -41,8 +40,12 @@ data class MServiceDate( ).compare(this, other) fun toFile(agencyTools: GAgencyTools) = buildList { - add(agencyTools.cleanServiceId(_serviceId).quotesEscape()) // service ID - add(calendarDate.toString()) // calendar date + if (FeatureFlags.F_EXPORT_SERVICE_ID_INTS) { + add(MServiceIds.getInt(agencyTools.cleanServiceId(_serviceId))) + } else { + add(agencyTools.cleanServiceId(_serviceId).quotesEscape()) + } + add(calendarDate.toString()) add(exceptionType.toString()) }.joinToString(Constants.COLUMN_SEPARATOR_) @@ -72,15 +75,28 @@ data class MServiceDate( return serviceDates.joinToString { it.toStringPlus() } } - fun fromFileLine(line: String) = line.split(Constants.COLUMN_SEPARATOR) - .takeIf { it.size == 3 } - ?.let { columns -> - MServiceDate( - serviceIdInt = GIDs.getInt(columns[0].unquotes()), // service ID - calendarDate = columns[1].toInt(), // calendar date - exceptionType = columns[2].toInt() - ) - } + @JvmStatic + fun fromCalendarDate(calendarDate: GCalendarDate) = + MServiceDate( + serviceIdInt = calendarDate.serviceIdInt, + calendarDate = calendarDate.date, + exceptionType = when (calendarDate.exceptionType) { + GCalendarDatesExceptionType.SERVICE_ADDED -> MCalendarExceptionType.ADDED + GCalendarDatesExceptionType.SERVICE_REMOVED -> MCalendarExceptionType.REMOVED + GCalendarDatesExceptionType.SERVICE_DEFAULT -> MCalendarExceptionType.DEFAULT + } + ) + + fun fromFileLine(line: String) = + line.split(Constants.COLUMN_SEPARATOR) + .takeIf { it.size == 3 } + ?.let { columns -> + MServiceDate( + serviceIdInt = GIDs.getInt(columns[0].unquotes()), + calendarDate = columns[1].toInt(), + exceptionType = columns[2].toInt() + ) + } @Suppress("unused") @JvmStatic diff --git a/src/main/java/org/mtransit/parser/mt/data/MServiceId.kt b/src/main/java/org/mtransit/parser/mt/data/MServiceId.kt new file mode 100644 index 0000000..bb34609 --- /dev/null +++ b/src/main/java/org/mtransit/parser/mt/data/MServiceId.kt @@ -0,0 +1,41 @@ +package org.mtransit.parser.mt.data + +import org.mtransit.parser.Constants +import org.mtransit.parser.MTLog +import org.mtransit.parser.db.SQLUtils.quotesEscape +import org.mtransit.parser.db.SQLUtils.unquotes + +data class MServiceId( + val serviceIdInt: Int, + val serviceId: String, // already agencyTools.cleanServiceId(serviceId) before +) : Comparable { + + /** + * same order as [org.mtransit.commons.GTFSCommons.T_SERVICE_IDS_SQL_INSERT] + */ + fun toFile() = buildList { + add(serviceIdInt.toString()) + add(serviceId.quotesEscape()) // already agencyTools.cleanServiceId(serviceId) before + }.joinToString(Constants.COLUMN_SEPARATOR_) + + override fun compareTo(other: MServiceId) = compareBy( + MServiceId::serviceIdInt, + MServiceId::serviceId, + ).compare(this, other) + + companion object { + fun fromFileLine(line: String): MServiceId? = + line.split(Constants.COLUMN_SEPARATOR) + .takeIf { it.size == 2 } + ?.let { columns -> + MServiceId( + serviceIdInt = columns[0].toInt(), + serviceId = columns[1].unquotes(), + ) + } + ?: run { + MTLog.log("Invalid service ID line: '$line'!") + null + } + } +} diff --git a/src/main/java/org/mtransit/parser/mt/data/MServiceIds.kt b/src/main/java/org/mtransit/parser/mt/data/MServiceIds.kt new file mode 100644 index 0000000..4671e91 --- /dev/null +++ b/src/main/java/org/mtransit/parser/mt/data/MServiceIds.kt @@ -0,0 +1,55 @@ +package org.mtransit.parser.mt.data + +import androidx.collection.SparseArrayCompat +import androidx.collection.mutableScatterMapOf +import org.mtransit.parser.MTLog + +object MServiceIds { + + private val incrementLock = Any() + + private var increment = 0 + private val idIntToId = SparseArrayCompat() + private val idToIdInt = mutableScatterMapOf() + + @JvmStatic + fun addAll(lastServiceIds: List?) { + lastServiceIds?.forEach { add(it) } + } + + fun add(serviceId: MServiceId) { + synchronized(incrementLock) { + idIntToId.put(serviceId.serviceIdInt, serviceId.serviceId) + idToIdInt[serviceId.serviceId] = serviceId.serviceIdInt + increment = maxOf(increment, serviceId.serviceIdInt) + } + } + + fun add(serviceId: String): Int { + synchronized(incrementLock) { + increment++ // move to next + val newServiceId = MServiceId(increment, serviceId) + add(newServiceId) + return newServiceId.serviceIdInt + } + } + + @Suppress("unused") + @JvmStatic + fun getString(serviceIdInt: Int) = + idIntToId[serviceIdInt] ?: throw MTLog.Fatal("Unexpected Service ID integer $serviceIdInt!") + + @JvmStatic + fun getInt(serviceId: String): Int = + idToIdInt[serviceId] + ?: synchronized(incrementLock) { + return idToIdInt[serviceId] ?: add(serviceId) + } + + @JvmStatic + fun getAll() = buildList { + idToIdInt.forEach { id, idInt -> + add(MServiceId(idInt, id)) + } + }.sorted() +}