/* Statistics Integration */ // This file extends the existing functionality without modifying original files (function() { let statsButtonAdded = false; let globalStatsButtonAdded = false; function addStatsButton() { if (statsButtonAdded) return; console.log('Attempting to add stats button...'); // Find the control groups const controlGroups = document.querySelectorAll('.control-group'); console.log('Found control groups:', controlGroups.length); if (controlGroups.length >= 2) { const downloadControlGroup = controlGroups[1]; // Second control group with download buttons const statsButton = document.createElement('button'); statsButton.id = 'showStats'; statsButton.className = 'btn-secondary'; statsButton.innerHTML = '📊 Statistics'; statsButton.addEventListener('click', () => { console.log('Stats button clicked'); // Use the new local chat analyzer if (window.localChatAnalyzer) { window.localChatAnalyzer.analyzeCurrentChat(); } else { // Fallback to original method console.log('window.chatStats available:', !!window.chatStats); if (window.chatStats) { console.log('Current data available:', !!window.chatStats.currentData); if (window.chatStats.currentData) { window.chatStats.showStats(); } else { console.log('No statistics data available yet, triggering analysis...'); triggerStatsAnalysis(); setTimeout(() => { if (window.chatStats.currentData) { window.chatStats.showStats(); } else { alert('No chat data available for statistics'); } }, 500); } } else { console.error('chatStats module not loaded'); alert('Statistics module not loaded'); } } }); // Insert before the download map button or at the end const downloadMapButton = document.getElementById('downloadMap'); if (downloadMapButton) { downloadControlGroup.insertBefore(statsButton, downloadMapButton); } else { downloadControlGroup.appendChild(statsButton); } statsButtonAdded = true; console.log('Stats button added successfully'); } else { console.log('Control groups not found yet'); } } function addGlobalStatsButton() { if (globalStatsButtonAdded) return; console.log('Adding global stats button...'); // Add button to header area const header = document.querySelector('header'); if (header) { const globalStatsButton = document.createElement('button'); globalStatsButton.id = 'globalStatsButton'; globalStatsButton.className = 'btn-primary global-stats-btn'; globalStatsButton.innerHTML = '📊 Global Chat Statistics'; globalStatsButton.style.cssText = ` position: fixed; top: 20px; right: 20px; z-index: 1000; padding: 12px 20px; background: linear-gradient(135deg, #007acc, #40a9ff); color: white; border: none; border-radius: 8px; font-weight: 600; cursor: pointer; box-shadow: 0 4px 12px rgba(0, 122, 204, 0.3); transition: all 0.3s ease; font-size: 14px; `; globalStatsButton.addEventListener('mouseenter', () => { globalStatsButton.style.transform = 'translateY(-2px)'; globalStatsButton.style.boxShadow = '0 6px 16px rgba(0, 122, 204, 0.4)'; }); globalStatsButton.addEventListener('mouseleave', () => { globalStatsButton.style.transform = 'translateY(0)'; globalStatsButton.style.boxShadow = '0 4px 12px rgba(0, 122, 204, 0.3)'; }); globalStatsButton.addEventListener('click', () => { console.log('Global stats button clicked'); showGlobalStatistics(); }); document.body.appendChild(globalStatsButton); globalStatsButtonAdded = true; console.log('Global stats button added successfully'); } } async function showGlobalStatistics() { console.log('Loading global statistics...'); try { // Create modal const modal = createGlobalStatsModal(); document.body.appendChild(modal); // Load chat index const response = await fetch('chat-logs/chat-index.json'); const chatIndex = await response.json(); // Calculate global stats const globalStats = calculateGlobalStats(chatIndex); // Display stats displayGlobalStats(globalStats, chatIndex); // Show modal modal.style.display = 'flex'; } catch (error) { console.error('Error loading global statistics:', error); alert('Error loading global statistics: ' + error.message); } } function createGlobalStatsModal() { const modal = document.createElement('div'); modal.id = 'globalStatsModal'; modal.style.cssText = ` display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.8); z-index: 2000; align-items: center; justify-content: center; `; modal.innerHTML = `

📊 Global Chat Statistics

📊
Loading global statistics...
`; // Close button modal.addEventListener('click', (e) => { if (e.target === modal) { modal.remove(); } }); setTimeout(() => { const closeBtn = modal.querySelector('#closeGlobalStats'); if (closeBtn) { closeBtn.addEventListener('click', () => modal.remove()); } }, 100); return modal; } function calculateGlobalStats(chatIndex) { const stats = { totalChats: chatIndex.chats.length, totalCategories: Object.keys(chatIndex.categories).length, categories: {}, dateRange: { earliest: null, latest: null }, totalEstimatedMessages: 0, averageMessagesPerChat: 0 }; // Calculate category stats Object.keys(chatIndex.categories).forEach(categoryKey => { const categoryInfo = chatIndex.categories[categoryKey]; const categoryChats = chatIndex.chats.filter(chat => chat.category === categoryKey); stats.categories[categoryKey] = { name: categoryInfo.name, color: categoryInfo.color, chatCount: categoryChats.length, percentage: Math.round((categoryChats.length / stats.totalChats) * 100), estimatedMessages: categoryChats.reduce((sum, chat) => sum + (chat.messages || 0), 0) }; }); // Calculate date range and messages chatIndex.chats.forEach(chat => { const chatDate = new Date(chat.date); if (!stats.dateRange.earliest || chatDate < stats.dateRange.earliest) { stats.dateRange.earliest = chatDate; } if (!stats.dateRange.latest || chatDate > stats.dateRange.latest) { stats.dateRange.latest = chatDate; } stats.totalEstimatedMessages += chat.messages || 0; }); stats.averageMessagesPerChat = Math.round(stats.totalEstimatedMessages / stats.totalChats); return stats; } function displayGlobalStats(stats, chatIndex) { const body = document.getElementById('globalStatsBody'); if (!body) return; const categoriesArray = Object.entries(stats.categories) .sort((a, b) => b[1].chatCount - a[1].chatCount); body.innerHTML = `

📈 Overview

Total Chats: ${stats.totalChats.toLocaleString()}
Categories: ${stats.totalCategories}
Est. Messages: ${stats.totalEstimatedMessages.toLocaleString()}
Avg/Chat: ${stats.averageMessagesPerChat}

📅 Timeline

First Chat: ${stats.dateRange.earliest?.toLocaleDateString() || 'N/A'}
Latest Chat: ${stats.dateRange.latest?.toLocaleDateString() || 'N/A'}
Time Span: ${calculateTimeSpan(stats.dateRange)}

📊 Category Breakdown

${categoriesArray.map(([key, category]) => `
${category.name}
${category.chatCount} (${category.percentage}%)
`).join('')}
💡 Tip: Click on individual chat logs to see detailed statistics for that session
`; } function calculateTimeSpan(dateRange) { if (!dateRange.earliest || !dateRange.latest) return 'N/A'; const diffTime = Math.abs(dateRange.latest - dateRange.earliest); const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); if (diffDays < 30) { return `${diffDays} days`; } else if (diffDays < 365) { const months = Math.round(diffDays / 30); return `${months} months`; } else { const years = Math.round(diffDays / 365); return `${years} years`; } } function triggerStatsAnalysis() { if (!window.chatStats) { console.log('chatStats not available yet'); return; } // Try to get messages from the current chat viewer instance if (window.chatViewer && window.chatViewer.currentMessages) { console.log('Using chatViewer.currentMessages:', window.chatViewer.currentMessages.length); window.chatStats.analyzeChat(window.chatViewer.currentMessages); return; } // Fallback: Parse messages from DOM const chatMessages = document.querySelectorAll('.message'); console.log('Found DOM messages:', chatMessages.length); if (chatMessages.length > 0) { const messages = Array.from(chatMessages).map(msg => { const timestamp = msg.querySelector('.timestamp')?.textContent || ''; const roleElement = msg.querySelector('.role-badge'); const role = roleElement ? roleElement.textContent.toLowerCase() : 'member'; const playerElement = msg.querySelector('.player-name'); const messageElement = msg.querySelector('.message-text'); if (playerElement && messageElement) { return { type: 'chat', timestamp: timestamp.replace(/[\[\]]/g, ''), role: role, player: playerElement.textContent, message: messageElement.textContent }; } else if (msg.classList.contains('join-leave')) { const text = msg.textContent; return { type: text.includes('joined') ? 'join' : 'leave', timestamp: timestamp.replace(/[\[\]]/g, ''), player: text.match(/(\w+) (joined|left)/)?.[1] || '', message: text }; } return null; }).filter(msg => msg !== null); if (messages.length > 0) { console.log('Analyzing', messages.length, 'messages'); window.chatStats.analyzeChat(messages); } } } // Wait for the page to load document.addEventListener('DOMContentLoaded', function() { console.log('DOM loaded, initializing statistics...'); // Add statistics CSS const link = document.createElement('link'); link.rel = 'stylesheet'; link.href = 'statistics.css'; document.head.appendChild(link); // Load local chat analyzer const analyzerScript = document.createElement('script'); analyzerScript.src = 'local-chat-analyzer.js'; analyzerScript.onload = () => { console.log('Local chat analyzer loaded'); }; document.head.appendChild(analyzerScript); // Try to add button immediately setTimeout(addStatsButton, 100); // Add global stats button (always available) setTimeout(addGlobalStatsButton, 200); // Monitor for controls becoming visible const observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { // Check if controls became visible if (mutation.target.id === 'controls' && mutation.attributeName === 'style') { const controls = document.getElementById('controls'); if (controls && controls.style.display !== 'none') { console.log('Controls became visible'); setTimeout(addStatsButton, 100); } } // Check if chat content changed if (mutation.target.id === 'chatContent' && mutation.type === 'childList') { console.log('Chat content changed'); setTimeout(() => { addStatsButton(); triggerStatsAnalysis(); }, 200); } }); }); // Start observing const controls = document.getElementById('controls'); const chatContainer = document.getElementById('chatContent'); if (controls) { observer.observe(controls, { attributes: true, attributeFilter: ['style'] }); } if (chatContainer) { observer.observe(chatContainer, { childList: true, subtree: true }); } // Also check periodically for the first few seconds let checkCount = 0; const intervalCheck = setInterval(() => { checkCount++; addStatsButton(); // Check if there's already chat content const messages = document.querySelectorAll('.message'); if (messages.length > 0) { triggerStatsAnalysis(); } if (checkCount >= 10 || statsButtonAdded) { clearInterval(intervalCheck); } }, 1000); // Ensure chatStats is available if (!window.chatStats) { console.log('Waiting for chatStats to be available...'); const waitForStats = setInterval(() => { if (window.chatStats) { console.log('chatStats is now available'); clearInterval(waitForStats); // Trigger analysis if there are already messages const messages = document.querySelectorAll('.message'); if (messages.length > 0) { console.log('Found existing messages, triggering analysis'); triggerStatsAnalysis(); } } }, 100); } }); })();