diff --git a/src/services/trainService.services.js b/src/services/trainService.services.js index d7379e7..71610fa 100644 --- a/src/services/trainService.services.js +++ b/src/services/trainService.services.js @@ -16,7 +16,7 @@ async function findByHeadcodeToday(headcode) { daysRun: {$in: [shortDay]} }; const queryData = await db.query('timetable', query); - let trainData = await parseTrains(queryData, now); + let trainData = await parseTrains(queryData); let preparedData = []; for (const trainService in trainData) { // Search for PIS Code for each service @@ -25,7 +25,7 @@ async function findByHeadcodeToday(headcode) { const pisDetail = await pis.findByTiplocArray(tiplocList); trainData[trainService]['pis'] = pisDetail?.[0]?.['code'] ?? 'None'; } else { - trainData[trainService]['pis'] = '0015' // Not in Service code + trainData[trainService]['pis'] = '0015'; // Not in Service code } preparedData.push(trainData[trainService]); } @@ -48,29 +48,131 @@ async function getPublicStops(data) { return tiplocList; } -async function parseTrains(data, date = new Date() { - // Parses an array returned from a db-query and removes any service entries that don't apply to {date} - // {date} shoule be a datetime object and defaults to now if not provided - as a general rule it should always be provided for clarity - // At this point, the returned objects need sorting to ensure the correct object is returned. - // C, N, O, P is the order - C being the preferred, then N, then O and finally P. - // If stpindicator == "C" && trainUid (isSame as N, O or P entry) => DO NOT DISPLAY SERVICE ("C" records do not contain the headcode (signalling_id)) so an additional lookup needs to be performed for the trainUid. - // If stpIndicator == "N" && trainUid (isSame as O or P entry) => Display this instead of "O", or "P" - // If stpIndicaor == "O" && trainUid (isSame as P entry) => Display this instead of "P" - // Obviously, remember that several trains can share a headcode, but the trainUid is unique for each service. - // Probably best to loop through each return here and add to a new [], then if another entry supersedes it, overwrite it in the []. Then pass to the below part of the function to process the data for sending. - // Maybe break in to a new function parseTrains() which can take in any dbquery array and remove any services that are not meant to be displayed based on the data provided. Maybe have a date as an input so it can be used in the future to fetch trains for a given date in the future - due to database cleaning in db-manager, past dates would need adjustments to how the database is cleaned leaving outdated services available. - const parsedData = data; - return parsedData; - let trainUids = [] +async function parseTrains(data) { // Takes a single days data from a headcode query and returns only relevant services + let trainUids = []; for (const i in data) { - const trainUid = data[i]['trainUid'] + const trainUid = data[i]['trainUid']; if (!trainUids.includes(trainUid)) { - data.push(trainUid) + data.push(trainUid); } } - let parsedData = [] + let parsedData = []; for (const i in trainUids) { - result = await findByTrainUid(trainUids[i]) - parsedData.push(result) + const result = await findByTrainUid(trainUids[i]); + parsedData.push(result); } -}; + return parsedData; +} + +async function findByTrainUid(uid, date = new Date()) { // Date defaults to today + const query = { + trainUid: uid, + scheduleStartDate: {$lte: date}, + scheduleEndDate: {$gte: date} + }; + const queryData = await db.query('timetable', query); + let c = []; + let n = []; + let o = []; + let p = []; + for (const serviceDetail of queryData) { + const trainUid = serviceDetail['trainUid']; + switch (serviceDetail['stpIndicator']) { // This won't work without further post procesing + case 'C': + c.push(trainUid); + break; + case 'N': + if (!c.includes(trainUid)) { + n.push(trainUid); + } + break; + case 'O': + if (!c.includes(trainUid) && !n.includes(trainUid)) { + o.push(trainUid); + } + break; + case 'P': + if (!c.includes(trainUid) && !n.includes(trainUid) && !o.includes(trainUid)) { + p.push(trainUid); + } + break; + } + } +} + +/* Thoughts: +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) { + // Handle empty queryData + return { + c: [], + n: [], + o: [], + p: [] + }; + } + + const trainUidSet = new Set(); + const trainUidStatus = {}; // Track the status of each trainUid + + for (const serviceDetail of queryData) { + const trainUid = serviceDetail['trainUid']; + const stpIndicator = serviceDetail['stpIndicator']; + + if (!trainUidStatus[trainUid]) { + trainUidStatus[trainUid] = { + hasO: false, + hasN: false, + hasC: false + }; + } + + if (stpIndicator === 'O') { + trainUidStatus[trainUid].hasO = true; + } else if (stpIndicator === 'N') { + trainUidStatus[trainUid].hasN = true; + } else if (stpIndicator === 'C') { + trainUidStatus[trainUid].hasC = true; + } + + trainUidSet.add(trainUid); + } + + const c = []; + const n = []; + const o = []; + const p = []; + + for (const serviceDetail of queryData) { + const trainUid = serviceDetail['trainUid']; + const stpIndicator = serviceDetail['stpIndicator']; + + if (stpIndicator === 'C') { + continue; // Skip 'C' entries + } + + if (stpIndicator === 'N' && !trainUidStatus[trainUid].hasC) { + n.push(trainUid); + } else if (stpIndicator === 'O' && !trainUidStatus[trainUid].hasN && !trainUidStatus[trainUid].hasC) { + o.push(trainUid); + } else if (stpIndicator === 'P' && !trainUidStatus[trainUid].hasN && !trainUidStatus[trainUid].hasO && !trainUidStatus[trainUid].hasC) { + p.push(trainUid); + } + } + + return { + c, + n, + o, + p + }; +} +*/ \ No newline at end of file