Files
ontime/apps/server/src/services/rundown-service/delayUtils.ts
T

89 lines
2.9 KiB
TypeScript

import { Rundown, EntryId, isOntimeDelay, isOntimeEvent, OntimeEvent } from 'ontime-types';
import { deleteAtIndex } from 'ontime-utils';
/**
* Applies delay from given event ID, deletes the delay event after
* Mutates the given rundown
* @throws if event ID not found or is not a delay
*/
export function apply(delayId: EntryId, rundown: Rundown): Rundown {
const delayEvent = rundown.entries[delayId];
if (!delayEvent || !isOntimeDelay(delayEvent)) {
throw new Error('Given delay ID not found');
}
const delayIndex = rundown.order.findIndex((entryId) => entryId === delayId);
// if the delay is empty, or the last element
// we can just delete it with no further operations
if (delayEvent.duration === 0 || delayIndex === rundown.order.length - 1) {
delete rundown.entries[delayId];
rundown.order = deleteAtIndex(delayIndex, rundown.order);
return rundown;
}
/**
* We apply the delay to the rundown
* This logic is mostly in sync with rundownCache.generate
* The difference is that here it will become part of the schedule,
* so we cant leave the work for the generate function
*/
let delayValue = delayEvent.duration;
let lastEntry: OntimeEvent | null = null;
let isFirstEvent = true;
for (let i = delayIndex + 1; i < rundown.order.length; i++) {
const currentId = rundown.order[i];
const currentEntry = rundown.entries[currentId];
// we don't do operation on other event types
if (!isOntimeEvent(currentEntry)) {
continue;
}
// we need to remove the link in the first event to maintain the gap
let shouldUnlink = isFirstEvent;
isFirstEvent = false;
// if the event is not linked, we try and maintain gaps
if (lastEntry !== null) {
// when applying negative delays, we need to unlink the event
// if the previous event was fully consumed by the delay
if (currentEntry.linkStart && delayValue < 0 && lastEntry.timeStart + delayValue < 0) {
shouldUnlink = true;
}
if (currentEntry.gap > 0) {
delayValue = Math.max(delayValue - currentEntry.gap, 0);
}
if (delayValue === 0) {
// we can bail from continuing if there are no further delays to apply
break;
}
}
// save the current entry before making mutations on its values
lastEntry = { ...currentEntry };
if (shouldUnlink) {
currentEntry.linkStart = null;
shouldUnlink = false;
}
// event times move up by the delay value
// we dont update the delay value since we would need to iterate through the entire dataset
// this is handled by the rundownCache.generate function
currentEntry.timeStart = Math.max(0, currentEntry.timeStart + delayValue);
currentEntry.timeEnd = Math.max(currentEntry.duration, currentEntry.timeEnd + delayValue);
currentEntry.revision += 1;
}
delete rundown.entries[delayId];
rundown.order = deleteAtIndex(delayIndex, rundown.order);
rundown.revision += 1;
return rundown;
}