using System; using System.Collections.Generic; using System.Linq; using Firebase.Database; using TMPro; using UnityEngine; public class VotingPage : MonoBehaviour { [Header("Scene References")] public PropositionFrame proposition1; public PropositionFrame proposition2; public TextMeshProUGUI currentPromptLabel; public TextMeshProUGUI timerLabel; [Header("Asset References")] public PromptList promptList; [Header("Settings")] public float votingTime = 20; private Queue remainingQuestions = new Queue(); private Question currentQuestion = null; private DatabaseReference roomRef; private Dictionary currentPlayers; // All the current playing players private DateTime endOfTimer = DateTime.MinValue; private Action OnVoteEnded; private bool allPlayersHaveVotedForCurrentQuestion = false; /// /// Is the number of questions for this game sessions /// private int numberOfQuestions = 0; private void Update() { // If there is no question displayed or the timer is not started, return early. if (currentQuestion == null || endOfTimer == DateTime.MinValue) return; if (DateTime.Now < endOfTimer) { TimeSpan duration = endOfTimer - DateTime.Now; timerLabel.text = ((int)duration.TotalSeconds).ToString("D2"); if (allPlayersHaveVotedForCurrentQuestion && endOfTimer > DateTime.Now.AddSeconds(4)) { Debug.Log("All players have voted. So I put only 4sec to look at the winner.", this); endOfTimer = DateTime.Now.AddSeconds(4); } } else { EndCurrentQuestion(); } } /// /// End current question and timer and go to next question (or end the vote if there is no more questions) /// private void EndCurrentQuestion() { timerLabel.text = "0"; if (remainingQuestions.Count > 0) { currentQuestion = remainingQuestions.Dequeue(); ShowNextQuestion(); } else { OnVoteEnded?.Invoke(); OnVoteEnded = null; gameObject.SetActive(false); for (int i = 0; i < numberOfQuestions; i++) { roomRef.Child("questions").Child(i.ToString()).ValueChanged -= OnQuestionDataUpdate; } } } /// /// Initializes the voting page with necessary data, such as the room reference, current players, /// questions, and a callback function for when the voting ends. /// /// Reference to the Firebase room database. /// Dictionary of current players. /// Dictionary of questions associated with their IDs. /// Callback function to invoke when the voting ends. public void ShowVotingPage(DatabaseReference _roomRef, Dictionary _currentPlayers, Dictionary _questions, Action _callback_OnVoteEnded) { Debug.Log("Initializing voting page"); roomRef = _roomRef; currentPlayers = _currentPlayers; OnVoteEnded = _callback_OnVoteEnded; allPlayersHaveVotedForCurrentQuestion = false; endOfTimer = DateTime.MinValue; remainingQuestions.Clear(); currentQuestion = null; Question[] _questionArray = _questions.Values.ToArray(); numberOfQuestions = _questionArray.Length; for (int i = 0; i < _questionArray.Length; i++) { remainingQuestions.Enqueue(_questionArray[i]); roomRef.Child("questions").Child(i.ToString()).ValueChanged += OnQuestionDataUpdate; } gameObject.SetActive(true); currentQuestion = remainingQuestions.Dequeue(); ShowNextQuestion(); } /// /// Displays the next question on the screen, updating the prompt, timer, and proposition frames. /// private void ShowNextQuestion() { // Set the current question ID in the Firebase room database. roomRef.Child("currentQuestionId").SetValueAsync(currentQuestion.index); // Update the prompt text based on the current question's prompt ID. Debug.Log($"Show Question {currentQuestion.promptId}", this); Prompt currentPrompt = promptList.GetPromptById(currentQuestion.promptId); currentPromptLabel.text = currentPrompt.en; Debug.Log($"Prompt is {currentPromptLabel.text}", this); // Initialize the proposition frames with proposition data. InitializeProposition(proposition1, currentQuestion.propositions[0]); InitializeProposition(proposition2, currentQuestion.propositions[1]); // Set the timer to end after the specified voting time. endOfTimer = DateTime.Now.AddSeconds(votingTime); //reset the count of voters allPlayersHaveVotedForCurrentQuestion = false; } /// /// Initializes a proposition frame with the provided proposition data, updating it if available, /// or handling the case when there is no proposition. /// /// The PropositionFrame to initialize or update. /// The Proposition data to use for initialization or update. private void InitializeProposition(PropositionFrame proposition, Proposition propositionData) { if (propositionData != null) { proposition.SetProposition(propositionData); } else { Debug.Log("User has given no proposition", this); proposition.SetNoProposition(); } } /// /// Handles updates to a question, such as when someone has voted for it. /// /// The sender of the event. /// The ValueChangedEventArgs containing the updated question reference. private void OnQuestionDataUpdate(object sender, ValueChangedEventArgs _questionRef) { string JSON = _questionRef.Snapshot.GetRawJsonValue(); if (string.IsNullOrEmpty(JSON)) return; Question question = Newtonsoft.Json.JsonConvert.DeserializeObject(JSON); // If someone succeeded in voting for another question than the one displayed, ignore it. if (question.index != currentQuestion.index) return; currentQuestion.propositions = question.propositions; if (currentQuestion.propositions.Count > 0) { // Update the proposition voters for both propositions. UpdatePropositionVoters(proposition1, currentQuestion.propositions[0]); UpdatePropositionVoters(proposition2, currentQuestion.propositions[1]); } //every players BUT the one who have created the propositions if (RoomManager.Instance.myRoom.NumbersOfVotersForQuestion(currentQuestion) >= currentPlayers.Count - 2) { allPlayersHaveVotedForCurrentQuestion = true; } } /// /// Updates the voters for a specific proposition frame based on the provided proposition data. /// If the proposition data is not null, it retrieves the list of voters and updates the frame. /// If there is no proposition data, it logs a message indicating that the user has not given a proposition. /// /// The PropositionFrame to update. /// The Proposition data used to update voters for the proposition frame. private void UpdatePropositionVoters(PropositionFrame proposition, Proposition propositionData) { if (propositionData != null) { List voters = GetVotersForProposition(propositionData); proposition.UpdateVoters(voters); } else { Debug.Log("User has given no proposition", this); // Handle the case when there is no proposition } } /// /// Retrieves the list of players who have voted for a specific proposition based on the provided proposition data. /// It checks if the proposition data contains a list of voters and then looks up player information in the current players dictionary. /// /// The Proposition data for which to retrieve voters. /// The list of players who voted for the proposition. private List GetVotersForProposition(Proposition propositionData) { List voters = new List(); if (propositionData.voters != null) { foreach (string playerId in propositionData.voters) { voters.Add(currentPlayers[playerId]); Debug.Log($"updating number of voters for: {propositionData.owner.name}'s propositions. They are now {voters.Count}."); } } return voters; } }