namespace ScoreboardApi.Functions { using ScoreboardApi.Objects; public class GameManager : IGameManager { private readonly IPointsCalculator pointsCalculator; private Game? _game; public GameManager(IPointsCalculator pointsCalculator) { this.pointsCalculator = pointsCalculator; } public void StartNew(Team home, Team away, DateTimeOffset kickOffTime) { if (_game != null) { throw new InvalidOperationException("Game is already configured"); } _game = new Game { Half = HalfType.Pre, Home = home, Away = away, StartedAt = kickOffTime, State = GameState.WaitingForStart }; } public void Finish() { if (_game == null) { return; } _game.FinishedAt = DateTimeOffset.UtcNow; _game.State = GameState.Finished; _game.Half = HalfType.End; var evt = new Event { Category = EventCategory.Match, EventType = EventType.MatchEnd, TimeStamp = DateTimeOffset.Now }; AddEvent(evt); } public void AddEvent(Event newEvent) { if (_game == null) { return; } newEvent.Id = GetEventId(); newEvent.Points = pointsCalculator.GetEventScore(newEvent.EventType); if (newEvent.Category == EventCategory.Match) { _game.MatchEvents.Add(newEvent); } else if (newEvent.Category == EventCategory.Home) { _game.Home.EventHistory.Add(newEvent); } else { _game.Away.EventHistory.Add(newEvent); } switch (newEvent.EventType) { case EventType.HalfTime: _game.State = GameState.HalfTime; _game.Half = HalfType.First; return; case EventType.SecondHalfStart: _game.State = GameState.SecondHalf; _game.Half = HalfType.Second; return; case EventType.TimeOff: _game.State = GameState.TimeOff; return; case EventType.TimeOn: if (_game.Half == HalfType.First) { _game.State = GameState.FirstHalf; } else if (_game.Half == HalfType.Second) { _game.State = GameState.SecondHalf; } break; case EventType.MatchEnd: _game.State = GameState.Finished; _game.Half = HalfType.End; break; } } public void DeleteEvent(int eventId) { if (_game == null) { return; } _game.Teams.ForEach( (t) => { Event? eventToRemove = t.EventHistory.FirstOrDefault(x => x.Id == eventId); if (eventToRemove != null) { t.EventHistory.Remove(eventToRemove); } }); } public void ResetGame() => _game = null; public Game GetScore() { if (_game == null) { return null; } if (_game.State == GameState.WaitingForStart && DateTimeOffset.UtcNow.UtcDateTime.CompareTo(_game.StartedAt.UtcDateTime) >= 0) { var evt = new Event { Category = EventCategory.Match, EventType = EventType.MatchStart, TimeStamp = DateTimeOffset.Now }; AddEvent(evt); _game.Half = HalfType.First; _game.State = GameState.FirstHalf; } return _game; } private int GetEventId() { IEnumerable events = _game.EventHistory; if (!events.Any()) { return 1; } return events.Max(x => x.Id) + 1; } } }