/** * OverlapDetector - Ren tidbaseret overlap detection * Ingen DOM manipulation, kun tidsberegninger */ import { CalendarEvent } from '../types/CalendarTypes'; // Branded type for event IDs export type EventId = string & { readonly __brand: 'EventId' }; export type OverlapResult = { overlappingEvents: CalendarEvent[]; stackLinks: Map; }; export interface StackLink { prev?: EventId; // Event ID of previous event in stack next?: EventId; // Event ID of next event in stack stackLevel: number; // 0 = base event, 1 = first stacked, etc } export class OverlapDetector { /** * Resolver hvilke events et givent event overlapper med i en kolonne * @param event - CalendarEvent der skal checkes for overlap * @param columnEvents - Array af CalendarEvent objekter i kolonnen * @returns Array af events som det givne event overlapper med */ public resolveOverlap(event: CalendarEvent, columnEvents: CalendarEvent[]): CalendarEvent[] { return columnEvents.filter(existingEvent => { // To events overlapper hvis: // event starter før existing slutter OG // event slutter efter existing starter return event.start < existingEvent.end && event.end > existingEvent.start; }); } /** * Dekorerer events med stack linking data * @param newEvent - Det nye event der skal tilføjes * @param overlappingEvents - Events som det nye event overlapper med * @returns OverlapResult med overlappende events og stack links */ public decorateWithStackLinks(newEvent: CalendarEvent, overlappingEvents: CalendarEvent[]): OverlapResult { const stackLinks = new Map(); if (overlappingEvents.length === 0) { return { overlappingEvents: [], stackLinks }; } // Kombiner nyt event med eksisterende og sortér efter start tid (tidligste første) const allEvents = [...overlappingEvents, newEvent].sort((a, b) => a.start.getTime() - b.start.getTime() ); // Opret sammenhængende kæde - alle events bindes sammen allEvents.forEach((event, index) => { const stackLink: StackLink = { stackLevel: index, prev: index > 0 ? allEvents[index - 1].id as EventId : undefined, next: index < allEvents.length - 1 ? allEvents[index + 1].id as EventId : undefined }; stackLinks.set(event.id as EventId, stackLink); }); return { overlappingEvents, stackLinks }; } }