File indexing completed on 2024-12-08 07:19:12

0001 /*
0002     SPDX-FileCopyrightText: 2018 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "stopoverrequest.h"
0008 #include "requestcontext_p.h"
0009 #include "datatypes/datatypes_p.h"
0010 #include "datatypes/json_p.h"
0011 #include "datatypes/locationutil_p.h"
0012 
0013 #include <KPublicTransport/Location>
0014 
0015 #include <QCryptographicHash>
0016 #include <QDateTime>
0017 #include <QMetaEnum>
0018 #include <QSharedData>
0019 
0020 using namespace KPublicTransport;
0021 
0022 enum { DepartureCacheTimeResolution = 60 }; // in seconds
0023 
0024 namespace KPublicTransport {
0025 class StopoverRequestPrivate : public QSharedData {
0026 public:
0027     Location stop;
0028     QDateTime dateTime;
0029     StopoverRequest::Mode mode = StopoverRequest::QueryDeparture;
0030     std::vector<RequestContext> contexts;
0031     QStringList backendIds;
0032     std::vector<Line::Mode> lineModes;
0033     bool downloadAssets = false;
0034     int maximumResults = 12;
0035 };
0036 }
0037 
0038 KPUBLICTRANSPORT_MAKE_GADGET(StopoverRequest)
0039 KPUBLICTRANSPORT_MAKE_PROPERTY(StopoverRequest, Location, stop, setStop)
0040 KPUBLICTRANSPORT_MAKE_PROPERTY(StopoverRequest, StopoverRequest::Mode, mode, setMode)
0041 KPUBLICTRANSPORT_MAKE_PROPERTY(StopoverRequest, bool, downloadAssets, setDownloadAssets)
0042 KPUBLICTRANSPORT_MAKE_PROPERTY(StopoverRequest, int, maximumResults, setMaximumResults)
0043 
0044 StopoverRequest::StopoverRequest(const Location &stop)
0045     : d(new StopoverRequestPrivate)
0046 {
0047     d->stop = stop;
0048 }
0049 
0050 bool StopoverRequest::isValid() const
0051 {
0052     return !d->stop.isEmpty();
0053 }
0054 
0055 QDateTime StopoverRequest::dateTime() const
0056 {
0057     if (!d->dateTime.isValid()) {
0058         d->dateTime = QDateTime::currentDateTime();
0059     }
0060     return d->dateTime;
0061 }
0062 
0063 void StopoverRequest::setDateTime(const QDateTime &dt)
0064 {
0065     d.detach();
0066     d->dateTime = dt;
0067 }
0068 
0069 const std::vector<Line::Mode>& StopoverRequest::lineModes() const
0070 {
0071     return d->lineModes;
0072 }
0073 
0074 void StopoverRequest::setLineModes(std::vector<Line::Mode> &&lineModes)
0075 {
0076     d.detach();
0077     d->lineModes = std::move(lineModes);
0078     std::sort(d->lineModes.begin(), d->lineModes.end());
0079     d->lineModes.erase(std::unique(d->lineModes.begin(), d->lineModes.end()), d->lineModes.end());
0080 }
0081 
0082 QVariantList StopoverRequest::lineModesVariant() const
0083 {
0084     QVariantList l;
0085     l.reserve(d->lineModes.size());
0086     std::transform(d->lineModes.begin(), d->lineModes.end(), std::back_inserter(l), [](const Line::Mode &value) {
0087         return QVariant::fromValue<Line::Mode>(value);
0088     });
0089     return l;
0090 }
0091 
0092 void StopoverRequest::setLineModesVariant(const QVariantList &lineModes)
0093 {
0094     auto l = std::move(d->lineModes);
0095     l.clear();
0096     l.reserve(lineModes.size());
0097     std::transform(lineModes.begin(), lineModes.end(), std::back_inserter(l), [](const auto &mode) { return static_cast<Line::Mode>(mode.toInt()); });
0098     setLineModes(std::move(l));
0099 }
0100 
0101 RequestContext StopoverRequest::context(const AbstractBackend *backend) const
0102 {
0103     const auto it = std::lower_bound(d->contexts.begin(), d->contexts.end(), backend);
0104     if (it != d->contexts.end() && (*it).backend == backend) {
0105         return *it;
0106     }
0107 
0108     RequestContext context;
0109     context.backend = backend;
0110     return context;
0111 }
0112 
0113 const std::vector<RequestContext>& StopoverRequest::contexts() const
0114 {
0115     return d->contexts;
0116 }
0117 
0118 void StopoverRequest::setContext(const AbstractBackend *backend, RequestContext &&context)
0119 {
0120     d.detach();
0121     const auto it = std::lower_bound(d->contexts.begin(), d->contexts.end(), backend);
0122     if (it != d->contexts.end() && (*it).backend == backend) {
0123         (*it) = std::move(context);
0124     } else {
0125         d->contexts.insert(it, std::move(context));
0126     }
0127 }
0128 
0129 void StopoverRequest::purgeLoops(const StopoverRequest &baseRequest)
0130 {
0131     RequestContext::purgeLoops(d->contexts, baseRequest.contexts());
0132 }
0133 
0134 QJsonObject StopoverRequest::toJson(const StopoverRequest &req)
0135 {
0136     auto obj = Json::toJson(req);
0137     obj.insert(QLatin1String("stop"), Location::toJson(req.stop()));
0138     return obj;
0139 }
0140 
0141 QStringList StopoverRequest::backendIds() const
0142 {
0143     return d->backendIds;
0144 }
0145 
0146 void StopoverRequest::setBackendIds(const QStringList &backendIds)
0147 {
0148     d.detach();
0149     d->backendIds = backendIds;
0150 }
0151 
0152 QString StopoverRequest::cacheKey() const
0153 {
0154     QCryptographicHash hash(QCryptographicHash::Sha1);
0155     hash.addData(QByteArray::number(d->dateTime.toSecsSinceEpoch() / DepartureCacheTimeResolution));
0156     hash.addData(LocationUtil::cacheKey(d->stop).toUtf8());
0157     hash.addData(d->mode == StopoverRequest::QueryArrival ? "A" : "D");
0158 
0159     hash.addData("MODES");
0160     for (const auto &mode : d->lineModes) {
0161         hash.addData(QMetaEnum::fromType<Line::Mode>().valueToKey(mode));
0162     }
0163 
0164     return QString::fromUtf8(hash.result().toHex());
0165 }
0166 
0167 #include "moc_stopoverrequest.cpp"