export class UIManager { constructor(routeManager) { this.routeManager = routeManager; this.gameManager = null; this.isSimulationReady = false; // -- MAIN MENU ELEMENTS -- this.elMainMenu = document.getElementById('main-menu'); this.btnStart = document.getElementById('btn-start'); this.btnMenuToggle = document.getElementById('menu-toggle'); this.selectMap = document.getElementById('map-selector'); // -- GAME UI ELEMENTS -- this.panelMain = document.getElementById('ui-main-menu'); this.panelDraft = document.getElementById('ui-draft-menu'); this.elContainer = document.getElementById('ui-container'); // Stats this.elCurrentLength = document.getElementById('current-length'); this.elCurrentCost = document.getElementById('current-cost'); this.elCurrentRiders = document.getElementById('current-riders'); this.elBudget = document.getElementById('val-budget'); this.elDay = document.getElementById('val-day'); this.elTotalRiders = document.getElementById('val-riders'); this.elApproval = document.getElementById('val-approval'); this.elIncomeFloat = document.getElementById('income-float'); this.elRouteList = document.getElementById('route-list'); // Buttons this.btnCreate = document.getElementById('btn-create-route'); this.btnSave = document.getElementById('btn-save'); this.btnDiscard = document.getElementById('btn-discard'); this.btnToggle = document.getElementById('ui-toggle'); // Save/Load this.btnSaveGame = document.getElementById('btn-save-game'); this.btnLoadGame = document.getElementById('btn-load-game'); this.inputLoadGame = document.getElementById('file-load-game'); // View Mode this.selectViewMode = document.getElementById('view-mode'); this.onViewModeChanged = null; this.initListeners(); this.initSafetyChecks(); } initListeners() { // --- MAIN MENU INTERACTIONS --- // 1. Start Button this.btnStart.addEventListener('click', () => { if (this.isSimulationReady) { this.elMainMenu.classList.add('hidden'); } }); // 2. Map Selector this.selectMap.addEventListener('change', (e) => { if (confirm("Switching maps will lose unsaved progress. Continue?")) { // Logic to reload map would go here. // For now, since we only have one map, we just reload the page to be safe window.location.reload(); } else { // Revert selection if canceled (conceptually simple, hard to do without tracking previous val) e.target.value = "madison_wi"; } }); // 3. Menu Toggle (Top Right) this.btnMenuToggle.addEventListener('click', () => { // Toggle menu visibility if (this.elMainMenu.classList.contains('hidden')) { this.elMainMenu.classList.remove('hidden'); } else { this.elMainMenu.classList.add('hidden'); } }); // --- GAME UI INTERACTIONS --- this.btnCreate.addEventListener('click', () => { this.enterDraftMode(); }); this.btnSave.addEventListener('click', () => { const success = this.routeManager.saveCurrentRoute(); if (success) { this.renderRouteList(); this.exitDraftMode(); } }); this.btnDiscard.addEventListener('click', () => { this.routeManager.clearCurrentRoute(); this.exitDraftMode(); }); this.btnToggle.addEventListener('click', () => { this.elContainer.classList.toggle('hidden'); }); this.selectViewMode.addEventListener('change', (e) => { if (this.onViewModeChanged) { this.onViewModeChanged(e.target.value); } }); // Save / Load System this.btnSaveGame.addEventListener('click', () => { if (this.routeManager.gameManager) { this.routeManager.gameManager.saveGame(); } }); this.btnLoadGame.addEventListener('click', () => { this.inputLoadGame.click(); }); this.inputLoadGame.addEventListener('change', (e) => { const file = e.target.files[0]; if (!file) return; const reader = new FileReader(); reader.onload = (evt) => { if (this.routeManager.gameManager) { this.routeManager.gameManager.loadGame(evt.target.result); this.renderRouteList(); // Auto close menu on load this.elMainMenu.classList.add('hidden'); } }; reader.readAsText(file); e.target.value = ''; }); } initSafetyChecks() { // Prompt before closing tab window.addEventListener('beforeunload', (e) => { // Modern browsers don't show custom text, but this triggers the generic "Are you sure?" e.preventDefault(); e.returnValue = ''; }); } // Called by Main.js when Promise.all is finished setLoadingComplete() { this.isSimulationReady = true; this.btnStart.disabled = false; this.btnStart.textContent = "Enter Simulation"; this.btnStart.classList.add('ready'); } enterDraftMode() { this.panelMain.style.display = 'none'; this.panelDraft.style.display = 'block'; this.routeManager.startDrafting(); } exitDraftMode() { this.panelMain.style.display = 'block'; this.panelDraft.style.display = 'none'; this.routeManager.stopDrafting(); } updateGameStats(stats) { this.elBudget.textContent = "$" + stats.budget.toLocaleString(); this.elDay.textContent = stats.day; this.elTotalRiders.textContent = stats.totalRiders.toLocaleString(); this.elApproval.textContent = stats.approval + "%"; if (stats.approval > 75) this.elApproval.style.color = "#10B981"; else if (stats.approval < 40) this.elApproval.style.color = "#EF4444"; else this.elApproval.style.color = "#D97706"; } showIncomeFeedback(amount) { this.elIncomeFloat.textContent = "+ $" + amount.toLocaleString(); this.elIncomeFloat.style.opacity = 1; this.elIncomeFloat.style.top = "40px"; setTimeout(() => { this.elIncomeFloat.style.opacity = 0; this.elIncomeFloat.style.top = "60px"; }, 2000); } updateDraftStats(stats) { let lenText = stats.length > 1000 ? (stats.length / 1000).toFixed(2) + " km" : Math.round(stats.length) + " m"; this.elCurrentLength.textContent = lenText; this.elCurrentCost.textContent = "$" + stats.cost.toLocaleString(); this.elCurrentRiders.textContent = stats.ridership.toLocaleString() + " / day"; } renderRouteList() { this.elRouteList.innerHTML = ''; const routes = this.routeManager.getSavedRoutes(); if (routes.length === 0) { this.elRouteList.innerHTML = '