// playerManager.js - Player-related operations import * as config from '../config.js'; import * as state from './state.js'; import * as ui from '../ui/ui.js'; import * as timer from './timer.js'; import audioManager from '../ui/audio.js'; import camera from '../ui/camera.js'; export function switchToPlayer(index) { if (index >= 0 && index < state.getPlayers().length) { const previousIndex = state.getCurrentPlayerIndex(); if(index !== previousIndex) { state.setCurrentPlayerIndex(index); audioManager.play('playerSwitch'); ui.renderPlayers(); // Update UI immediately // If the game is running, restart the timer for the new player // The timer interval callback will handle the decrementing if (state.getGameState() === config.GAME_STATES.RUNNING) { timer.startTimer(); // This clears the old interval and starts anew } } } } export function nextPlayer() { const currentGameState = state.getGameState(); let newIndex = -1; if (currentGameState === config.GAME_STATES.RUNNING) { newIndex = state.findNextPlayerWithTimeCircular(1); // Find next with time } else { // Allow cycling through all players if not running const playerCount = state.getPlayers().length; if(playerCount > 0) { newIndex = (state.getCurrentPlayerIndex() + 1) % playerCount; } } if (newIndex !== -1) { switchToPlayer(newIndex); } else if (currentGameState === config.GAME_STATES.RUNNING) { console.log("NextPlayer: No other player has time remaining."); // Optionally handle game over immediately? Timer logic should catch this too. } } export function previousPlayer() { const currentGameState = state.getGameState(); let newIndex = -1; if (currentGameState === config.GAME_STATES.RUNNING) { newIndex = state.findNextPlayerWithTimeCircular(-1); // Find previous with time } else { // Allow cycling through all players if not running const playerCount = state.getPlayers().length; if (playerCount > 0) { newIndex = (state.getCurrentPlayerIndex() - 1 + playerCount) % playerCount; } } if (newIndex !== -1) { switchToPlayer(newIndex); } else if (currentGameState === config.GAME_STATES.RUNNING) { console.log("PreviousPlayer: No other player has time remaining."); } } export function handlePlayerFormSubmit(event) { event.preventDefault(); audioManager.play('buttonClick'); const name = ui.elements.playerNameInput.value.trim(); const timeInMinutes = parseInt(ui.elements.playerTimeInput.value, 10); let remainingTimeSeconds = 0; // Default const isNewPlayer = ui.elements.modalTitle.textContent === 'Add New Player'; const currentGameState = state.getGameState(); if (!name || isNaN(timeInMinutes) || timeInMinutes <= 0) { alert('Please enter a valid name and positive time.'); return; } // Get remaining time ONLY if editing and game is paused/over if (!isNewPlayer && (currentGameState === config.GAME_STATES.PAUSED || currentGameState === config.GAME_STATES.OVER)) { const remainingTimeString = ui.elements.playerRemainingTimeInput.value; const parsedSeconds = ui.parseTimeString(remainingTimeString); if (parsedSeconds === null) { // Check if parsing failed alert('Please enter remaining time in MM:SS format (e.g., 05:30).'); return; } remainingTimeSeconds = parsedSeconds; // Validate remaining time against total time? Optional. if (remainingTimeSeconds > timeInMinutes * 60) { alert('Remaining time cannot be greater than the total time.'); return; } } else { // For new players or when editing in setup, remaining time matches total time remainingTimeSeconds = timeInMinutes * 60; } let imageDataUrl = ui.elements.playerImageInput.dataset.capturedImage || null; const imageFile = ui.elements.playerImageInput.files[0]; const saveAction = (finalImageData) => { if (isNewPlayer) { state.addPlayer(name, timeInMinutes, finalImageData); audioManager.play('playerAdded'); } else { const playerIndex = state.getCurrentPlayerIndex(); // Use 'undefined' for image if no new image is provided, so state.updatePlayer keeps the old one const imageArg = finalImageData !== null ? finalImageData : (isNewPlayer ? null : undefined); state.updatePlayer(playerIndex, name, timeInMinutes, remainingTimeSeconds, imageArg); audioManager.play('playerEdited'); } ui.hidePlayerModal(); ui.renderPlayers(); ui.updateGameButton(); // Update in case player count changed for setup state camera.stopStream(); // Ensure camera is stopped }; if (!imageDataUrl && imageFile) { // Handle file upload: Read file as Data URL const reader = new FileReader(); reader.onload = (e) => saveAction(e.target.result); reader.onerror = (e) => { console.error("Error reading image file:", e); alert("Error processing image file."); }; reader.readAsDataURL(imageFile); } else { // Handle captured image or no image change const currentImage = isNewPlayer ? null : state.getCurrentPlayer()?.image; // If imageDataUrl has content (from camera), use it. // If not, and no file was selected, keep the current image (by passing undefined to updatePlayer later). // If it's a new player and no image, pass null. saveAction(imageDataUrl ?? (isNewPlayer ? null : currentImage)); } } export function handleDeletePlayer() { audioManager.play('buttonClick'); const success = state.deletePlayer(state.getCurrentPlayerIndex()); if (success) { audioManager.play('playerDeleted'); ui.hidePlayerModal(); ui.renderPlayers(); ui.updateGameButton(); // Update in case player count dropped below 2 } else { alert('Cannot delete player. Minimum of 2 players required.'); } camera.stopStream(); }