/**
* GLOBAL FALLBACK - muss VOR allem anderen geladen werden!
* Falls diese Datei nicht geladen ist, brauchen wir einen Dummy DebugConfig
*/
if (typeof window !== 'undefined' && !window.DebugConfig) {
window.DebugConfig = {
log: function(domain, level, ...args) {
// Silent fallback - tut nichts wenn debug-config.js nicht geladen ist
}
};
window.DEBUG_DOMAINS = {};
window.DEBUG_CONFIG = {};
}
/**
* @fileoverview Zentrale Debug-Konfiguration für WolfsWorld
*
* Zweck: Hierarchisches, strukturiertes Logging-System für alle Module des Projekts.
* Erlaubt gezieltes Debugging von Spiellogik, KI-Algorithmen und Visualisierungen
* ohne Code-Änderungen - nur durch Config-Flags an/aus.
*
* ============================================================================
* LOGGING KONVENTIONEN (MUSS eingehalten werden!)
* ============================================================================
*
* 1) KEIN direktes console.log/console.warn/console.error in Feature-Code!
* ❌ FALSCH: console.log('Debug message:', obj);
* ✅ RICHTIG: DebugConfig.log(DEBUG_DOMAINS.MY_DOMAIN, 'debug', 'Message:', obj);
*
* 2) Jedes Log MUSS einer Domain zugeordnet sein
* → Ermöglicht gezieltes Debugging (nur MY_DOMAIN, nicht alles)
* → Siehe DEBUG_DOMAINS unten für verfügbare Domains
* → Nicht sicher? Nutz ähnliche oder parent-Domain
*
* 3) Strukturierte Payloads nutzen (Objekte, keine String-Konkatenation)
* ❌ console.log('Agent: ' + name + ', Depth: ' + depth);
* ✅ DebugConfig.log(domain, 'debug', 'Agent info:', { name, depth });
* Vorteil: Browser DevTools können Objects expandieren, nicht nur unformatiert Text
*
* 4) Korrekte Levels verwenden:
* - 'debug': Normale Operationen, State-Changes, Flow-Info
* → Nur sichtbar wenn Domain-Flag = true
* - 'warn': Unerwartetes aber recoverable (z.B. invalid input, fallback)
* → IMMER sichtbar wenn DEBUG_CRITICAL = true (auch ohne Domain)
* - 'error': Fehler der abgefangen werden (~errors, wie null-checks)
* → IMMER sichtbar wenn DEBUG_CRITICAL = true
* - 'critical': Kritische Systemfehler (sollte nicht passieren!)
* → IMMER sichtbar wenn DEBUG_CRITICAL = true
*
* 5) Globale Overrides nutzen für schnelles Debugging:
* DEBUG_ALL = true → Alle Logs sichtbar (maximale Verbosität)
* DEBUG_CRITICAL = true → Nur Fehler/Warnings/Critical (default)
* DEBUG_GAMES = true → Alle Spiele (aber nicht AI/VIZ)
*
* ============================================================================
* QUICK START - Die häufigsten Use Cases
* ============================================================================
*
* // Use Case 1: Nur TTT debuggen
* DEBUG_CONFIG.DEBUG_GAMES_TICTACTOE = true;
* // Zeigt alle TTT Logs (regular, 3D, Ultimate)
* // DebugConfig.log(DEBUG_DOMAINS.GAMES_TTT_REGULAR, 'debug', ...) sichtbar
*
* // Use Case 2: Nur MinimaxAgent Fehler sehen
* DEBUG_CONFIG.DEBUG_CRITICAL = true; // ← Default, error/warn/critical immer
* // Zeigt alle Errors/Warnings/Critical, unabhängig von Domains
*
* // Use Case 3: Komplettes Debugging (alles sehen)
* DEBUG_CONFIG.DEBUG_ALL = true;
* // Zeigt ALLES - aber sehr verbose!
*
* // Use Case 4: AI Heuristiken debuggen
* DEBUG_CONFIG.DEBUG_AI_HEURISTICS_TTT = true;
* // Zeigt nur TTT Heuristic Logs
*
* // Use Case 5: Logs in Datei speichern
* DEBUG_CONFIG.OUTPUT_FILE = true;
* // Logs werden in /log/debug-DATUM.log geschrieben (zusätzlich zu console)
*
* ============================================================================
* HIERARCHIE & LOOKUP LOGIK
* ============================================================================
*
* Domains sind hierarchisch strukturiert:
*
* GAMES
* ├─ GAMES_TICTACTOE
* │ ├─ GAMES_TTT_REGULAR
* │ ├─ GAMES_TTT_3D
* │ └─ GAMES_TTT_ULTIMATE
* ├─ GAMES_ROTATEBOX
* ├─ GAMES_NIM
* └─ GAMES_CONNECT4
*
* AI
* ├─ AI_MINIMAX
* ├─ AI_ABPRUNING
* ├─ AI_HEURISTICS
* │ ├─ AI_HEURISTICS_TTT
* │ └─ AI_HEURISTICS_CONNECT4
* ├─ AI_RULES
* │ ├─ AI_RULES_TTT
* │ └─ AI_RULES_CONNECT4
* ├─ AI_AGENTS
* │ ├─ AI_AGENT_MINIMAX
* │ ├─ AI_AGENT_RULES
* │ └─ AI_AGENT_RANDOM
* └─ AI_SEARCH_ALGORITHMS
*
* Lookup funktioniert so:
* 1. DebugConfig.log(DEBUG_DOMAINS.GAMES_TTT_REGULAR, 'debug', msg) aufgerufen
* 2. debugShouldLog() prüft: DEBUG_GAMES_TTT_REGULAR? → true? → sichtbar
* 3. Wenn nein, prüft parent: DEBUG_GAMES? → true? → sichtbar
* 4. Wenn nein, alle false → unsichtbar
*
* Vorteil: DEBUG_GAMES=true zeigt ALLE Spiele, aber nicht AI/VIZ
*
* ============================================================================
* FLAG NAMING CONVENTION
* ============================================================================
*
* DEBUG_<MODULNAME>: Parent Flag (z.B. DEBUG_GAMES)
* DEBUG_<MODULE>_<SUB>: Sub-Module (z.B. DEBUG_GAMES_TTT_REGULAR)
* DEBUG_<>_<GAME>: Spiel-Spezifisch (z.B. DEBUG_HEURISTICS_TTT)
* DEBUG_CRITICAL: Globales Critical Level Flag
* DEBUG_ALL: Globales Override Flag
* OUTPUT_FILE: Logs in Datei schreiben
*
* ============================================================================
* DEBUGGING TIP: OUTPUT_FILE Feature
* ============================================================================
*
* Wenn OUTPUT_FILE = true:
* - Alle Logs werden AUCH in /log/debug-DATUM-ZEIT.log geschrieben
* - Format: [LEVEL] [DOMAIN] [TIMESTAMP] Nachricht
* - Perfekt für Performance-Profiling oder Post-Session Analyse
* - /log Verzeichnis ist in .gitignore (nicht committet)
*
* Beispiel .log Datei:
* [debug] [GAMES_TTT_REGULAR] 15:32:04.123 Move executed: {"move":[0,1],"player":1}
* [warn] [AI_MINIMAX] 15:32:05.456 Depth limit exceeded
* [error] [CORE_GAME_CONTROLLER] 15:32:06.789 Canvas not found
*
* ============================================================================
* WEITERE RESSOURCEN
* ============================================================================
*
* Vollständige Dokumentation:
* - STRUKTUR_AUDIT_ALLE_JS_DATEIEN.md - Alle 65 JS Dateien, ihre Domains
* - CONSOLE_LOG_STANDARDISIERUNG.md - Konvention & Rationale
* - BESTANDSERFASSUNG_CONSOLE_LOGS.md - Vorhandene Logs
* - PHASE2_MIGRATIONS_CHECKLISTE.md - Wie man Code migriert
* - INDEX_CONSOLE_LOG_STANDARDISIERUNG.md - Einstiegspunkt für alles
*
* @typedef {'debug'|'warn'|'error'|'critical'} DebugLevel
* @author Alexander Wolf
*/
const DEBUG_CONFIG = {
// ========== GLOBAL CONTROLS ==========
DEBUG_ALL: false, // Überschreibt alles (max Verbosität)
DEBUG_CRITICAL: true, // Aktiv: warn/error/critical auf allen Domains
OUTPUT_FILE: false, // Logs auch in /log/debug-DATUM.log schreiben
// ========== GAMES MODUL ==========
DEBUG_GAMES: false, // Alle Spiellogiken
DEBUG_GAMES_TICTACTOE: false, // TTT allgemein
DEBUG_GAMES_TTT_REGULAR: false, // 3x3 TTT
DEBUG_GAMES_TTT_3D: false, // 4x4x4 TTT
DEBUG_GAMES_TTT_ULTIMATE: false, // Ultimate TTT
DEBUG_GAMES_ROTATEBOX: false, // RotateBox Spiel
DEBUG_GAMES_NIM: false, // Nim Spiel
DEBUG_GAMES_CONNECT4: false, // Connect 4
DEBUG_GAMES_KNIGHTS_TOUR: false, // Knight's Tour
// ========== AI MODUL ==========
DEBUG_AI: false, // Alle KI-Algorithmen
DEBUG_AI_MINIMAX: false, // Minimax Kern-Engine
DEBUG_AI_ABPRUNING: true, // Alpha-Beta Pruning Detail
// Heuristiken (CRITICAL!)
DEBUG_AI_HEURISTICS: false, // Alle Heuristiken-Module
DEBUG_AI_HEURISTICS_TTT: false, // TTT-spezifische Heuristiken
DEBUG_AI_HEURISTICS_CONNECT4: false,// Connect4-spez Heuristiken
DEBUG_AI_HEURISTICS_ADAPTER: false, // Heuristik-Regel-Adapter
// Rules & Strategy (CRITICAL!)
DEBUG_AI_RULES: false, // Rule Engine Kern
DEBUG_AI_RULES_TTT: false, // TTT Strategy Rules
DEBUG_AI_RULES_CONNECT4: false, // Connect4 Strategy Rules
// Agenten
DEBUG_AI_AGENTS: false, // Agent Management
DEBUG_AI_AGENT_MINIMAX: false, // MinimaxAgent spezifisch
DEBUG_AI_AGENT_RULES: false, // RuleBasedAgent spezifisch
DEBUG_AI_AGENT_RANDOM: false, // RandomAgent spezifisch
// Such-Algorithmen
DEBUG_AI_SEARCH_ALGORITHMS: false, // Verschiedene Suchalgorithmiken
DEBUG_AI_ALGORITHM_RUNNER: false, // Algorithm Orchestration
// ========== VIZ MODUL ==========
DEBUG_VIZ: false, // Alle Visualisierungen
DEBUG_VIZ_TREE: false, // Tree-Viz allgemein
DEBUG_VIZ_TREE_ENGINE: false, // Tree-Engine Kern
DEBUG_VIZ_TREE_FEATURES: false, // Features-Engine
// Tree Adapter (Detail-Level)
DEBUG_VIZ_TREE_ADAPTER_BASE: false, // Base Adapter
DEBUG_VIZ_TREE_ADAPTER_DFS: false, // DFS Tree Adapter
DEBUG_VIZ_TREE_ADAPTER_BFS: false, // BFS Tree Adapter
DEBUG_VIZ_TREE_ADAPTER_MINIMAX: false, // Minimax Adapter
DEBUG_VIZ_TREE_ADAPTER_ALPHABETA: false,// Alpha-Beta Adapter
DEBUG_VIZ_TREE_ADAPTER_GENERIC: false, // Generic Tree Adapter (Diagramm-Modus)
// Spiel-spezifische Node-Renderer
DEBUG_VIZ_TREE_MINIMAX_NODES: false, // Minimax Node Rendering
DEBUG_VIZ_TREE_ROTATEBOX_NODES: false, // RotateBox Node Rendering
DEBUG_VIZ_TREE_KNIGHTS_NODES: false, // KnightsTour Node Rendering
// Specializers
DEBUG_VIZ_SPECIALIZERS_RULES: false, // Rules Visualizer
DEBUG_VIZ_SPECIALIZERS_FLOWCHART: false,// Flowchart Visualizer
// Shared
DEBUG_VIZ_BASE: false, // Base Visualizer shared
DEBUG_VIZ_SHARED_UTILS: false, // Shared VIZ Utilities
// ========== CORE MODUL ==========
DEBUG_CORE: false, // Zentrale Spielarchitektur
DEBUG_CORE_GAME_CONTROLLER: false, // BaseGameController
DEBUG_CORE_GAME_STATE: false, // GameState Template
DEBUG_CORE_GAME_ADAPTER: false, // GameAdapter
DEBUG_CORE_AGENT: false, // Base Agent Klasse
// IframeBridge Kommunikation
DEBUG_CORE_IFRAME_BRIDGE: false, // IframeBridge System (Host + Client)
DEBUG_CORE_IFRAME_BRIDGE_HOST: false, // IframeBridgeHost (Parent-Seite)
DEBUG_CORE_IFRAME_BRIDGE_CLIENT: false, // IframeBridgeClient (iframe-Seite)
// ========== LEARNING MODUL ==========
DEBUG_LEARNING: false, // Learning Path System
DEBUG_LEARNING_PATH: false, // Kurs Navigation & Fortschritt
// ========== UTILS MODUL ==========
DEBUG_UTILS: false, // Utilities & Tools
DEBUG_UTILS_BENCHMARK: false, // Performance Messungen
// ========== LEGACY DOMAINS (Backward Compatibility) ==========
// ⚠️ Diese sollten schrittweise durch neue Domains ersetzt werden
DEBUG_MINIMAX: false, // ⚠️ DEPRECATED: Nutze DEBUG_AI_MINIMAX stattdessen
DEBUG_ABPRUNING: true, // ⚠️ DEPRECATED: Nutze DEBUG_AI_ABPRUNING stattdessen
DEBUG_MINIMAX_VIZ_UI: true, // ⚠️ DEPRECATED: Nutze DEBUG_VIZ_TREE stattdessen
DEBUG_TTT_RENDERER: false, // ⚠️ DEPRECATED: Nutze DEBUG_GAMES_TTT_REGULAR stattdessen
};
const DEBUG_DOMAINS = {
// ========== GAMES ==========
GAMES: 'GAMES',
GAMES_TICTACTOE: 'GAMES_TICTACTOE',
GAMES_TTT_REGULAR: 'GAMES_TTT_REGULAR',
GAMES_TTT_3D: 'GAMES_TTT_3D',
GAMES_TTT_ULTIMATE: 'GAMES_TTT_ULTIMATE',
GAMES_ROTATEBOX: 'GAMES_ROTATEBOX',
GAMES_NIM: 'GAMES_NIM',
GAMES_CONNECT4: 'GAMES_CONNECT4',
GAMES_KNIGHTS_TOUR: 'GAMES_KNIGHTS_TOUR',
// ========== AI ==========
AI: 'AI',
AI_MINIMAX: 'AI_MINIMAX',
AI_ABPRUNING: 'AI_ABPRUNING',
AI_HEURISTICS: 'AI_HEURISTICS',
AI_HEURISTICS_TTT: 'AI_HEURISTICS_TTT',
AI_HEURISTICS_CONNECT4: 'AI_HEURISTICS_CONNECT4',
AI_HEURISTICS_ADAPTER: 'AI_HEURISTICS_ADAPTER',
AI_RULES: 'AI_RULES',
AI_RULES_TTT: 'AI_RULES_TTT',
AI_RULES_CONNECT4: 'AI_RULES_CONNECT4',
AI_AGENTS: 'AI_AGENTS',
AI_AGENT_MINIMAX: 'AI_AGENT_MINIMAX',
AI_AGENT_RULES: 'AI_AGENT_RULES',
AI_AGENT_RANDOM: 'AI_AGENT_RANDOM',
AI_SEARCH_ALGORITHMS: 'AI_SEARCH_ALGORITHMS',
AI_ALGORITHM_RUNNER: 'AI_ALGORITHM_RUNNER',
// ========== VIZ ==========
VIZ: 'VIZ',
VIZ_TREE: 'VIZ_TREE',
VIZ_TREE_ENGINE: 'VIZ_TREE_ENGINE',
VIZ_TREE_FEATURES: 'VIZ_TREE_FEATURES',
VIZ_TREE_ADAPTER_BASE: 'VIZ_TREE_ADAPTER_BASE',
VIZ_TREE_ADAPTER_DFS: 'VIZ_TREE_ADAPTER_DFS',
VIZ_TREE_ADAPTER_BFS: 'VIZ_TREE_ADAPTER_BFS',
VIZ_TREE_ADAPTER_MINIMAX: 'VIZ_TREE_ADAPTER_MINIMAX',
VIZ_TREE_ADAPTER_ALPHABETA: 'VIZ_TREE_ADAPTER_ALPHABETA',
VIZ_TREE_ADAPTER_GENERIC: 'VIZ_TREE_ADAPTER_GENERIC',
VIZ_TREE_MINIMAX_NODES: 'VIZ_TREE_MINIMAX_NODES',
VIZ_TREE_ROTATEBOX_NODES: 'VIZ_TREE_ROTATEBOX_NODES',
VIZ_TREE_KNIGHTS_NODES: 'VIZ_TREE_KNIGHTS_NODES',
VIZ_SPECIALIZERS_RULES: 'VIZ_SPECIALIZERS_RULES',
VIZ_SPECIALIZERS_FLOWCHART: 'VIZ_SPECIALIZERS_FLOWCHART',
VIZ_BASE: 'VIZ_BASE',
VIZ_SHARED_UTILS: 'VIZ_SHARED_UTILS',
// ========== CORE ==========
CORE: 'CORE',
CORE_GAME_CONTROLLER: 'CORE_GAME_CONTROLLER',
CORE_GAME_STATE: 'CORE_GAME_STATE',
CORE_GAME_ADAPTER: 'CORE_GAME_ADAPTER',
CORE_AGENT: 'CORE_AGENT',
CORE_IFRAME_BRIDGE: 'CORE_IFRAME_BRIDGE',
CORE_IFRAME_BRIDGE_HOST: 'CORE_IFRAME_BRIDGE_HOST',
CORE_IFRAME_BRIDGE_CLIENT: 'CORE_IFRAME_BRIDGE_CLIENT',
// ========== LEARNING ==========
LEARNING: 'LEARNING',
LEARNING_PATH: 'LEARNING_PATH',
// ========== UTILS ==========
UTILS: 'UTILS',
UTILS_BENCHMARK: 'UTILS_BENCHMARK',
// ========== LEGACY DOMAINS (Backward Compatibility) ==========
MINIMAX: 'MINIMAX',
ABPRUNING: 'ABPRUNING',
MINIMAX_VIZ_UI: 'MINIMAX_VIZ_UI',
TTT_RENDERER: 'TTT_RENDERER',
};
/**
* Entscheidet, ob ein Logeintrag geschrieben werden soll.
* Hierarchisch: Global > Critical > Domain-spezifisch > Parent-Domain
*
* @param {string} domain - Domain aus DEBUG_DOMAINS
* @param {DebugLevel} [level='debug'] - Log-Level
* @returns {boolean}
*/
function debugShouldLog(domain, level = 'debug') {
// === GLOBAL OVERRIDES ===
if (DEBUG_CONFIG.DEBUG_ALL === true) return true;
// === CRITICAL LEVEL ===
// warn/error/critical sind IMMER sichtbar wenn DEBUG_CRITICAL = true
if (level === 'critical' || level === 'warn' || level === 'error') {
if (DEBUG_CONFIG.DEBUG_CRITICAL === true) return true;
}
// === DOMAIN-SPEZIFISCHE CHECKS (Hierarchisch) ===
// Strategy: Zuerst spezifisches Domain-Flag prüfen (z.B. DEBUG_AI_HEURISTICS_TTT)
// Dann parent-Domain (z.B. DEBUG_AI_HEURISTICS)
// Dann grand-parent (z.B. DEBUG_AI)
const config_key = `DEBUG_${domain}`;
if (DEBUG_CONFIG.hasOwnProperty(config_key) && DEBUG_CONFIG[config_key] === true) {
return true;
}
// GAMES Module Hierarchy
if (domain.startsWith('GAMES_')) {
if (domain === 'GAMES_TTT_REGULAR' || domain === 'GAMES_TTT_3D' || domain === 'GAMES_TTT_ULTIMATE') {
if (DEBUG_CONFIG.DEBUG_GAMES_TICTACTOE === true) return true;
}
if (DEBUG_CONFIG.DEBUG_GAMES === true) return true;
}
// AI Module Hierarchy (komplex wegen vieler Sub-Domains!)
if (domain.startsWith('AI_')) {
// AI_HEURISTICS Hierarchy
if (domain === 'AI_HEURISTICS_TTT' && DEBUG_CONFIG.DEBUG_AI_HEURISTICS === true) return true;
if (domain === 'AI_HEURISTICS_CONNECT4' && DEBUG_CONFIG.DEBUG_AI_HEURISTICS === true) return true;
if (domain === 'AI_HEURISTICS_ADAPTER' && DEBUG_CONFIG.DEBUG_AI_HEURISTICS === true) return true;
// AI_RULES Hierarchy
if (domain === 'AI_RULES_TTT' && DEBUG_CONFIG.DEBUG_AI_RULES === true) return true;
if (domain === 'AI_RULES_CONNECT4' && DEBUG_CONFIG.DEBUG_AI_RULES === true) return true;
// AI_AGENTS Hierarchy
if ((domain === 'AI_AGENT_MINIMAX' || domain === 'AI_AGENT_RULES' || domain === 'AI_AGENT_RANDOM') &&
DEBUG_CONFIG.DEBUG_AI_AGENTS === true) return true;
// AI_TREE_ADAPTERS Hierarchy
if ((domain === 'AI_TREE_ADAPTER_MINIMAX' || domain === 'AI_TREE_ADAPTER_ALPHABETA' || domain === 'AI_TREE_ADAPTER_BASE') &&
DEBUG_CONFIG.DEBUG_AI_SEARCH_ALGORITHMS === true) return true;
// Parent AI flag
if (DEBUG_CONFIG.DEBUG_AI === true) return true;
}
// VIZ Module Hierarchy
if (domain.startsWith('VIZ_')) {
// VIZ_TREE_ADAPTER Hierarchy
if (domain.includes('ADAPTER_') && DEBUG_CONFIG.DEBUG_VIZ_TREE === true) return true;
// VIZ_TREE_*_NODES Hierarchy
if ((domain === 'VIZ_TREE_MINIMAX_NODES' || domain === 'VIZ_TREE_ROTATEBOX_NODES' || domain === 'VIZ_TREE_KNIGHTS_NODES') &&
DEBUG_CONFIG.DEBUG_VIZ_TREE_ENGINE === true) return true;
// VIZ_SPECIALIZERS Hierarchy
if (domain.includes('SPECIALIZERS_') && DEBUG_CONFIG.DEBUG_VIZ === true) return true;
// VIZ parent flags
if (domain.includes('TREE_') && DEBUG_CONFIG.DEBUG_VIZ_TREE === true) return true;
if (DEBUG_CONFIG.DEBUG_VIZ === true) return true;
}
// CORE Module Hierarchy
if (domain.startsWith('CORE_')) {
// CORE_IFRAME_BRIDGE Hierarchy
if ((domain === 'CORE_IFRAME_BRIDGE_HOST' || domain === 'CORE_IFRAME_BRIDGE_CLIENT') &&
DEBUG_CONFIG.DEBUG_CORE_IFRAME_BRIDGE === true) return true;
if (DEBUG_CONFIG.DEBUG_CORE === true) return true;
}
// LEARNING Module Hierarchy
if (domain.startsWith('LEARNING_')) {
if (DEBUG_CONFIG.DEBUG_LEARNING === true) return true;
}
// UTILS Module Hierarchy
if (domain.startsWith('UTILS_')) {
if (DEBUG_CONFIG.DEBUG_UTILS === true) return true;
}
return false;
}
/**
* Schreibt einen Debug-Logeintrag gemäß globaler Debug-Konfiguration.
* Gibt in console aus UND optional in Datei (/log/debug-*.log wenn OUTPUT_FILE=true)
*
* @param {string} domain - Domain aus DEBUG_DOMAINS
* @param {DebugLevel} level - Log-Level ('debug', 'warn', 'error', 'critical')
* @param {...any} args - Log-Argumente (formatiert wie console.log)
*/
function debugLog(domain, level, ...args) {
if (!debugShouldLog(domain, level)) return;
// Format der Ausgabe: [LEVEL] [DOMAIN] [TIMESTAMP] Message
const timestamp = new Date().toLocaleTimeString('de-DE', { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit', fractionalSecondDigits: 3 });
const levelStr = level.toUpperCase().padEnd(7);
const domainStr = domain.padEnd(30);
const prefix = `[${levelStr}] [${domainStr}] ${timestamp}`;
// === CONSOLE OUTPUT ===
if (level === 'warn') {
console.warn(prefix, ...args);
} else if (level === 'error' || level === 'critical') {
console.error(prefix, ...args);
} else {
console.log(prefix, ...args);
}
// === FILE OUTPUT (wenn aktiviert) ===
if (DEBUG_CONFIG.OUTPUT_FILE === true && typeof window === 'undefined' === false) {
// Nur im Browser! Node.js hat native fs, aber wir checken das hier nicht
debugWriteToFile(prefix, level, args);
}
}
/**
* Schreibt eine Log-Zeile in die Debug-Log-Datei (falls OUTPUT_FILE=true)
* Datei-Pfad: /log/debug-YYYY-MM-DD-HHMMSS.log
* Format: [LEVEL] [DOMAIN] Timestamp Message
*
* @private
* @param {string} prefix - Formatierter Prefix ([LEVEL] [DOMAIN] timestamp)
* @param {DebugLevel} level - Log-Level
* @param {any[]} args - Log-Argumente
*/
function debugWriteToFile(prefix, level, args) {
try {
// Formatiere Args zu String
let message = args.map(arg => {
if (typeof arg === 'string') return arg;
if (typeof arg === 'object') return JSON.stringify(arg, null, 2);
return String(arg);
}).join(' ');
const logLine = `${prefix} ${message}\n`;
// Sende an Server (falls vorhanden)
// Dies würde z.B. ein Backend-Endpoint sein, der Logs speichert
// Format: POST /api/debug-log mit { log: logLine, level, timestamp }
// Für jetzt: Placeholder
// Alternative: IndexedDB (für Browser)
if (typeof indexedDB !== 'undefined') {
debugStoreInIndexedDB(logLine, level);
}
} catch (e) {
console.error('[DEBUG_CONFIG] Error writing to log file:', e.message);
}
}
/**
* Speichert Log in IndexedDB (Browser-seitig)
* Datenbank: 'WolfsWorldDebugLogs'
* Object Store: 'logs'
* Schlüssel: autoincrement timestamp
*
* @private
* @param {string} logLine - Formatierte Log-Zeile
* @param {DebugLevel} level - Log-Level
*/
function debugStoreInIndexedDB(logLine, level) {
try {
const request = indexedDB.open('WolfsWorldDebugLogs', 1);
request.onerror = () => {
console.warn('[DEBUG_CONFIG] IndexedDB open failed');
};
request.onupgradeneeded = (e) => {
const db = e.target.result;
if (!db.objectStoreNames.contains('logs')) {
db.createObjectStore('logs', { keyPath: 'id', autoIncrement: true });
}
};
request.onsuccess = (e) => {
const db = e.target.result;
const tx = db.transaction(['logs'], 'readwrite');
const store = tx.objectStore('logs');
store.add({
timestamp: new Date().toISOString(),
level: level,
message: logLine
});
tx.oncomplete = () => {
db.close();
};
};
} catch (e) {
// Silent fail - nicht self-propagate in console
}
}
if (typeof window !== 'undefined') {
window.DEBUG_CONFIG = DEBUG_CONFIG;
window.DEBUG_DOMAINS = DEBUG_DOMAINS;
window.DebugConfig = {
config: DEBUG_CONFIG,
domains: DEBUG_DOMAINS,
shouldLog: debugShouldLog,
log: debugLog,
/**
* Exportiert alle gespeicherten Logs aus IndexedDB als CSV
* Browser-Download: debug-logs-DATUM.csv
*
* Verwendung:
* window.DebugConfig.exportLogs();
* // Lädt CSV herunter
*
* @returns {Promise<void>}
*/
async exportLogs() {
if (typeof indexedDB === 'undefined') {
console.error('IndexedDB not available');
return;
}
return new Promise((resolve, reject) => {
const request = indexedDB.open('WolfsWorldDebugLogs', 1);
request.onsuccess = (e) => {
const db = e.target.result;
const tx = db.transaction(['logs'], 'readonly');
const store = tx.objectStore('logs');
const getAllRequest = store.getAll();
getAllRequest.onsuccess = () => {
const logs = getAllRequest.result;
let csv = 'Timestamp,Level,Message\n';
logs.forEach(log => {
const escapedMsg = `"${log.message.replace(/"/g, '""')}"`;
csv += `${log.timestamp},${log.level},${escapedMsg}\n`;
});
const blob = new Blob([csv], { type: 'text/csv' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `debug-logs-${new Date().toISOString().split('T')[0]}.csv`;
a.click();
URL.revokeObjectURL(url);
db.close();
resolve();
};
getAllRequest.onerror = () => {
reject(new Error('Failed to retrieve logs from IndexedDB'));
};
};
request.onerror = () => {
reject(new Error('Failed to open IndexedDB'));
};
});
},
/**
* Löscht alle Logs aus IndexedDB
*
* Verwendung:
* window.DebugConfig.clearLogs();
*
* @returns {Promise<void>}
*/
async clearLogs() {
if (typeof indexedDB === 'undefined') {
console.error('IndexedDB not available');
return;
}
return new Promise((resolve, reject) => {
const request = indexedDB.open('WolfsWorldDebugLogs', 1);
request.onsuccess = (e) => {
const db = e.target.result;
const tx = db.transaction(['logs'], 'readwrite');
const store = tx.objectStore('logs');
const clearRequest = store.clear();
clearRequest.onsuccess = () => {
console.log('[DebugConfig] All logs cleared from IndexedDB');
db.close();
resolve();
};
clearRequest.onerror = () => {
reject(new Error('Failed to clear logs'));
};
};
request.onerror = () => {
reject(new Error('Failed to open IndexedDB'));
};
});
},
/**
* Gibt alle gespeicherten Logs aus IndexedDB in console aus
*
* Verwendung:
* window.DebugConfig.showStoredLogs();
*
* @returns {Promise<void>}
*/
async showStoredLogs() {
if (typeof indexedDB === 'undefined') {
console.error('IndexedDB not available');
return;
}
return new Promise((resolve, reject) => {
const request = indexedDB.open('WolfsWorldDebugLogs', 1);
request.onsuccess = (e) => {
const db = e.target.result;
const tx = db.transaction(['logs'], 'readonly');
const store = tx.objectStore('logs');
const getAllRequest = store.getAll();
getAllRequest.onsuccess = () => {
const logs = getAllRequest.result;
console.table(logs);
db.close();
resolve();
};
getAllRequest.onerror = () => {
reject(new Error('Failed to retrieve logs'));
};
};
request.onerror = () => {
reject(new Error('Failed to open IndexedDB'));
};
});
},
};
}