import { EventBus } from '../core/EventBus.js'; import { EventTypes } from '../constants/EventTypes.js'; import { CalendarConfig } from '../core/CalendarConfig.js'; import { CalendarEvent, CalendarView, IEventBus } from '../types/CalendarTypes.js'; import { EventManager } from './EventManager.js'; import { GridManager } from './GridManager.js'; import { EventRenderer } from './EventRenderer.js'; import { ScrollManager } from './ScrollManager.js'; /** * CalendarManager - Main coordinator for all calendar managers * Uses simple direct method calls instead of complex state management */ export class CalendarManager { private eventBus: IEventBus; private config: CalendarConfig; private eventManager: EventManager; private gridManager: GridManager; private eventRenderer: EventRenderer; private scrollManager: ScrollManager; private currentView: CalendarView = 'week'; private currentDate: Date = new Date(); private isInitialized: boolean = false; constructor(eventBus: IEventBus, config: CalendarConfig) { this.eventBus = eventBus; this.config = config; this.setupEventListeners(); console.log('📋 CalendarManager: Created with direct coordination'); } /** * Set manager references (called from index.ts) */ public setManagers(eventManager: EventManager, gridManager: GridManager, eventRenderer: EventRenderer, scrollManager: ScrollManager): void { this.eventManager = eventManager; this.gridManager = gridManager; this.eventRenderer = eventRenderer; this.scrollManager = scrollManager; } /** * Initialize calendar system using simple direct calls */ public async initialize(): Promise { if (this.isInitialized) { console.warn('CalendarManager is already initialized'); return; } console.log('🚀 CalendarManager: Starting simple initialization'); try { // Debug: Check calendar type const calendarType = this.config.getCalendarMode(); console.log(`🔍 CalendarManager: Initializing ${calendarType} calendar`); // Step 1: Load data console.log('📊 Loading event data...'); await this.eventManager.loadData(); // Step 2: Pass data to GridManager and render grid structure console.log('🏗️ Rendering grid...'); if (calendarType === 'resource') { const resourceData = this.eventManager.getResourceData(); this.gridManager.setResourceData(resourceData); } await this.gridManager.render(); // Step 3: Initialize scroll synchronization console.log('📜 Setting up scroll synchronization...'); this.scrollManager.initialize(); // Step 4: Set initial view and date BEFORE event rendering console.log('⚙️ Setting initial view and date...'); this.setView(this.currentView); this.setCurrentDate(this.currentDate); // Step 5: Event rendering will be triggered by GRID_RENDERED event console.log('🎨 Event rendering will be triggered automatically by grid events...'); this.isInitialized = true; console.log('✅ CalendarManager: Simple initialization complete'); // Emit initialization complete event this.eventBus.emit(EventTypes.CALENDAR_INITIALIZED, { currentDate: this.currentDate, currentView: this.currentView }); } catch (error) { console.error('❌ CalendarManager initialization failed:', error); throw error; } } /** * Skift calendar view (dag/uge/måned) */ public setView(view: CalendarView): void { if (this.currentView === view) { return; } const previousView = this.currentView; this.currentView = view; console.log(`Changing view from ${previousView} to ${view}`); // Emit view change event this.eventBus.emit(EventTypes.VIEW_CHANGED, { previousView, currentView: view, date: this.currentDate }); // Grid re-rendering will trigger event rendering automatically via GRID_RENDERED event } /** * Sæt aktuel dato */ public setCurrentDate(date: Date): void { const previousDate = this.currentDate; this.currentDate = new Date(date); console.log(`Changing date from ${previousDate.toISOString()} to ${date.toISOString()}`); // Emit date change event this.eventBus.emit(EventTypes.DATE_CHANGED, { previousDate, currentDate: this.currentDate, view: this.currentView }); // Grid update for new date will trigger event rendering automatically via GRID_RENDERED event } /** * Naviger til i dag */ public goToToday(): void { this.setCurrentDate(new Date()); } /** * Naviger til næste periode (dag/uge/måned afhængig af view) */ public goToNext(): void { const nextDate = this.calculateNextDate(); this.setCurrentDate(nextDate); } /** * Naviger til forrige periode (dag/uge/måned afhængig af view) */ public goToPrevious(): void { const previousDate = this.calculatePreviousDate(); this.setCurrentDate(previousDate); } /** * Hent aktuel view */ public getCurrentView(): CalendarView { return this.currentView; } /** * Hent aktuel dato */ public getCurrentDate(): Date { return new Date(this.currentDate); } /** * Hent calendar konfiguration */ public getConfig(): CalendarConfig { return this.config; } /** * Check om calendar er initialiseret */ public isCalendarInitialized(): boolean { return this.isInitialized; } /** * Get initialization report for debugging */ public getInitializationReport(): any { return { isInitialized: this.isInitialized, currentView: this.currentView, currentDate: this.currentDate, initializationTime: 'N/A - simple initialization' }; } /** * Genindlæs calendar data */ public refresh(): void { console.log('Refreshing calendar...'); this.eventBus.emit(EventTypes.CALENDAR_REFRESH_REQUESTED, { view: this.currentView, date: this.currentDate }); } /** * Ryd calendar og nulstil til standard tilstand */ public reset(): void { console.log('Resetting calendar...'); this.currentView = 'week'; this.currentDate = new Date(); this.eventBus.emit(EventTypes.CALENDAR_RESET, { view: this.currentView, date: this.currentDate }); } /** * Setup event listeners for at håndtere events fra andre managers */ private setupEventListeners(): void { // Lyt efter navigation events this.eventBus.on(EventTypes.NAVIGATE_TO_DATE, (event) => { const customEvent = event as CustomEvent; const { date } = customEvent.detail; this.setCurrentDate(new Date(date)); }); // Lyt efter view change requests this.eventBus.on(EventTypes.VIEW_CHANGE_REQUESTED, (event) => { const customEvent = event as CustomEvent; const { view } = customEvent.detail; this.setView(view); }); // Lyt efter today navigation this.eventBus.on(EventTypes.NAVIGATE_TO_TODAY, () => { this.goToToday(); }); // Lyt efter next/previous navigation this.eventBus.on(EventTypes.NAVIGATE_NEXT, () => { this.goToNext(); }); this.eventBus.on(EventTypes.NAVIGATE_PREVIOUS, () => { this.goToPrevious(); }); // Lyt efter refresh requests this.eventBus.on(EventTypes.REFRESH_REQUESTED, () => { this.refresh(); }); // Lyt efter reset requests this.eventBus.on(EventTypes.RESET_REQUESTED, () => { this.reset(); }); } /** * Beregn næste dato baseret på aktuel view */ private calculateNextDate(): Date { const nextDate = new Date(this.currentDate); switch (this.currentView) { case 'day': nextDate.setDate(nextDate.getDate() + 1); break; case 'week': nextDate.setDate(nextDate.getDate() + 7); break; case 'month': nextDate.setMonth(nextDate.getMonth() + 1); break; } return nextDate; } /** * Beregn forrige dato baseret på aktuel view */ private calculatePreviousDate(): Date { const previousDate = new Date(this.currentDate); switch (this.currentView) { case 'day': previousDate.setDate(previousDate.getDate() - 1); break; case 'week': previousDate.setDate(previousDate.getDate() - 7); break; case 'month': previousDate.setMonth(previousDate.getMonth() - 1); break; } return previousDate; } /** * Calculate the current period based on view and date */ private calculateCurrentPeriod(): { start: string; end: string } { const current = new Date(this.currentDate); switch (this.currentView) { case 'day': const dayStart = new Date(current); dayStart.setHours(0, 0, 0, 0); const dayEnd = new Date(current); dayEnd.setHours(23, 59, 59, 999); return { start: dayStart.toISOString(), end: dayEnd.toISOString() }; case 'week': // Find start of week (Monday) const weekStart = new Date(current); const dayOfWeek = weekStart.getDay(); const daysToMonday = dayOfWeek === 0 ? 6 : dayOfWeek - 1; // Sunday = 0, so 6 days back to Monday weekStart.setDate(weekStart.getDate() - daysToMonday); weekStart.setHours(0, 0, 0, 0); // Find end of week (Sunday) const weekEnd = new Date(weekStart); weekEnd.setDate(weekEnd.getDate() + 6); weekEnd.setHours(23, 59, 59, 999); return { start: weekStart.toISOString(), end: weekEnd.toISOString() }; case 'month': const monthStart = new Date(current.getFullYear(), current.getMonth(), 1); const monthEnd = new Date(current.getFullYear(), current.getMonth() + 1, 0, 23, 59, 59, 999); return { start: monthStart.toISOString(), end: monthEnd.toISOString() }; default: // Fallback to week view const fallbackStart = new Date(current); fallbackStart.setDate(fallbackStart.getDate() - 3); fallbackStart.setHours(0, 0, 0, 0); const fallbackEnd = new Date(current); fallbackEnd.setDate(fallbackEnd.getDate() + 3); fallbackEnd.setHours(23, 59, 59, 999); return { start: fallbackStart.toISOString(), end: fallbackEnd.toISOString() }; } } }