File indexing completed on 2025-02-02 05:02:34
0001 /* 0002 SPDX-FileCopyrightText: 2019-2023 Volker Krause <vkrause@kde.org> 0003 SPDX-License-Identifier: LGPL-2.0-or-later 0004 */ 0005 0006 #include "publictransportmatcher.h" 0007 #include "logging.h" 0008 #include "publictransport.h" 0009 #include "reservationhelper.h" 0010 0011 #include <KItinerary/LocationUtil> 0012 #include <KItinerary/Reservation> 0013 #include <KItinerary/SortUtil> 0014 0015 #include <KPublicTransport/Journey> 0016 #include <KPublicTransport/Stopover> 0017 0018 bool PublicTransportMatcher::isSameMode(const QVariant &res, KPublicTransport::Line::Mode mode) 0019 { 0020 using namespace KPublicTransport; 0021 0022 if (KItinerary::JsonLd::isA<KItinerary::TrainReservation>(res)) { 0023 return PublicTransport::isTrainMode(mode); 0024 } else if (KItinerary::JsonLd::isA<KItinerary::BusReservation>(res)) { 0025 return PublicTransport::isBusMode(mode); 0026 } else if (KItinerary::JsonLd::isA<KItinerary::FlightReservation>(res)) { 0027 return mode == Line::Air; 0028 } else if (KItinerary::JsonLd::isA<KItinerary::BoatReservation>(res)) { 0029 return mode == Line::Boat || mode == Line::Ferry; 0030 } else if (res.isValid()) { 0031 qCWarning(Log) << "unexpected reservation type!?" << res; 0032 } 0033 0034 return false; 0035 } 0036 0037 bool PublicTransportMatcher::isSameMode(const QVariant &res, const KPublicTransport::JourneySection §ion) 0038 { 0039 return isSameMode(res, section.route().line().mode()); 0040 } 0041 0042 bool PublicTransportMatcher::isSameRoute(const KPublicTransport::Route &lhs, const QString &trainName, const QString &trainNumber) 0043 { 0044 KPublicTransport::Line rhs; 0045 rhs.setModeString(trainName); 0046 rhs.setName(trainNumber); 0047 if (KPublicTransport::Line::isSame(lhs.line(), rhs)) { 0048 return true; 0049 } 0050 if (lhs.name().size() >= 3) { 0051 rhs.setName(QString(trainName + QLatin1Char(' ') + trainNumber).trimmed()); 0052 auto lhsLine = lhs.line(); 0053 lhsLine.setModeString(QString()); 0054 lhsLine.setName(lhs.name()); 0055 return KPublicTransport::Line::isSame(lhsLine, rhs); 0056 } 0057 return false; 0058 } 0059 0060 bool PublicTransportMatcher::isDepartureForReservation(const QVariant &res, const KPublicTransport::Stopover &dep) 0061 { 0062 const auto lineData = ReservationHelper::lineNameAndNumber(res); 0063 return PublicTransportMatcher::isSameMode(res, dep.route().line().mode()) 0064 && KItinerary::SortUtil::startDateTime(res) == dep.scheduledDepartureTime() 0065 && PublicTransportMatcher::isSameRoute(dep.route(), lineData.first, lineData.second); 0066 } 0067 0068 bool PublicTransportMatcher::isArrivalForReservation(const QVariant &res, const KPublicTransport::Stopover &arr) 0069 { 0070 const auto lineData = ReservationHelper::lineNameAndNumber(res); 0071 return PublicTransportMatcher::isSameMode(res, arr.route().line().mode()) 0072 && KItinerary::SortUtil::endDateTime(res) == arr.scheduledArrivalTime() 0073 && PublicTransportMatcher::isSameRoute(arr.route(), lineData.first, lineData.second); 0074 } 0075 0076 bool PublicTransportMatcher::isJourneyForReservation(const QVariant &res, const KPublicTransport::JourneySection &journey) 0077 { 0078 const auto lineData = ReservationHelper::lineNameAndNumber(res); 0079 return PublicTransportMatcher::isSameMode(res, journey.route().line().mode()) 0080 && KItinerary::SortUtil::startDateTime(res) == journey.scheduledDepartureTime() 0081 && PublicTransportMatcher::isSameRoute(journey.route(), lineData.first, lineData.second); 0082 } 0083 0084 /* Compare times without assuming times without a timezone are in the current time zone 0085 * (they might be local to the destination instead). 0086 */ 0087 static bool isSameDateTime(const QDateTime &lhs, const QDateTime &rhs) 0088 { 0089 if (lhs == rhs) { 0090 return true; 0091 } 0092 if (lhs.timeSpec() == Qt::LocalTime && rhs.timeSpec() != Qt::LocalTime) { 0093 QDateTime dt(rhs); 0094 dt.setTimeSpec(Qt::LocalTime); 0095 return lhs == dt; 0096 } 0097 if (lhs.timeSpec() != Qt::LocalTime && rhs.timeSpec() == Qt::LocalTime) { 0098 QDateTime dt(lhs); 0099 dt.setTimeSpec(Qt::LocalTime); 0100 return dt == rhs; 0101 } 0102 return false; 0103 } 0104 0105 static bool isSameDeparture(const QVariant &depLoc, const QVariant &res, const QDateTime &depTime, const KPublicTransport::Stopover &stop) 0106 { 0107 return isSameDateTime(depTime, stop.scheduledDepartureTime()) 0108 && KPublicTransport::Location::isSame(PublicTransport::locationFromPlace(depLoc, res), stop.stopPoint()); 0109 } 0110 0111 static bool isSameArrival(const QVariant &arrLoc, const QVariant &res, const QDateTime &arrTime, const KPublicTransport::Stopover &stop) 0112 { 0113 return isSameDateTime(arrTime, stop.scheduledArrivalTime()) 0114 && KPublicTransport::Location::isSame(PublicTransport::locationFromPlace(arrLoc, res), stop.stopPoint()); 0115 } 0116 0117 KPublicTransport::JourneySection PublicTransportMatcher::subJourneyForReservation(const QVariant &res, const KPublicTransport::JourneySection &journey) 0118 { 0119 const auto lineData = ReservationHelper::lineNameAndNumber(res); 0120 if (!PublicTransportMatcher::isSameMode(res, journey.route().line().mode()) || 0121 !PublicTransportMatcher::isSameRoute(journey.route(), lineData.first, lineData.second)) { 0122 return {}; 0123 } 0124 0125 KPublicTransport::JourneySection result(journey); 0126 auto stopovers = result.takeIntermediateStops(); 0127 0128 auto it = stopovers.begin(); 0129 if (!isSameDeparture(KItinerary::LocationUtil::departureLocation(res), res, KItinerary::SortUtil::startDateTime(res), journey.departure())) { 0130 for (;it != stopovers.end(); ++it) { 0131 if (isSameDeparture(KItinerary::LocationUtil::departureLocation(res), res, KItinerary::SortUtil::startDateTime(res), *it)) { 0132 result.setDeparture(*it); 0133 break; 0134 } 0135 } 0136 } 0137 if (it == stopovers.end()) { 0138 return {}; 0139 } 0140 ++it; 0141 auto it2 = it; 0142 for (;it2 != stopovers.end(); ++it2) { 0143 if (isSameArrival(KItinerary::LocationUtil::arrivalLocation(res), res, KItinerary::SortUtil::endDateTime(res), *it2)) { 0144 result.setArrival(*it2); 0145 break; 0146 } 0147 } 0148 if (it2 == stopovers.end() && !isSameArrival(KItinerary::LocationUtil::arrivalLocation(res), res, KItinerary::SortUtil::endDateTime(res), journey.arrival())) { 0149 return {}; 0150 } 0151 0152 result.setIntermediateStops({it, it2}); 0153 return result; 0154 }