const STORAGE_KEY = 'turnierplaner_data'; const ROTATION_STATE_KEY = 'turnierplaner_rotation'; const SCORES_KEY = 'turnierplaner_scores'; let timerInterval = null; let timerSeconds = 0; let isRunning = false; let allTeams = []; let fieldCount = 0; // Anzahl der physischen Felder (jedes Feld hat 2 Feldhälften) let rotationState = {}; let matchScores = {}; // { "league:fieldNum": {team1Score, team2Score}, ... } document.addEventListener('DOMContentLoaded', () => { loadTournamentData(); setupTimerInput(); loadMatchScores(); }); function loadTournamentData() { const stored = localStorage.getItem(STORAGE_KEY); if (!stored) { console.warn('Keine Turnierdaten gefunden'); return; } const data = JSON.parse(stored); allTeams = data; fieldCount = parseInt(data.fieldCount) || 0; // Lade oder initialisiere Rotations-State loadRotationState(data); // Populate fields mit aktuellem State displayCurrentRound(); } function loadRotationState(data) { const stored = localStorage.getItem(ROTATION_STATE_KEY); if (stored) { rotationState = JSON.parse(stored); } else { // Initialisiere mit Startzustand rotationState = { bundesliga: { round: 0, teamOrder: data.bundesliga.map((t, i) => i) }, champions: { round: 0, teamOrder: data.champions.map((t, i) => i) } }; saveRotationState(); } } function saveRotationState() { localStorage.setItem(ROTATION_STATE_KEY, JSON.stringify(rotationState)); } function displayCurrentRound() { displayLeagueRound('bundesliga', allTeams.bundesliga); displayLeagueRound('champions', allTeams.champions); } function displayLeagueRound(league, teams) { // Jedes Feld hat 2 Feldhälften, also maximal fieldCount * 2 Teams können gleichzeitig spielen const maxPlayingTeams = fieldCount * 2; const playingTeamsCount = Math.min(teams.length, maxPlayingTeams); const fieldsPerLeague = Math.ceil(playingTeamsCount / 2); // Anzahl Felder für diese Liga const state = rotationState[league]; // Bestimme Offset für Feldnummern - Champions League beginnt nach Bundesliga let fieldNumberOffset = 0; if (league === 'champions') { const bundesligaPlayingTeams = Math.min(allTeams.bundesliga.length, fieldCount * 2); fieldNumberOffset = Math.ceil(bundesligaPlayingTeams / 2); } // Aktualisiere Felder basierend auf teamOrder const container = document.getElementById(`${league}-fields`); container.innerHTML = ''; for (let i = 0; i < fieldsPerLeague; i++) { // Info-Box für Feldnummer (nur Label) const fieldInfoBox = document.createElement('div'); fieldInfoBox.className = 'field-info-box'; const fieldNum = fieldNumberOffset + i + 1; fieldInfoBox.innerHTML = `
Feld ${fieldNum}:
`; container.appendChild(fieldInfoBox); // Team 1 (mittlere Spalte) mit Score-Input const team1Index = state.teamOrder[i * 2]; const team1 = teams[team1Index] || {}; const fieldCard1 = document.createElement('div'); fieldCard1.className = 'field-card'; const scoreKey = getScoreKey(league, fieldNum); const existingScore = matchScores[scoreKey] || { team1Score: '', team2Score: '' }; fieldCard1.innerHTML = `
${team1.name || '-'}
`; fieldCard1.id = `score-${league}-${fieldNum}-t1-card`; container.appendChild(fieldCard1); // Team 2 (rechte Spalte) mit Score-Input const team2Index = state.teamOrder[i * 2 + 1]; const team2 = teams[team2Index] || {}; const fieldCard2 = document.createElement('div'); fieldCard2.className = 'field-card'; fieldCard2.innerHTML = `
${team2.name || '-'}
`; container.appendChild(fieldCard2); } // Aktualisiere wartende Teams updateWaitingTeams(league, teams, fieldsPerLeague, state.teamOrder); } function updateWaitingTeams(league, teams, fieldsPerLeague, teamOrder) { const container = document.getElementById(`${league}-waiting`); container.innerHTML = ''; // Anzahl der spielenden Teams = fieldsPerLeague * 2 (2 Teams pro Feld) const playingTeamsCount = fieldsPerLeague * 2; const waitingIndices = teamOrder.slice(playingTeamsCount); if (waitingIndices.length === 0) { container.innerHTML = '
Alle Teams spielen
'; } else { waitingIndices.forEach(teamIndex => { const team = teams[teamIndex]; const badge = document.createElement('div'); badge.className = 'waiting-team-badge'; badge.textContent = team.name; badge.title = `${team.club || ''} - ${team.motto || ''}`; container.appendChild(badge); }); } } function populateFields(league, teams, fieldCount) { const container = document.getElementById(`${league}-fields`); const totalFields = parseInt(fieldCount); const fieldsPerLeague = Math.ceil(totalFields / 2); container.innerHTML = ''; for (let i = 1; i <= fieldsPerLeague; i++) { const fieldCard = document.createElement('div'); fieldCard.className = 'field-card'; // Zuweisung von Teams zu Feldern (Round-Robin) const teamIndex = (i - 1) % teams.length; const team = teams[teamIndex] || {}; fieldCard.innerHTML = `
Feld ${i}
${team.name || '-'}
`; fieldCard.setAttribute('data-field', i); fieldCard.setAttribute('data-league', league); fieldCard.setAttribute('data-team', team.name || ''); container.appendChild(fieldCard); } } function populateWaitingTeams(league, teams, fieldCount) { const container = document.getElementById(`${league}-waiting`); const totalFields = parseInt(fieldCount); const fieldsPerLeague = Math.ceil(totalFields / 2); container.innerHTML = ''; // Teams die auf Feldern spielen const playingTeamIndices = new Set(); for (let i = 0; i < fieldsPerLeague; i++) { playingTeamIndices.add(i % teams.length); } // Wartende Teams sind alle Teams, die nicht gerade spielen const waitingTeams = teams.filter((team, index) => !playingTeamIndices.has(index)); if (waitingTeams.length === 0) { container.innerHTML = '
Alle Teams spielen
'; } else { waitingTeams.forEach(team => { const badge = document.createElement('div'); badge.className = 'waiting-team-badge'; badge.textContent = team.name; badge.title = `${team.club || ''} - ${team.motto || ''}`; container.appendChild(badge); }); } } // Timer Functions function setupTimerInput() { const timerInput = document.getElementById('timerInput'); timerInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') { const value = timerInput.value.trim(); if (value) { parseAndSetTimer(value); timerInput.value = ''; timerInput.blur(); // Remove focus after input } } }); } function parseAndSetTimer(timeStr) { let seconds = 0; if (timeStr.includes(':')) { // Parse MM:SS format const parts = timeStr.split(':'); if (parts.length === 2) { const minutes = parseInt(parts[0]) || 0; seconds = parseInt(parts[1]) || 0; seconds = minutes * 60 + seconds; } } else { // Parse as just seconds seconds = parseInt(timeStr) || 0; } if (seconds > 0) { // Stop current timer if running if (isRunning) { pauseTimer(); } timerSeconds = seconds; updateTimerDisplay(); // Start timer automatically startTimer(); } } function toggleTimer() { if (isRunning) { pauseTimer(); } else { startTimer(); } } function startTimer() { if (isRunning) return; isRunning = true; const btn = document.getElementById('timerBtn'); btn.textContent = 'Pause'; timerInterval = setInterval(() => { if (timerSeconds > 0) { timerSeconds--; updateTimerDisplay(); } else { pauseTimer(); } }, 1000); } function pauseTimer() { if (!isRunning) return; isRunning = false; const btn = document.getElementById('timerBtn'); btn.textContent = 'Start'; if (timerInterval) { clearInterval(timerInterval); timerInterval = null; } } function updateTimerDisplay() { const minutes = Math.floor(timerSeconds / 60); const seconds = timerSeconds % 60; const display = `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`; document.getElementById('timerDisplay').textContent = display; } // Modal Functions function openPointsModal() { document.getElementById('pointsModal').style.display = 'block'; } function closePointsModal() { document.getElementById('pointsModal').style.display = 'none'; } function openResultsModal() { document.getElementById('resultsModal').style.display = 'block'; } function closeResultsModal() { document.getElementById('resultsModal').style.display = 'none'; } function savePoints(event) { event.preventDefault(); const field = document.getElementById('pointsField').value; const team = document.getElementById('pointsTeam').value; const points = document.getElementById('pointsValue').value; if (!field || !points) { alert('Bitte alle Felder ausfüllen'); return; } // TODO: Punkte speichern (z.B. in localStorage oder an Server) console.log('Punkte gespeichert:', { field, team, points }); alert(`✅ Punkte für ${team} gespeichert!`); // Reset form document.getElementById('pointsField').value = ''; document.getElementById('pointsTeam').value = ''; document.getElementById('pointsValue').value = ''; closePointsModal(); } function saveResults(event) { event.preventDefault(); const field = document.getElementById('resultsField').value; const team = document.getElementById('resultsTeam').value; const sets = document.getElementById('resultsSets').value; const opponent = document.getElementById('resultsOpponent').value; if (!field || !sets) { alert('Bitte alle Pflichtfelder ausfüllen'); return; } // TODO: Ergebnisse speichern (z.B. in localStorage oder an Server) console.log('Ergebnis gespeichert:', { field, team, sets, opponent }); alert(`✅ Ergebnis für ${team} gespeichert!`); // Reset form document.getElementById('resultsField').value = ''; document.getElementById('resultsTeam').value = ''; document.getElementById('resultsSets').value = ''; document.getElementById('resultsOpponent').value = ''; closeResultsModal(); } // Close modal when clicking outside window.addEventListener('click', (event) => { const pointsModal = document.getElementById('pointsModal'); const resultsModal = document.getElementById('resultsModal'); if (event.target === pointsModal) { closePointsModal(); } if (event.target === resultsModal) { closeResultsModal(); } }); function goBack() { // Stop timer before navigating if (isRunning) { pauseTimer(); } window.location.href = 'index.html'; } // Rotation Logic function nextRound() { // Inkrementiere Runden-Nummer rotationState.bundesliga.round++; rotationState.champions.round++; // Leere die Scores für die neue Runde matchScores = {}; saveMatchScores(); rotateLeague('bundesliga', allTeams.bundesliga); rotateLeague('champions', allTeams.champions); saveRotationState(); displayCurrentRound(); console.log('Nächste Runde!', rotationState); } function rotateLeague(league, teams) { // Jedes Feld hat 2 Feldhälften - maximale spielende Teams = fieldCount * 2 const maxPlayingTeams = fieldCount * 2; const playingTeamsCount = Math.min(teams.length, maxPlayingTeams); const state = rotationState[league]; const totalTeams = teams.length; const waitingCount = totalTeams - playingTeamsCount; // Fall 1: Keine wartenden Teams (Anzahl Teams = fieldCount * 2) // Team 1 bleibt stehen, alle anderen rotieren um 1 Position weiter if (waitingCount === 0) { // [0, 1, 2, 3, 4, 5] -> [0, 2, 3, 4, 5, 1] // Team an Index 0 bleibt, Team an Index 1 geht ans Ende, Rest rückt auf if (state.teamOrder.length > 1) { const secondTeam = state.teamOrder.splice(1, 1)[0]; state.teamOrder.push(secondTeam); } console.log(`${league} Fall 1: Team ${teams[state.teamOrder[0]].name} bleibt stehen, andere rotieren`); } // Fall 2: Genau 1 wartendes Team (Anzahl Teams = fieldCount * 2 + 1) // Alle rotieren um 1 Position, wartendes Team kommt aufs Randfeld else if (waitingCount === 1) { // [0, 1, 2, 3, 4, 5, 6(wartend)] -> [1, 2, 3, 4, 5, 6, 0] // Einfach erstes Team ans Ende verschieben const first = state.teamOrder.shift(); state.teamOrder.push(first); console.log(`${league} Fall 2: Team ${teams[first].name} geht warten, Team ${teams[state.teamOrder[playingTeamsCount - 1]].name} kommt ins Spiel`); } // Fall 3: Mehrere wartende Teams (Anzahl Teams > fieldCount * 2 + 1) // Alle wartenden sollen spielen, max 1 Runde Pause else { // [0, 1, 2, 3(spielend), 4, 5, 6, 7(wartend)] -> [4, 5, 6, 7(jetzt spielend), 0, 1, 2, 3(jetzt wartend)] // Wartende Teams kommen nach vorne, spielende Teams gehen warten const playingTeams = state.teamOrder.slice(0, playingTeamsCount); const waitingTeams = state.teamOrder.slice(playingTeamsCount); state.teamOrder = [...waitingTeams, ...playingTeams]; console.log(`${league} Fall 3: Wartende Teams spielen jetzt, spielende Teams warten`); } } // ===== SCORE & PUNKTE-SYSTEM ===== function loadMatchScores() { const stored = localStorage.getItem(SCORES_KEY); if (stored) { matchScores = JSON.parse(stored); } else { matchScores = {}; } } function saveMatchScores() { localStorage.setItem(SCORES_KEY, JSON.stringify(matchScores)); } function getScoreKey(league, fieldNum) { return `${league}:${fieldNum}`; } function updateMatchScore(league, fieldNum, team1Score, team2Score) { const key = getScoreKey(league, fieldNum); matchScores[key] = { round: rotationState[league].round, team1Score: parseInt(team1Score) || 0, team2Score: parseInt(team2Score) || 0 }; saveMatchScores(); } function calculatePoints(team1Score, team2Score) { // Berechnet Punkte für Team 1 und Team 2 basierend auf Spielstand const diff = Math.abs(team1Score - team2Score); if (team1Score > team2Score) { // Team 1 gewinnt return { team1Points: diff + 2, team2Points: -diff }; } else if (team2Score > team1Score) { // Team 2 gewinnt return { team1Points: -diff, team2Points: diff + 2 }; } else { // Unentschieden return { team1Points: 0, team2Points: 0 }; } } function getTeamPointsHistory() { // Erstellt eine Punkte-Historie für alle Teams in beiden Ligen const history = { bundesliga: {}, champions: {} }; // Initialisiere leere Arrays für jedes Team allTeams.bundesliga.forEach((team, idx) => { history.bundesliga[idx] = []; }); allTeams.champions.forEach((team, idx) => { history.champions[idx] = []; }); // Gehe durch alle gespeicherten Scores Object.keys(matchScores).forEach(key => { const [league, fieldNum] = key.split(':'); const score = matchScores[key]; const fieldNumInt = parseInt(fieldNum); const state = rotationState[league]; const teamsInLeague = league === 'bundesliga' ? allTeams.bundesliga : allTeams.champions; // Berechne fieldsPerLeague basierend auf fieldCount const maxPlayingTeams = fieldCount * 2; const playingTeamsCount = Math.min(teamsInLeague.length, maxPlayingTeams); const fieldsPerLeague = Math.ceil(playingTeamsCount / 2); // Bestimme Offset für Feldnummern const bundesligaPlayingTeams = Math.min(allTeams.bundesliga.length, fieldCount * 2); const bundesligaFields = Math.ceil(bundesligaPlayingTeams / 2); const fieldOffset = league === 'bundesliga' ? 0 : bundesligaFields; const i = fieldNumInt - fieldOffset - 1; if (i >= 0 && i < fieldsPerLeague && state && state.teamOrder) { const team1Index = state.teamOrder[i * 2]; const team2Index = state.teamOrder[i * 2 + 1]; if (team1Index !== undefined && team2Index !== undefined) { const points = calculatePoints(score.team1Score, score.team2Score); if (!history[league][team1Index][score.round]) { history[league][team1Index][score.round] = 0; } if (!history[league][team2Index][score.round]) { history[league][team2Index][score.round] = 0; } history[league][team1Index][score.round] = points.team1Points; history[league][team2Index][score.round] = points.team2Points; } } }); return history; } // ===== MODAL FUNCTIONS ===== function openPointsModal() { const history = getTeamPointsHistory(); const content = document.getElementById('pointsDisplayContent'); content.innerHTML = ''; // Bundesliga if (allTeams.bundesliga.length > 0) { content.appendChild(createLeaguePointsSection('bundesliga', 'Bundesliga', allTeams.bundesliga, history.bundesliga)); } // Champions League if (allTeams.champions.length > 0) { content.appendChild(createLeaguePointsSection('champions', 'Champions League', allTeams.champions, history.champions)); } document.getElementById('pointsModal').style.display = 'block'; } function createLeaguePointsSection(leagueId, leagueName, teams, history) { const section = document.createElement('div'); section.className = 'league-points-section'; // Header const header = document.createElement('div'); header.className = 'league-points-header'; header.innerHTML = leagueName; section.appendChild(header); // Table const table = document.createElement('table'); table.className = 'points-table'; // Berechne maximale Runde let maxRound = 0; Object.keys(history).forEach(teamId => { if (history[teamId] && history[teamId].length) { maxRound = Math.max(maxRound, history[teamId].length - 1); } }); // Header Row const headerRow = document.createElement('tr'); headerRow.innerHTML = 'Team'; for (let r = 0; r <= maxRound; r++) { const th = document.createElement('th'); th.innerHTML = `Runde ${r + 1}`; headerRow.appendChild(th); } const totalTh = document.createElement('th'); totalTh.innerHTML = 'Gesamt'; headerRow.appendChild(totalTh); table.appendChild(headerRow); // Team Rows teams.forEach((team, teamIdx) => { const row = document.createElement('tr'); // Team Name const nameCell = document.createElement('td'); nameCell.style.textAlign = 'left'; nameCell.style.fontWeight = '500'; nameCell.innerHTML = team.name; row.appendChild(nameCell); // Points per round let totalPoints = 0; const teamHistory = history[teamIdx] || []; for (let r = 0; r <= maxRound; r++) { const cell = document.createElement('td'); const points = teamHistory[r] !== undefined ? teamHistory[r] : '-'; if (points !== '-') { totalPoints += points; const pointsDiv = document.createElement('div'); pointsDiv.className = 'points-value'; if (points > 0) { pointsDiv.classList.add('positive'); pointsDiv.innerHTML = `+${points}`; } else if (points < 0) { pointsDiv.classList.add('negative'); pointsDiv.innerHTML = `${points}`; } else { pointsDiv.classList.add('neutral'); pointsDiv.innerHTML = '0'; } cell.appendChild(pointsDiv); } else { cell.innerHTML = '-'; } row.appendChild(cell); } // Total Points const totalCell = document.createElement('td'); const totalDiv = document.createElement('div'); totalDiv.className = 'points-value points-total'; totalDiv.innerHTML = totalPoints > 0 ? `+${totalPoints}` : `${totalPoints}`; totalCell.appendChild(totalDiv); row.appendChild(totalCell); table.appendChild(row); }); section.appendChild(table); return section; } function closePointsModal() { document.getElementById('pointsModal').style.display = 'none'; } function openScoreboard() { const history = getTeamPointsHistory(); const content = document.getElementById('scoreboardContent'); content.innerHTML = ''; // Erstelle Daten für beide Ligen mit Gesamtpunkten const leaguesData = [ { id: 'bundesliga', name: 'Bundesliga', teams: allTeams.bundesliga, history: history.bundesliga }, { id: 'champions', name: 'Champions League', teams: allTeams.champions, history: history.champions } ]; leaguesData.forEach(league => { if (league.teams.length > 0) { // Berechne Gesamtpunkte für jedes Team const teamScores = league.teams.map((team, idx) => { const teamHistory = league.history[idx] || []; const totalPoints = teamHistory.reduce((sum, pts) => sum + (pts || 0), 0); return { idx, name: team.name, points: totalPoints }; }); // Sortiere absteigend nach Punkten teamScores.sort((a, b) => b.points - a.points); // Erstelle die Liga-Section const section = document.createElement('div'); section.className = 'scoreboard-league'; const header = document.createElement('div'); header.className = 'scoreboard-league-header'; header.innerHTML = league.name; section.appendChild(header); const list = document.createElement('ul'); list.className = 'scoreboard-list'; teamScores.forEach((score, rank) => { const item = document.createElement('li'); item.className = 'scoreboard-item'; const rankDiv = document.createElement('div'); rankDiv.className = 'scoreboard-rank'; rankDiv.innerHTML = `${rank + 1}.`; item.appendChild(rankDiv); const nameDiv = document.createElement('div'); nameDiv.className = 'scoreboard-team-name'; nameDiv.innerHTML = score.name; item.appendChild(nameDiv); const pointsDiv = document.createElement('div'); pointsDiv.className = 'scoreboard-points'; if (score.points > 0) { pointsDiv.classList.add('positive'); pointsDiv.innerHTML = `+${score.points}`; } else if (score.points < 0) { pointsDiv.classList.add('negative'); pointsDiv.innerHTML = `${score.points}`; } else { pointsDiv.innerHTML = '0'; } item.appendChild(pointsDiv); list.appendChild(item); }); section.appendChild(list); content.appendChild(section); } }); document.getElementById('scoreboardModal').style.display = 'block'; } function closeScoreboard() { document.getElementById('scoreboardModal').style.display = 'none'; } function confirmReset() { document.getElementById('resetConfirmModal').style.display = 'block'; } function closeResetConfirm() { document.getElementById('resetConfirmModal').style.display = 'none'; } function performReset() { // Lade die Rohdaten (Teams, Feldanzahl) const stored = localStorage.getItem(STORAGE_KEY); if (!stored) return; const data = JSON.parse(stored); // Setze Rotationsstates zurück auf Anfangszustand rotationState = { bundesliga: { round: 0, teamOrder: data.bundesliga.map((t, i) => i) }, champions: { round: 0, teamOrder: data.champions.map((t, i) => i) } }; // Leere alle Scores matchScores = {}; // Speichere zurückgesetzte States saveRotationState(); saveMatchScores(); // Aktualisiere die UI displayCurrentRound(); // Schließe das Modal closeResetConfirm(); alert('✅ Turnier wurde zurückgesetzt! Alle Runden und Scores wurden gelöscht.'); } function openResultsModal() { document.getElementById('resultsModal').style.display = 'block'; } function closeResultsModal() { document.getElementById('resultsModal').style.display = 'none'; }