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

0001 /*
0002    SPDX-FileCopyrightText: 2017 Volker Krause <vkrause@kde.org>
0003    SPDX-FileCopyrightText: 2018 Daniel Vrátil <dvratil@kde.org>
0004 
0005    SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 function isHeaderOrFooter(line) {
0009     return line.search(/(Jízdní řád( a rezervace)?|Jízdenku lze použít po stejné trase|Jízdní doklad zakoupený u obchodníka)/) >= 0;
0010 }
0011 
0012 function createSeat(res)
0013 {
0014     if (!res.reservedTicket)
0015         res.reservedTicket = JsonLd.newObject("Ticket");
0016     if (!res.reservedTicket.ticketedSeat)
0017         res.reservedTicket.ticketedSeat = JsonLd.newObject("Seat");
0018 }
0019 
0020 function parseSeat(res, text) {
0021     var coach = text.match(/(\s+)(\d+)/);
0022     var idx = 0;
0023     if (coach) {
0024         createSeat(res);
0025         res.reservedTicket.ticketedSeat.seatSection = coach[2];
0026         idx = coach.index + coach[1].length + coach[2].length;
0027     }
0028     var seat = text.substr(idx).match(/\s+([\d,\- ]+)/)
0029     if (seat && seat[1].trim()) {
0030         seatNumber = seat[1].trim();
0031         if (seatNumber) {
0032             createSeat(res);
0033             res.reservedTicket.ticketedSeat.seatNumber = seatNumber;
0034         }
0035     }
0036 }
0037 
0038 // There's no validity year anywhere in the ticket, so we take the purchase date and
0039 // if the trip month and day are after the purchase month and day we assume the
0040 // the ticket will become valid the same year it was purchased, otherwise we assume
0041 // the ticket is for next year.
0042 // This fails when you buy the ticket more than a year ahead of the trip, but I doubt
0043 // you can even do that with Czech Railways...
0044 function detectYear(tripDate, purchaseDate)
0045 {
0046     var tripDay = parseInt(tripDate[1]);
0047     var tripMonth = parseInt(tripDate[2]);
0048     var purchaseDay = parseInt(purchaseDate[2]);
0049     var purchaseMonth = parseInt(purchaseDate[3]);
0050     var purchaseYear = parseInt(purchaseDate[4]);
0051 
0052     if ((purchaseMonth < tripMonth) ||
0053         (purchaseMonth === tripMonth) && (purchaseDay <= tripDay)) {
0054         return purchaseYear;
0055     } else {
0056         return purchaseYear + 1;
0057     }
0058 }
0059 
0060 function parseDeparture(res, line, purchaseDate) {
0061     res.reservationFor.departureStation = JsonLd.newObject("TrainStation");
0062     var station = line.match(/^(.+?)  /);
0063     if (!station)
0064         return;
0065     var idx = station.index + station[0].length;
0066     res.reservationFor.departureStation.name = station[1];
0067     var dt = line.substr(idx).match(/([0-9]{2})\.([0-9]{2})\. ([0-9]{2}:[0-9]{2})/);
0068     if (dt) {
0069         idx += dt.index + dt[0].length;
0070         res.reservationFor.departureTime = JsonLd.toDateTime(dt[1] + ' ' + dt[2] + ' ' + detectYear(dt, purchaseDate) + ' ' + dt[3], "dd MM yyyy hh:mm", "cs");
0071     }
0072     var trainId = line.substr(idx).match(/([a-zA-Z]+ [0-9a-zA-Z]+)/);
0073     if (trainId) {
0074         idx += trainId.index + trainId[0].length
0075         res.reservationFor.trainNumber = trainId[1];
0076     }
0077     parseSeat(res, line.substr(idx));
0078 }
0079 
0080 function parseArrival(res, line, purchaseDate) {
0081     res.reservationFor.arrivalStation = JsonLd.newObject("TrainStation");
0082     var station = line.match(/^(.+?)  /);
0083     if (!station)
0084         return;
0085     var idx = station.index + station[0].length;
0086     res.reservationFor.arrivalStation.name = station[1];
0087     var dt = line.substr(idx).match(/([0-9]{2})\.([0-9]{2})\. ([0-9]{2}:[0-9]{2})/);
0088     if (dt) {
0089         idx += dt.index + dt[0].length;
0090         res.reservationFor.arrivalTime = JsonLd.toDateTime(dt[1] + ' ' + dt[2] + ' ' + detectYear(dt, purchaseDate) + ' ' + dt[3], "dd MM yyyy hh:mm", "cs");
0091     }
0092 }
0093 
0094 function findNextStationLineIndex(lines, start) {
0095     var pos = start;
0096     while (pos < lines.length && (lines[pos].startsWith(" ") || lines[pos].startsWith("Ref:"))) {
0097         pos += 1;
0098     }
0099     return pos;
0100 }
0101 
0102 function parseLegs(text, purchaseDate) {
0103     var reservations = new Array();
0104     var lines = text.split('\n');
0105     var depIdx = 1, arrIdx = 2;
0106     while (depIdx < lines.length) {
0107         // stop when reaching the footer or the next itinerary header
0108         if (isHeaderOrFooter(lines[depIdx]))
0109             return reservations;
0110 
0111         var res = JsonLd.newObject("TrainReservation");
0112         res.reservationFor = JsonLd.newObject("TrainTrip");
0113 
0114         arrIdx = findNextStationLineIndex(lines, depIdx + 1)
0115         parseDeparture(res, lines[depIdx], purchaseDate);
0116         parseArrival(res, lines[arrIdx], purchaseDate);
0117 
0118         // Find the next leg
0119         depIdx = findNextStationLineIndex(lines, arrIdx + 1);
0120 
0121         reservations.push(res);
0122     }
0123 
0124     return reservations;
0125 }
0126 
0127 function main(text) {
0128     var reservations = new Array();
0129     var pos = 0;
0130 
0131     var purchaseDate = text.match(/([d|D]atum platby|UZP): ([0-9]{1,2})\.([0-9]{1,2})\.([0-9]{4})/)
0132 
0133     while (true) {
0134          // find itinerary headers
0135         var header = text.substr(pos).match(/Timetable( and Reservations)?/);
0136         if (!header)
0137             break;
0138         var idx = header.index + header[0].length;
0139         var timetableHeader = text.substr(pos + idx).match(/(Místo \/ Seat \/ Sitzplatz)/)
0140         idx = idx + timetableHeader.index + timetableHeader[0].length;
0141         reservations = reservations.concat(parseLegs(text.substr(pos + idx), purchaseDate));
0142         if (idx == 0)
0143             break;
0144         pos += idx + 1;
0145     }
0146 
0147     var bookingRef = text.match(/Kód transakce:\s*([A-Z0-9]{6})\n/);
0148     for (var i = 0; bookingRef && i < reservations.length; ++i)
0149         reservations[i].reservationNumber = bookingRef[1];
0150     return reservations;
0151 }
0152 
0153 // ### this is based on an international ticket, do domestic ones look the same?
0154 function parsePdfTicket(content, node, triggerNode) {
0155     const page = content.pages[triggerNode.location];
0156     const text = page.textInRect(0.0, 0.0, 0.675, 1.0);
0157     let idx = 0;
0158     let reservations = [];
0159     while (true) {
0160         let leg = text.substr(idx).match(/\n(.*?)  +(\d\d\.\d\d\.) +(\d\d:\d\d) +(.*?)(?:  +(\d+) +(\d+))?\n(.*?)  +(\d\d.\d\d.) +(\d\d:\d\d)/);
0161         if (!leg) {
0162             break;
0163         }
0164         let res = JsonLd.newTrainReservation();
0165         res.reservationFor.departureStation.name = leg[1];
0166         res.reservationFor.departureTime = JsonLd.toDateTime(leg[2] + leg[3], 'dd.MM.hh:mm', 'cz');
0167         res.reservationFor.arrivalStation.name = leg[7];
0168         res.reservationFor.arrivalTime = JsonLd.toDateTime(leg[8] + leg[9], 'dd.MM.hh:mm', 'cz');
0169         res.reservationFor.trainNumber = leg[4];
0170         if (leg[5] && leg[6]) {
0171             res.reservedTicket.ticketedSeat.seatSection = leg[5];
0172             res.reservedTicket.ticketedSeat.seatNumber = leg[6];
0173         }
0174 
0175         if (triggerNode.result[0]['@type'] == 'TrainReservation') {
0176             res = JsonLd.apply(triggerNode.result[0], res);
0177             res.reservationNumber = triggerNode.content.block('1154UT').findSubBlock('KK').content;
0178         }
0179         res.reservedTicket = JsonLd.apply(triggerNode.result[0].reservedTicket, res.reservedTicket);
0180 
0181         reservations.push(res);
0182         idx += leg.index + leg[0].length;
0183     }
0184 
0185     return reservations;
0186 }
0187 
0188 function parseUicTicket(uic, node)
0189 {
0190     if (node.result[0]['@type'] == 'TrainReservation') {
0191         let res = node.result[0];
0192         res.reservationNumber = uic.block('1154UT').findSubBlock('KK').content;
0193         res.reservedTicket.ticketNumber = uic.pnr;
0194         return res;
0195     } else {
0196         let ticket = node.result[0];
0197         ticket.ticketNumber = uic.pnr;
0198         return ticket;
0199     }
0200 }
0201 
0202 function parseEvent(event) {
0203     let reservations = [];
0204     let idx = 0;
0205     while (true) {
0206         const leg = event.description.substr(idx).match(/(.*)\n(.*) (\d\d):(\d\d)\n(.*) (\d\d):(\d\d)\n.* (\d+),.* (\d+)/);
0207         if (!leg)
0208             break;
0209         idx += leg.index + leg[0].length;
0210 
0211         let res = JsonLd.newTrainReservation();
0212         res.reservationFor.trainNumber = leg[1];
0213         res.reservationFor.departureStation.name = leg[2];
0214         res.reservationFor.departureTime = new Date(event.dtStart);
0215         res.reservationFor.departureTime.setHours(leg[3], leg[4]);
0216         res.reservationFor.arrivalStation.name = leg[5];
0217         res.reservationFor.arrivalTime = new Date(event.dtStart);
0218         res.reservationFor.arrivalTime.setHours(leg[6], leg[7]);
0219         res.reservedTicket.ticketedSeat.seatSection = leg[8];
0220         res.reservedTicket.ticketedSeat.seatNumber = leg[9];
0221         reservations.push(res);
0222     }
0223     return reservations;
0224 }