File indexing completed on 2024-12-29 04:51:00

0001 /*
0002     SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "eradocumentprocessor.h"
0008 #include "logging.h"
0009 
0010 #include "era/elbticket.h"
0011 #include "era/ssbticketreader.h"
0012 #include "era/ssbv1ticket.h"
0013 #include "era/ssbv2ticket.h"
0014 #include "era/ssbv3ticket.h"
0015 
0016 #include <KItinerary/ExtractorResult>
0017 
0018 #include <KItinerary/Reservation>
0019 #include <KItinerary/Ticket>
0020 #include <KItinerary/TrainTrip>
0021 
0022 using namespace KItinerary;
0023 
0024 bool ElbDocumentProcessor::canHandleData(const QByteArray &encodedData, [[maybe_unused]] QStringView fileName) const
0025 {
0026     return ELBTicket::maybeELBTicket(encodedData);
0027 }
0028 
0029 ExtractorDocumentNode ElbDocumentProcessor::createNodeFromData(const QByteArray &encodedData) const
0030 {
0031     ExtractorDocumentNode node;
0032     if (const auto ticket = ELBTicket::parse(encodedData)) {
0033         node.setContent(*ticket);
0034     }
0035     return node;
0036 }
0037 
0038 bool SsbDocumentProcessor::canHandleData(const QByteArray &encodedData, [[maybe_unused]] QStringView fileName) const
0039 {
0040     return SSBv3Ticket::maybeSSB(encodedData) || SSBv2Ticket::maybeSSB(encodedData) || SSBv1Ticket::maybeSSB(encodedData);
0041 }
0042 
0043 ExtractorDocumentNode SsbDocumentProcessor::createNodeFromData(const QByteArray &encodedData) const
0044 {
0045     ExtractorDocumentNode node;
0046     node.setContent(SSBTicketReader::read(encodedData));
0047     return node;
0048 }
0049 
0050 TrainStation makeStation(int idType, const QString &alphaId, int numericId)
0051 {
0052     TrainStation station;
0053     if (idType == 0 && numericId > 10'00000 && numericId < 99'99999) {
0054       station.setIdentifier(QLatin1StringView("uic:") +
0055                             QString::number(numericId));
0056       station.setName(QString::number(numericId));
0057     } else if (idType == 1 && alphaId.size() == 5 && std::all_of(alphaId.begin(), alphaId.end(), [](QChar c) { return c.isUpper(); })) {
0058         // TODO is the identifier type defined in that case??
0059         station.setName(alphaId);
0060     }
0061     return station;
0062 }
0063 
0064 void SsbDocumentProcessor::preExtract(ExtractorDocumentNode &node, [[maybe_unused]] const ExtractorEngine *engine) const
0065 {
0066     if (node.isA<SSBv3Ticket>()) {
0067         const auto ssb = node.content<SSBv3Ticket>();
0068 
0069         Seat seat;
0070         seat.setSeatingType(QString::number(ssb.classOfTravel()));
0071         Ticket ticket;
0072         ticket.setTicketToken(QLatin1StringView("aztecbin:") +
0073                               QString::fromLatin1(ssb.rawData().toBase64()));
0074 
0075         Organization issuer;
0076         issuer.setIdentifier(
0077             QLatin1StringView("uic:") +
0078             QString::number(ssb.issuerCode())); // left pad with 0 to 4 digets?
0079         TrainTrip trip;
0080         trip.setProvider(issuer);
0081 
0082         TrainReservation res;
0083         res.setReservationNumber(ssb.tcn());
0084         ticket.setTicketNumber(ssb.tcn());
0085 
0086         switch (ssb.ticketTypeCode()) {
0087             case SSBv3Ticket::IRT_RES_BOA:
0088                 trip.setDepartureDay(ssb.type1DepartureDay(node.contextDateTime()));
0089                 trip.setTrainNumber(ssb.type1TrainNumber());
0090                 seat.setSeatSection(QString::number(ssb.type1CoachNumber()));
0091                 seat.setSeatNumber(ssb.type1SeatNumber());
0092                 trip.setDepartureStation(makeStation(ssb.type1StationCodeNumericOrAlpha(), ssb.type1DepartureStationAlpha(), ssb.type1DepartureStationNum()));
0093                 trip.setDepartureStation(makeStation(ssb.type1StationCodeNumericOrAlpha(), ssb.type1ArrivalStationAlpha(), ssb.type1ArrivalStationNum()));
0094                 break;
0095             case SSBv3Ticket::NRT:
0096                 trip.setDepartureStation(makeStation(ssb.type2StationCodeNumericOrAlpha(), ssb.type2DepartureStationAlpha(), ssb.type2DepartureStationNum()));
0097                 trip.setArrivalStation(makeStation(ssb.type2StationCodeNumericOrAlpha(), ssb.type2ArrivalStationAlpha(), ssb.type2ArrivalStationNum()));
0098                 ticket.setValidFrom(ssb.type2ValidFrom(node.contextDateTime()).startOfDay());
0099                 ticket.setValidUntil({ssb.type2ValidUntil(node.contextDateTime()), {23, 59, 59}});
0100                 trip.setDepartureDay(ssb.type2ValidFrom(node.contextDateTime()));
0101                 break;
0102             case SSBv3Ticket::GRT:
0103             case SSBv3Ticket::RPT:
0104                 qCWarning(Log) << "Unsupported SSB v3 ticket type:" << ssb.ticketTypeCode();
0105                 return;
0106         }
0107 
0108         res.setReservationFor(trip);
0109         ticket.setTicketedSeat(seat);
0110         res.setReservedTicket(ticket);
0111         node.addResult(QList<QVariant>{QVariant::fromValue(res)});
0112     }
0113 }