const log = require('../utils/log.utils'); const db = require('./dbAccess.services'); const clean = require('../utils/sanitizer.utils'); const pis = require('../services/pis.services'); async function findByHeadcodeToday(headcode) { const sanitizedHeadcode = clean.removeNonAlphanumeric(headcode).toUpperCase(); log.out('trainServiceServices.findByHeadcode: Searching for headcode ' + sanitizedHeadcode, 'dbug'); const now = new Date(); const dayMap = ['su', 'm', 't', 'w', 'th', 'f', 's']; const shortDay = dayMap[now.getDay()]; // Fetch short day from map const query = { headcode: sanitizedHeadcode, scheduleStartDate: {$lte: now}, scheduleEndDate: {$gte: now}, daysRun: {$in: [shortDay]} }; const queryData = await db.query('timetable', query); let trainData = await parseTrains(queryData); let preparedData = []; for (let trainService in trainData) { // Search for PIS Code for each service const tiplocList = await getPublicStops(trainData[trainService]['stops']); //console.log(tiplocList.length); console.log(tiplocList); if (tiplocList.length) { const pisDetail = await pis.findByTiplocArray(tiplocList); trainData[trainService]['pis'] = pisDetail?.[0]?.['code'] ?? 'None'; } else { trainData[trainService]['pis'] = '0015'; // Not in Service code // '0015' is a string otherwise it is interpreted as octal 13. } preparedData.push(trainData[trainService]); } return preparedData; } async function findByHeadcode(date, headcode) { const sanitizedHeadcode = clean.removeNonAlphanumeric(headcode).toUpperCase(); log.out('trainServiceServices.findByHeadcode: Searching for headcode ' + sanitizedHeadcode, 'dbug'); let searchDate; if (date === 'now') { searchDate = new Date(); } else { searchDate = new Date(date); } const dayMap = ['su', 'm', 't', 'w', 'th', 'f', 's']; const shortDay = dayMap[searchDate.getDay()]; // Fetch short day from map const query = { headcode: sanitizedHeadcode, scheduleStartDate: {$lte: searchDate}, scheduleEndDate: {$gte: searchDate}, daysRun: {$in: [shortDay]} }; const queryData = await db.query('timetable', query); let trainData = await parseTrains(queryData); let preparedData = []; for (let trainService in trainData) { // Search for PIS Code for each service const tiplocList = await getPublicStops(trainData[trainService]['stops']); //console.log(tiplocList.length); console.log(tiplocList); if (tiplocList.length) { const pisDetail = await pis.findByTiplocArray(tiplocList); trainData[trainService]['pis'] = pisDetail?.[0]?.['code'] ?? 'None'; } else { trainData[trainService]['pis'] = '0015'; // Not in Service code // '0015' is a string otherwise it is interpreted as octal 13. } preparedData.push(trainData[trainService]); } return preparedData; } module.exports = { findByHeadcodeToday, findByHeadcode }; /* Internal Functions, not to be exported */ /* Accepts the 'stops' array from a db query and produces an array of only public stops as TIPLOCs. */ async function getPublicStops(data) { let tiplocList = []; for (const publicStop in data) { if (data[publicStop]['isPublic']) { tiplocList.push(data[publicStop]['tiploc']); } } return tiplocList; } /* Takes a single days data from a headcode query and requeries using the trainUid, required to ensure any cancellations are accounted for */ async function parseTrains(data) { let trainUids = []; for (const i of data) { const trainUid = i['trainUid']; if (!trainUids.includes(trainUid)) { trainUids.push(trainUid); } } let parsedData = []; for (const i in trainUids) { const result = await findByTrainUid(trainUids[i]); parsedData.push(result); } return parsedData; } /* Queries using a trainUid and filters all schedules that have been over-ridden by overlays, cancellations and new schedules. */ async function findByTrainUid(uid, date = new Date()) { const query = { trainUid: uid, scheduleStartDate: {$lte: date}, scheduleEndDate: {$gte: date} }; const queryData = await db.query('timetable', query); if (queryData.length === 0) { return []; } let stpIndicators = {}; for (const serviceDetail of queryData) { const trainUid = serviceDetail['trainUid']; const stpIndicator = serviceDetail['stpIndicator']; if (!stpIndicators[trainUid]) { stpIndicators[trainUid] = { hasC: false, hasN: false, hasO: false, hasP: false }; } if (stpIndicator === 'C') { stpIndicators[trainUid].hasC = true; } if (stpIndicator === 'N') { stpIndicators[trainUid].hasN = true; } if (stpIndicator === 'O') { stpIndicators[trainUid].hasO = true; } if (stpIndicator === 'P') { stpIndicators[trainUid].hasP = true; } } let preparedData = []; for (const serviceDetail of queryData) { const trainUid = serviceDetail['trainUid']; const thisStpIndicators = stpIndicators[trainUid]; const stpIndicator = serviceDetail['stpIndicator']; if (stpIndicator === 'C') { return; } if (stpIndicator === 'N' && !thisStpIndicators.hasC) { return serviceDetail; } else if (stpIndicator === 'O' && !thisStpIndicators.hasC && !thisStpIndicators.hasN) { return serviceDetail; } else if (stpIndicator === 'P' && !thisStpIndicators.hasC && !thisStpIndicators.hasN && !thisStpIndicators.hasO) { return serviceDetail; } } return preparedData; }