private GuessGameState WhenResetting(IChatService twitch, GuessGameCommand cmd)
        {
            if (cmd.ArgumentsAsList.Count < 2)
            {
                throw new InvalidOperationException();
            }

            if (!TimeSpan.TryParseExact(cmd.ArgumentsAsList[1], "m\\:ss", null, out TimeSpan time))
            {
                return(GuessGameState.NotStarted);
            }
            if (_guesses.Any(kv => kv.Value == time))
            {
                var found = _guesses.FirstOrDefault(kv => kv.Value == time);
                twitch.BroadcastMessageOnChannel($"WINNER!!! - Congratulations {found.Key} - you have won!");
            }
            else
            {
                var closest = _guesses.DefaultIfEmpty().Select(g => new { user = g.Key, seconds = g.Value.TotalSeconds, close = Math.Abs(g.Value.TotalSeconds - time.TotalSeconds) })
                              .OrderBy(g => g.close)
                              .First();

                twitch.BroadcastMessageOnChannel($"No winners THIS time, but {closest.user} was closest at just {closest.close} seconds off!");
            }
            return(GuessGameState.NotStarted);
        }
        private void OnHelpCommand(IChatService twitch, GuessGameCommand cmd, StateMachine <GuessGameState, GuessGameTrigger> .Transition transition)
        {
            switch (transition.Destination)
            {
            case GuessGameState.NotStarted:
                twitch.WhisperMessage(cmd.ChatUser.DisplayName, "The time-guessing game is not currently running.  To open the game for guesses, execute !guess open");
                break;

            case GuessGameState.OpenTakingGuesses:
                if (cmd.ChatUser.IsBroadcaster || cmd.ChatUser.IsModerator)
                {
                    twitch.WhisperMessage(cmd.ChatUser.Username, "The time-guessing game is currently taking guesses.  Guess a time with !guess 1:23, Your last guess will stand, and you can check your guess with !guess mine, OR close the guesses with !guess close");
                }
                else
                {
                    twitch.BroadcastMessageOnChannel("The time-guessing game is currently taking guesses.  Guess a time with !guess 1:23  Your last guess will stand, and you can check your guess with !guess mine");
                }
                break;

            case GuessGameState.GuessesClosed:
                if (!cmd.ChatUser.IsBroadcaster && !cmd.ChatUser.IsModerator)
                {
                    twitch.BroadcastMessageOnChannel("The time-guessing game is currently CLOSED.  You can check your guess with !guess mine");
                }
                else
                {
                    twitch.WhisperMessage(cmd.ChatUser.Username, "The time-guessing game is currently CLOSED.  You can check your guess with !guess mine, you can re-open for guessing with !guess open, and you can check for winners and reset the game with !guess end 1:23");
                }
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }
        }
 public void Mine(IChatService service, GuessGameCommand cmd)
 {
     cmd.ArgumentsAsList = new List <string>()
     {
         "mine"
     };
     SendGenericCommand(service, cmd);
 }
        private void SendGenericCommand(IChatService service, GuessGameCommand cmd)
        {
            if (service == null)
            {
                throw new ArgumentException("IChatService should not be null");
            }
            var validator = new GuessGameCommandValidator();
            var results   = validator.Validate(cmd);

            if (!results.IsValid)
            {
                foreach (var failure in results.Errors)
                {
                    //todo: move to logger??
                    Console.WriteLine("Property " + failure.PropertyName + " failed validation. Error was: " + failure.ErrorMessage);
                }
                throw new ArgumentException("The requested command is invalid", nameof(cmd));
            }

            if (cmd.ArgumentsAsList.Count == 0)
            {
                _machine.Fire(_setHelpTrigger, service, cmd);
                return;
            }
            //todo: choice based on argumentlist instead of called method??
            switch (cmd.ArgumentsAsList[0])
            {
            case "help":
                _machine.Fire(_setHelpTrigger, service, cmd);
                break;

            case "open":
                _machine.Fire(_setOpenTrigger, service, cmd);
                break;

            case "close":
                _machine.Fire(_setCloseTrigger, service, cmd);
                break;

            case "reset":
            case "end":
                _machine.Fire(_setResetTrigger, service, cmd);
                break;

            case "mine":
                _machine.Fire(_setMineTrigger, service, cmd);
                break;

            default:
                _machine.Fire(_setGuessTrigger, service, cmd);
                break;
            }
        }
 private void OnTakeGuessCommand(IChatService twitch, GuessGameCommand cmd, StateMachine <GuessGameState, GuessGameTrigger> .Transition transition)
 {
     if (            //cmd.ArgumentsAsList[0].Contains("-") ||
         !TimeSpan.TryParseExact(cmd.ArgumentsAsList[0], "m\\:ss", null, out TimeSpan time))
     {
         twitch.BroadcastMessageOnChannel($"Sorry {cmd.ChatUser.Username}, guesses are only accepted in the format !guess 1:23");
         return;
     }
     if (_guesses.Any(kv => kv.Value == time))
     {
         var firstGuess = _guesses.First(kv => kv.Value == time);
         twitch.BroadcastMessageOnChannel($"Sorry {cmd.ChatUser.Username}, {firstGuess.Key} already guessed {time.ToString()}");
     }
     else if (_guesses.Any(kv => kv.Key == cmd.ChatUser.Username))
     {
         _guesses[cmd.ChatUser.Username] = time;
     }
     else
     {
         _guesses.Add(cmd.ChatUser.Username, time);
     }
 }
        private void OnMineCommand(IChatService twitch, GuessGameCommand cmd, StateMachine <GuessGameState, GuessGameTrigger> .Transition transition)
        {
            switch (transition.Destination)
            {
            case GuessGameState.NotStarted:
                break;

            case GuessGameState.OpenTakingGuesses:
                twitch.BroadcastMessageOnChannel(_guesses.Any(kv => kv.Key == cmd.ChatUser.Username)
                                                        ? $"{cmd.ChatUser.Username} guessed {_guesses[cmd.ChatUser.Username].ToString()}"
                                                        : $"{cmd.ChatUser.Username} has not guessed yet!");
                break;

            case GuessGameState.GuessesClosed:
                twitch.BroadcastMessageOnChannel(_guesses.Any(kv => kv.Key == cmd.ChatUser.Username)
                                                        ? $"{cmd.ChatUser.Username} guessed {_guesses[cmd.ChatUser.Username].ToString()}"
                                                        : $"{cmd.ChatUser.Username} has not guessed yet!");
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }
        }
 private bool CanClose(IChatService service, GuessGameCommand cmd)
 {
     return(cmd.ChatUser.IsBroadcaster || cmd.ChatUser.IsModerator);
 }
 private GuessGameState WhenOpeningFromNotStarted(IChatService twitch, GuessGameCommand cmd)
 {
     twitch.BroadcastMessageOnChannel("Now taking guesses. Submit your guess with !guess 1:23 where 1 is minutes and 23 is seconds.");
     return(GuessGameState.OpenTakingGuesses);
 }
 private GuessGameState WhenClosingFromTakingGuesses(IChatService twitch, GuessGameCommand cmd)
 {
     twitch.BroadcastMessageOnChannel($"No more guesses...  the race is about to start with {_guesses.Count} guesses from {_guesses.DefaultIfEmpty().Min(kv => kv.Value).ToString()} to {_guesses.DefaultIfEmpty().Max(kv => kv.Value).ToString()}");
     return(GuessGameState.GuessesClosed);
 }
 private GuessGameState WhenOpeningFromClosed(IChatService twitch, GuessGameCommand cmd)
 {
     twitch.BroadcastMessageOnChannel("Now taking guesses again!  You may log a new guess or change your guess now!");
     return(GuessGameState.OpenTakingGuesses);
 }
 public void Guess(IChatService service, GuessGameCommand cmd)
 {
     SendGenericCommand(service, cmd);
 }
 public void Reset(IChatService service, GuessGameCommand cmd)
 {
     //cmd.ArgumentsAsList = new List<string>() { "reset" };
     SendGenericCommand(service, cmd);
 }