import { EventBus } from '../core/EventBus'; import { IEventBus, CalendarEvent, RenderContext } from '../types/CalendarTypes'; import { CoreEvents } from '../constants/CoreEvents'; import { calendarConfig } from '../core/CalendarConfig'; import { CalendarTypeFactory } from '../factories/CalendarTypeFactory'; import { EventManager } from '../managers/EventManager'; import { EventRendererStrategy } from './EventRenderer'; /** * EventRenderingService - Render events i DOM med positionering using Strategy Pattern * Håndterer event positioning og overlap detection */ export class EventRenderingService { private eventBus: IEventBus; private eventManager: EventManager; private strategy: EventRendererStrategy; constructor(eventBus: IEventBus, eventManager: EventManager) { this.eventBus = eventBus; this.eventManager = eventManager; // Cache strategy at initialization const calendarType = calendarConfig.getCalendarMode(); this.strategy = CalendarTypeFactory.getEventRenderer(calendarType); this.setupEventListeners(); } /** * Render events in a specific container for a given period */ public renderEvents(context: RenderContext): void { // Clear existing events in the specific container first this.strategy.clearEvents(context.container); // Get events from EventManager for the period const events = this.eventManager.getEventsForPeriod( context.startDate, context.endDate ); if (events.length === 0) { return; } // Use cached strategy to render events in the specific container this.strategy.renderEvents(events, context.container, calendarConfig); // Emit EVENTS_RENDERED event for filtering system this.eventBus.emit(CoreEvents.EVENTS_RENDERED, { events: events, container: context.container }); } private setupEventListeners(): void { // Event-driven rendering: React to grid and container events this.eventBus.on(CoreEvents.GRID_RENDERED, (event: Event) => { this.handleGridRendered(event as CustomEvent); }); // CONTAINER_READY_FOR_EVENTS removed - events are now pre-rendered synchronously // this.eventBus.on(EventTypes.CONTAINER_READY_FOR_EVENTS, (event: Event) => { // this.handleContainerReady(event as CustomEvent); // }); this.eventBus.on(CoreEvents.VIEW_CHANGED, (event: Event) => { this.handleViewChanged(event as CustomEvent); }); } /** * Handle GRID_RENDERED event - render events in the current grid */ private handleGridRendered(event: CustomEvent): void { const { container, startDate, endDate, currentDate } = event.detail; if (!container) { return; } let periodStart: Date; let periodEnd: Date; if (startDate && endDate) { // Direct date format - use as provided periodStart = startDate; periodEnd = endDate; } else if (currentDate) { return; } else { return; } this.renderEvents({ container: container, startDate: periodStart, endDate: periodEnd }); } /** * Handle CONTAINER_READY_FOR_EVENTS event - render events in pre-rendered container */ private handleContainerReady(event: CustomEvent): void { const { container, startDate, endDate } = event.detail; if (!container || !startDate || !endDate) { return; } this.renderEvents({ container: container, startDate: new Date(startDate), endDate: new Date(endDate) }); } /** * Handle VIEW_CHANGED event - clear and re-render for new view */ private handleViewChanged(event: CustomEvent): void { // Clear all existing events since view structure may have changed this.clearEvents(); // New rendering will be triggered by subsequent GRID_RENDERED event } private clearEvents(container?: HTMLElement): void { this.strategy.clearEvents(container); } public refresh(container?: HTMLElement): void { // Clear events in specific container or globally this.clearEvents(container); } public destroy(): void { this.clearEvents(); } }