UNPKG

typed-ocpp

Version:

A library for type-aware parsing, serialization and validation of OCPP 1.6, OCPP 2.0 and OCPP 2.1 messages

120 lines 4.63 kB
/* * This module implements primitive types and functions to deal with temporal * schedules as arrays of non-overlapping period objects. */ /** * Returns the first (and only) period in the schedule which covers the time * instant represented by the provided date. Returns undefined if the schedule * does not contain one such period. */ export const getPeriodForDate = (schedule, value) => { return schedule.find(p => p.start <= value); }; /** * Merges two schedules together. Overlapping periods will be broken down into * shorter periods. The cloning and merging functions will be called to create * the resulting periods and may be used to customize the merging logic in the * case of partially or completely overlapping periods. */ export const merge = (left, right, cloner, merger) => { const merged_schedule = []; let lp = 0; let rp = 0; let l = left[0]; let r = right[0]; let next_left = false; let next_right = false; let merged_period; while (lp < left.length || rp < right.length) { if (lp >= left.length) { // No items left in left, we continue with left until we run out of items. merged_period = { ...r, data: cloner(r.data) }; next_right = true; } else if (rp >= right.length) { // No items left in right, we continue with left util we run out of items. merged_period = { ...l, data: cloner(l.data) }; next_left = true; } else if (l.end < r.start) { // Left item comes entirely before right item merged_period = { ...l, data: cloner(l.data) }; next_left = true; } else if (r.end < l.start) { // Right item comes entirely before left item merged_period = { ...r, data: cloner(r.data) }; next_right = true; } else { if (l.start === r.start) { // Left starts on the same date as right if (l.end > r.end) { // Left starts on the same date as right but ends after it merged_period = { ...r, data: merger(l.data, r.data) }; l = { ...l, start: r.end }; next_right = true; } else if (l.end < r.end) { // Left starts on the same date as right but ends before it merged_period = { ...l, data: merger(l.data, r.data) }; r = { ...r, start: l.end }; next_left = true; } else { // Left and right start and end on the same dates merged_period = { ...r, data: merger(l.data, r.data) }; next_left = true; next_right = true; } } else if (l.start < r.start) { // Left starts before right merged_period = { ...l, end: r.start, data: cloner(l.data) }; l = { ...l, start: r.start }; } else { // Right starts before left merged_period = { ...r, end: l.start, data: cloner(r.data) }; r = { ...r, start: l.start }; } } if (merged_period) { if (merged_period.end > merged_period.start) { merged_schedule.push(merged_period); } merged_period = undefined; } if (next_left = next_left || (l && l.start >= l.end)) { // If left has collapsed into a zero-length period we advance to the next one l = left[++lp]; next_left = false; } if (next_right = next_right || (r && r.start >= r.end)) { // If right has collapsed into a zero-length period we advance to the next one r = right[++rp]; next_right = false; } } return merged_schedule; }; /** * Fills empty gaps in a schedule with new periods built upon the provided * `defaults` data object. */ export const fillGaps = (schedule, start, end, getPeriodData) => { const filled = []; let curr = start; for (const period of schedule) { if (curr < period.start) { filled.push({ start: curr, end: period.start, data: getPeriodData(curr, period.start) }); } filled.push(period); curr = period.end; } if (curr < end) { filled.push({ start: curr, end, data: getPeriodData(curr, end) }); } return filled; }; //# sourceMappingURL=schedule.js.map