/** * Main JavaScript Application for Markov Economics * * Provides utility functions and global application behavior */ // Global application state window.MarkovEconomics = { socket: null, currentSimulationId: null, isConnected: false, // Configuration config: { maxRetries: 3, retryDelay: 1000, updateInterval: 100 } }; /** * Initialize Socket.IO connection */ function initializeSocket() { if (typeof io !== 'undefined') { window.MarkovEconomics.socket = io(); window.MarkovEconomics.socket.on('connect', function() { console.log('Connected to server'); window.MarkovEconomics.isConnected = true; updateConnectionStatus(true); }); window.MarkovEconomics.socket.on('disconnect', function() { console.log('Disconnected from server'); window.MarkovEconomics.isConnected = false; updateConnectionStatus(false); }); window.MarkovEconomics.socket.on('connect_error', function(error) { console.error('Connection error:', error); updateConnectionStatus(false); }); } } /** * Update connection status indicator */ function updateConnectionStatus(connected) { // You can add a connection status indicator here if needed if (connected) { console.log('✅ Real-time connection established'); } else { console.log('❌ Real-time connection lost'); } } /** * Format numbers for display */ function formatNumber(num, decimals = 2) { if (num === null || num === undefined || isNaN(num)) { return '0'; } if (Math.abs(num) >= 1e9) { return (num / 1e9).toFixed(decimals) + 'B'; } else if (Math.abs(num) >= 1e6) { return (num / 1e6).toFixed(decimals) + 'M'; } else if (Math.abs(num) >= 1e3) { return (num / 1e3).toFixed(decimals) + 'K'; } else { return num.toLocaleString(undefined, { minimumFractionDigits: decimals, maximumFractionDigits: decimals }); } } /** * Format currency values */ function formatCurrency(amount, decimals = 0) { if (amount === null || amount === undefined || isNaN(amount)) { return '$0'; } return '$' + formatNumber(amount, decimals); } /** * Format percentage values */ function formatPercentage(value, decimals = 1) { if (value === null || value === undefined || isNaN(value)) { return '0%'; } return (value * 100).toFixed(decimals) + '%'; } /** * Show notification message */ function showNotification(message, type = 'info', duration = 3000) { // Create notification element const notification = document.createElement('div'); notification.className = `alert alert-${type} alert-dismissible fade show position-fixed`; notification.style.cssText = ` top: 20px; right: 20px; z-index: 9999; min-width: 300px; box-shadow: 0 4px 12px rgba(0,0,0,0.15); `; notification.innerHTML = ` ${message} `; document.body.appendChild(notification); // Auto-remove after duration setTimeout(() => { if (notification.parentNode) { notification.remove(); } }, duration); return notification; } /** * Show loading spinner */ function showLoading(element, text = 'Loading...') { if (typeof element === 'string') { element = document.getElementById(element); } if (element) { element.innerHTML = `