/* 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 = `
📊
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);
}
});
})();