private void PerformServerRequest(ServerRequestConfig config)
        {
            BackgroundWorker worker = new BackgroundWorker();
            worker.DoWork += (sender, args) =>
                {
                    var workerConfig = (ServerRequestConfig)args.Argument;
                    //"http://centralserver.codeketeers.com/ServerPairing.php?challenge=James&from=Anthony"
                    JavaScriptSerializer dataSerailizer = new JavaScriptSerializer();
                    string queryString = string.Join("&", dataSerailizer.Deserialize<Dictionary<string, string>>(config.RequestData).Where(kv => !string.IsNullOrEmpty(kv.Value)).Select(kv => string.Format("{0}={1}", kv.Key, HttpUtility.UrlEncode(kv.Value != null ? kv.Value : string.Empty))));
                    string fullUrl = string.Format("{0}?{1}", config.Url, queryString);
                    Logger.Instance.Log("ServerRequest", string.Format("GameId:{0}|MatchId:{1}|Request:{2}", workerConfig.GameId, workerConfig.MatchId, fullUrl), JsonSerializer.SerializeToJSON(workerConfig));
                    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(fullUrl);
                    request.ContentLength = 0;

                    var httpResponse = (HttpWebResponse)request.GetResponse();
                    using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
                    {
                        var result = streamReader.ReadToEnd();
                        Logger.Instance.Log("ServerResponse", string.Format("GameId:{0}|MatchId:{1}|Request:{2}", workerConfig.GameId, workerConfig.MatchId, fullUrl), result);
                        workerConfig.ResponseAction(result, workerConfig.MatchId);
                    }
                };
            worker.RunWorkerAsync(config);
            worker.RunWorkerCompleted += (cs, ce) =>
            {
                if (ce.Error != null)
                {
                    Exception ex = ce.Error;
                    while (ex.InnerException != null)
                    {
                        ex = ex.InnerException;
                    }

                    Logger.Instance.Log("CentralServerCommunicationError", string.Format("GameId:{0}|MatchId:{1}|Error:{2}",config.GameId,config.MatchId, ex.Message), ce.Error.StackTrace);
                    using (IGameDataService dataService = new GameDataService())
                    {
                        dataService.EndGame(config.GameId, null);
                        dataService.Save();

                        Match match = dataService.GetMatch(config.MatchId, null);
                        CentralServerSession session = dataService.GetCentralServerSession(null, null, config.GameId);
                        Player tttdPlayer = dataService.GetPlayer(match.PlayerOneId);

                        MoveRequest challengeRequest = new MoveRequest();
                        challengeRequest.GameId = session.CentralServerGameId.Value;
                        challengeRequest.PlayerName = tttdPlayer.PlayerName;
                        challengeRequest.X = 0;
                        challengeRequest.Y = 0;
                        challengeRequest.Flags = CentralServerCommunicationChannel.GetStatus(StatusFlag.ChallengeMove);

                        CentralServerCommunicationChannel.Instance.PostMove(challengeRequest, match.CurrentGameId.Value, match.MatchId);
                    }
                }
            };
        }
        void aiTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            using(IGameDataService gameDataService = new GameDataService())
            {
                IEnumerable<AIAttentionRequiredResult> aiGames = gameDataService.GetAIGamesRequiringAttention();

                //If we have any Games that the AI needs to play, loop through them all.
                //We will notify the AI to play on seperate threads.
                if (aiGames.Any())
                {
                    foreach(var aiGame in aiGames)
                    {
                        BackgroundWorker aiWorker = new BackgroundWorker();
                        aiWorker.DoWork += aiWorker_DoWork;
                        aiWorker.RunWorkerAsync(aiGame);
                        aiWorker.RunWorkerCompleted += (cs,ce) =>
                            {
                                if (ce.Error != null)
                                {
                                    Exception ex = ce.Error;
                                    while (ex.InnerException != null)
                                    {
                                        ex = ex.InnerException;
                                    }

                                    Logger.Instance.Log("CentralServerCommunicationError", string.Format("GameId:{0}|Error:{1}",aiGame.GameId, ex.Message), ce.Error.StackTrace);
                                    using (IGameDataService dataService = new GameDataService())
                                    {
                                        Match match = dataService.GetMatch(null, aiGame.GameId);
                                        CentralServerSession session = dataService.GetCentralServerSession(null, null, aiGame.GameId);
                                        Player tttdPlayer = dataService.GetPlayer(match.PlayerOneId);
                                        GameConfiguration config = GameConfigCache.Instance.GetConfig(match.MatchId);

                                        dataService.EndGame(aiGame.GameId, match.PlayerOneId == aiGame.PlayerId ? match.PlayerTwoId : match.PlayerOneId);
                                        dataService.Save();

                                        if (config.GameType == GameType.Network)
                                        {
                                            MoveRequest challengeRequest = new MoveRequest();
                                            challengeRequest.GameId = session.CentralServerGameId.Value;
                                            challengeRequest.PlayerName = tttdPlayer.PlayerName;
                                            challengeRequest.X = 0;
                                            challengeRequest.Y = 0;
                                            challengeRequest.Flags = CentralServerCommunicationChannel.GetStatus(StatusFlag.AcceptLoss);

                                            CentralServerCommunicationChannel.Instance.PostMove(challengeRequest, match.CurrentGameId.Value, match.MatchId);
                                        }
                                    }
                                }
                            };
                    }
                }
            }
        }
        static void ChallengePlayerCompleted(string data, int matchId)
        {
            var response = JsonSerializer.DeseriaizeFromJSON<ChallengeResponse>(data);
            if (string.IsNullOrEmpty(response.Error))
            {
                Match match;
                CentralServerSession session;
                using (IGameDataService dataService = new GameDataService())
                {
                    match = dataService.GetMatch(matchId, null);
                    session = dataService.GetCentralServerSession(null, null, match.CurrentGameId.Value);

                    dataService.Attach(session);
                    session.CentralServerGameId = response.GameId;
                    dataService.Save();

                    TicTacToeHost.Instance.AcceptChallenge(match.PlayerTwoId, match.MatchId);

                    if (response.YourTurn)
                    {
                        dataService.SetPlayerTurn(match.CurrentGameId.Value, match.PlayerOneId);
                        dataService.Save();
                    }
                    else
                    {
                        dataService.SetPlayerTurn(match.CurrentGameId.Value, match.PlayerTwoId);
                        dataService.Save();
                        TicTacToeHost.Instance.Move(new Move() { GameId = match.CurrentGameId.Value, PlayerId = match.PlayerTwoId, X = response.X, Y = response.Y }, false);
                    }
                }
            }
        }
        static void PostMoveCompleted(string data, int matchId)
        {
            var response = JsonSerializer.DeseriaizeFromJSON<MoveResponse>(data);
            bool newGame = false;
            int gameId;
            int oldGameId;
            Match match;
            Player tttdPlayer;
            CentralServerSession session;
            StatusFlag flag = CentralServerCommunicationChannel.ParseStatus(response.StatusFlag);
            using (IGameDataService dataService = new GameDataService())
            {
                match = dataService.GetMatch(matchId, null);
                session = dataService.GetCentralServerSession(null, null, match.CurrentGameId.Value);
                tttdPlayer = dataService.GetPlayer(match.PlayerOneId);
                oldGameId = match.CurrentGameId.Value;

                if (response.NewGameId != null && response.NewGameId > 0 && response.NewGameId != session.CentralServerGameId)
                {
                    int newGameId = TicTacToeHost.Instance.ConfigureGame(matchId);
                    gameId = newGameId;
                    newGame = true;
                    session = dataService.CreateCentralServerSession(newGameId, response.NewGameId);
                }
                else
                {
                    gameId = match.CurrentGameId.Value;
                }
                dataService.Save();
            }

            if (response.YourTurn
                //|| (newGame && response.X == null && response.Y == null)
                )
            {
                using (IGameDataService dataService = new GameDataService())
                {
                    dataService.SetPlayerTurn(gameId, match.PlayerOneId);
                    dataService.Save();
                }
            }
            else if(flag == StatusFlag.ChallengeMove || flag == StatusFlag.ChallengeWin)
            {
                using (IGameDataService dataService = new GameDataService())
                {
                    dataService.EndGame(oldGameId, null);
                    dataService.Save();
                }
            }
            else if (response.X >= 0 && response.Y >= 0)
            {
                if (flag == StatusFlag.AcceptLoss)
                {
                    using (IGameDataService dataService = new GameDataService())
                    {
                        dataService.EndGame(oldGameId, match.PlayerOneId);
                        dataService.Save();
                    }
                }

                if (newGame)
                {
                    using (IGameDataService dataService = new GameDataService())
                    {
                        dataService.SetPlayerTurn(gameId, match.PlayerTwoId);
                        dataService.Save();
                    }
                }

                Move move = new Move() { GameId = gameId, PlayerId = match.PlayerTwoId };
                GameState state = TicTacToeHost.Instance.GetGameState(gameId, match.PlayerTwoId);
                if (state.Mode == PlayMode.DeathMatch)
                {
                    move.OriginX = response.X;
                    move.OriginY = response.Y;
                    for (int x = 0; x < 3; x++)
                    {
                        for (int y = 0; y < 3; y++)
                        {
                            if (state.GameBoard[x][y] == null || state.GameBoard[x][y] == 0)
                            {
                                move.X = x;
                                move.Y = y;
                            }
                        }
                    }
                }
                else
                {
                    move.X = response.X.Value;
                    move.Y = response.Y.Value;
                }

                MoveResult opponentMoveResult = TicTacToeHost.Instance.Move(move, false);
                GameState postMoveState = TicTacToeHost.Instance.GetGameState(gameId, match.PlayerTwoId);
                if (opponentMoveResult != MoveResult.Valid || flag == StatusFlag.WinningMove || postMoveState.YouWon)
                {
                    MoveRequest challengeRequest = new MoveRequest();
                    challengeRequest.GameId = session.CentralServerGameId.Value;
                    challengeRequest.PlayerName = tttdPlayer.PlayerName;
                    challengeRequest.X = 0;
                    challengeRequest.Y = 0;

                    bool challenging = false;
                    if (opponentMoveResult != MoveResult.Valid)
                    {
                        challengeRequest.Flags = CentralServerCommunicationChannel.GetStatus(StatusFlag.ChallengeMove);
                        challenging = true;
                    }
                    else
                    {
                        if (flag == StatusFlag.WinningMove && !postMoveState.YouWon)
                        {
                            challengeRequest.Flags = CentralServerCommunicationChannel.GetStatus(StatusFlag.ChallengeWin);
                            challenging = true;
                        }
                        else
                        {
                            challengeRequest.Flags = CentralServerCommunicationChannel.GetStatus(StatusFlag.AcceptLoss);
                        }
                    }

                    if (challenging)
                    {
                        using (IGameDataService dataService = new GameDataService())
                        {
                            dataService.EndGame(gameId, null);
                            dataService.Save();
                        }
                    }

                    CentralServerCommunicationChannel.Instance.PostMove(challengeRequest, match.CurrentGameId.Value, match.MatchId);
                }
            }
        }
        void ICommunicationChannel.ChallengePlayer(int matchId)
        {
            using (IGameDataService dataService = new GameDataService())
            {
                //We need to create a session even if the challenge isn't accepted.
                Match match = dataService.GetMatch(matchId, null);
                dataService.CreateCentralServerSession(match.CurrentGameId.Value);

                Player player = dataService.GetPlayer(match.PlayerOneId);
                Player opponent = dataService.GetPlayer(match.PlayerTwoId);
                Game game = dataService.GetGame(match.CurrentGameId.Value);

                var requestData = new ChallengeRequest();
                requestData.PlayerName = player.PlayerName;
                requestData.OpponentName = opponent.PlayerName;

                string requestJSON = JsonSerializer.SerializeToJSON<ChallengeRequest>(requestData);
                var requestConfig = new ServerRequestConfig();
                requestConfig.Url = string.Format("{0}/ServerPairing.php", ConfigurationManager.AppSettings["CentralServerUrl"]);
                requestConfig.RequestData = requestJSON;
                requestConfig.GameId = game.GameId;
                requestConfig.MatchId = game.MatchId;
                requestConfig.ResponseAction = new Action<string, int>(ChallengePlayerCompleted);

                this.PerformServerRequest(requestConfig);
            }
        }
        void ICommunicationChannel.PostMove(int matchId, int x, int y, PlayMode mode)
        {
            using (IGameDataService dataService = new GameDataService())
            {
                Match match = dataService.GetMatch(matchId, null);
                Player player = dataService.GetPlayer(match.PlayerOneId);
                GameState state = TicTacToeHost.Instance.GetGameState(match.CurrentGameId.Value, player.PlayerId);

                int moveCount = dataService.Repository.GetGameMoves().Where(mv => mv.GameId == match.CurrentGameId.Value).GroupBy(mv => mv.MoveDate).Count();

                string flag;
                if (state.Mode == PlayMode.DeathMatch && moveCount == 9)
                {
                    flag = CentralServerCommunicationChannel.GetStatus(StatusFlag.DrawMove);
                }
                else if (state.Mode == PlayMode.DeathMatch && moveCount == 10)
                {
                    flag = CentralServerCommunicationChannel.GetStatus(StatusFlag.AcceptDraw);
                }
                else if (state.Mode == PlayMode.Won)
                {
                    flag = CentralServerCommunicationChannel.GetStatus(StatusFlag.WinningMove);
                }
                else
                {
                    flag = CentralServerCommunicationChannel.GetStatus(StatusFlag.None);
                }

                var requestData = new MoveRequest();
                requestData.PlayerName = player.PlayerName;
                requestData.GameId = -1;
                requestData.Flags = flag;
                requestData.X = x;
                requestData.Y = y;

                CentralServerSession session = dataService.GetCentralServerSession(null, null, match.CurrentGameId.Value);
                if (session != null)
                    requestData.GameId = session.CentralServerGameId.Value;

                this.PostMove(requestData, match.CurrentGameId.Value, match.MatchId);
            }
        }
        private void UpdateChallengeState(int playerId, int matchId, bool? state)
        {
            using (IGameDataService gameDataService = new GameDataService())
            {
                Match match = gameDataService.GetMatch(matchId, null);
                GameConfiguration config = GameConfigCache.Instance.GetConfig(matchId);

                if (match.EndDate == null)
                {
                    gameDataService.Attach(match);

                    bool challengeStateChange = false;
                    if (match.PlayerOneId == playerId && match.PlayerOneAccepted != state)
                    {
                        match.PlayerOneAccepted = state;
                        challengeStateChange = true;
                    }
                    else if (match.PlayerTwoId == playerId && match.PlayerTwoAccepted != state)
                    {
                        match.PlayerTwoAccepted = state;
                        challengeStateChange = true;
                    }

                    if (playerId == match.PlayerOneId || playerId == match.PlayerTwoId && challengeStateChange)
                    {
                        match.StateDate = DateTime.Now;
                        if (match.PlayerOneAccepted == false && match.PlayerTwoAccepted == false)
                        {
                            match.EndDate = match.StateDate;
                        }
                        else if (match.PlayerOneAccepted == true
                            && match.PlayerTwoAccepted == true
                            && config.GameType != GameType.Network)
                        {
                            gameDataService.SetPlayerTurn(match.CurrentGameId.Value, match.PlayerOneId);
                        }
                    }

                    gameDataService.Save();
                }
            }
        }
        public LogViewModel(int matchId)
            : this()
        {
            using (IGameDataService dataService = new GameDataService())
            {
                Match match = dataService.GetMatch(matchId, null);
                Player playerOne = dataService.GetPlayer(match.PlayerOneId);
                Player playerTwo = dataService.GetPlayer(match.PlayerTwoId);
                IEnumerable<Game> games = dataService.GetGamesForMatch(matchId);
                IEnumerable<AuditLog> auditLogs = dataService.GetAllAuditLogsForMatch(matchId);

                LogViewModel.Log matchStartLogEntry = new Log();
                matchStartLogEntry.LogType = "MatchStart";
                matchStartLogEntry.LogDateTime = match.CreateDate;
                matchStartLogEntry.Metadata = string.Format("{0} vs. {1}", playerOne.PlayerName, playerTwo.PlayerName);
                matchStartLogEntry.Message = null;
                this.Logs.Add(matchStartLogEntry);

                if (match.EndDate != null)
                {
                    LogViewModel.Log matchEndLogEntry = new Log();
                    matchEndLogEntry.LogType = match.WinningPlayerId != null ? "MatchWon" : "MatchEnded";
                    matchEndLogEntry.LogDateTime = match.EndDate.Value;
                    if (match.WinningPlayerId != null)
                    {
                        Player winningPlayer = dataService.GetPlayer(match.WinningPlayerId.Value);
                        matchEndLogEntry.Metadata = string.Format("Winner: {0}", winningPlayer.PlayerName);
                    }
                    else
                        matchEndLogEntry.Metadata = "Match ended in error.";

                    this.Logs.Add(matchEndLogEntry);
                }

                foreach (var log in auditLogs)
                {
                    string message = string.Join("", dataService.GetAuditLogSections(log.LogId).OrderBy(section => section.SectionId).Select(section => section.Section));
                    LogViewModel.Log logEntry = new Log();
                    logEntry.LogType = log.LogType;
                    logEntry.LogDateTime = log.LogDateTime;
                    logEntry.Metadata = log.Metadata;
                    logEntry.Message = message;

                    this.Logs.Add(logEntry);
                }

                foreach (var game in games)
                {
                    LogViewModel.Log gameStartLogEntry = new Log();
                    gameStartLogEntry.LogType = "GameStart";
                    gameStartLogEntry.LogDateTime = game.CreateDate;
                    gameStartLogEntry.Metadata = string.Format("Game Id: {0}", game.GameId);
                    gameStartLogEntry.Message = null;
                    this.Logs.Add(gameStartLogEntry);

                    if (game.EndDate != null)
                    {
                        LogViewModel.Log gameEndLogEntry = new Log();
                        gameEndLogEntry.LogType = game.WinningPlayerId != null ? "GameWon" : "GameEnded";
                        gameEndLogEntry.LogDateTime = game.EndDate.Value;
                        if (game.WinningPlayerId != null)
                        {
                            Player winningPlayer = dataService.GetPlayer(game.WinningPlayerId.Value);
                            gameEndLogEntry.Metadata = string.Format("Winner: {0}", winningPlayer.PlayerName);
                        }
                        else
                            gameEndLogEntry.Metadata = "Game ended in error.";

                        this.Logs.Add(gameEndLogEntry);
                    }

                    var moves = dataService.GetGameMoves(game.GameId).GroupBy(mv => new { mv.PlayerId, mv.MoveDate });
                    foreach (var move in moves)
                    {
                        LogViewModel.Log moveLogEntry = new Log();
                        Player movePlayer = dataService.GetPlayer(move.First().PlayerId);

                        moveLogEntry.LogType = "DatabaseMove";
                        moveLogEntry.LogDateTime = move.First().MoveDate;
                        moveLogEntry.Metadata = movePlayer.PlayerName;

                        string message;
                        if (move.Count() >= 2)
                        {
                            GameMove unsetMove = move.FirstOrDefault(uMove => !uMove.IsSettingPiece);
                            GameMove setMove = move.FirstOrDefault(sMove => sMove.IsSettingPiece);

                            message = string.Format("OriginX: {0}, OriginY: {1}, X: {2}, Y: {3}", unsetMove != null ? (int?)unsetMove.X : null
                                                                                                , unsetMove != null ? (int?)unsetMove.y : null
                                                                                                , setMove != null ? (int?)setMove.X : null
                                                                                                , setMove != null ? (int?)setMove.y : null);
                        }
                        else
                        {
                            GameMove setMove = move.First();
                            message = string.Format("X: {0}, Y: {1}", setMove.X, setMove.y);
                        }
                        moveLogEntry.Message = message;
                        this.Logs.Add(moveLogEntry);
                    }
                }
            }
        }
        public MoveResult Move(Move move, bool raiseEvent)
        {
            MoveResult validationResult = this.ValidateMove(move);
            bool canMove = true;
            if (validationResult != MoveResult.Valid)
                canMove = false;

            Logger.Instance.Log("MoveAttempt", string.Format("GameId:{1}|PlayerId:{2}|ValidationResult:{0}", validationResult.ToString(), move.GameId, move.PlayerId), JsonSerializer.SerializeToJSON(move));

            if (!canMove)
                return validationResult;

            Match match;
            GameState currentState = TicTacToeHost.Instance.GetGameState(move.GameId, move.PlayerId);
            using (IGameDataService gameDataService = new GameDataService())
            {
                match = gameDataService.GetMatch(null, move.GameId);
                gameDataService.Move(move.GameId, move.PlayerId, move.OriginX, move.OriginY, move.X, move.Y);
                gameDataService.Save();
            }

            this.UpdateGame(move.GameId);

            if (validationResult == MoveResult.Valid && raiseEvent)
            {
                GameConfiguration config = GameConfigCache.Instance.GetConfig(match.MatchId);
                if (config.GameType == GameType.Network)
                    this.PlayerMove(this, new MoveEventArgs()
                    {
                        MatchId = match.MatchId,
                        PlayerId = move.PlayerId,
                        Mode = currentState.Mode,
                        OriginX = move.OriginX,
                        OriginY = move.OriginY,
                        X = move.X,
                        Y = move.Y
                    });
            }

            return validationResult;
        }
 public bool IsMatchStateChanged(int matchId, string stateDateString)
 {
     using (IGameDataService gameDataService = new GameDataService())
     {
         Match match = gameDataService.GetMatch(matchId, null);
         if (match != null)
             return match.StateDate.ToString("yyyyMMddHHmmssfffff") != stateDateString;
         else
             return false;
     }
 }
        public MatchState GetMatchState(int matchId, int playerId)
        {
            MatchState result = null;

            using (IGameDataService gameDataServcie = new GameDataService())
            {
                Match match = gameDataServcie.GetMatch(matchId, null);

                if (match != null)
                {
                    result = new MatchState();
                    result.MatchId = matchId;
                    result.PlayerId = playerId;
                    result.CurrentGameId = match.CurrentGameId;

                    if ((match.PlayerOneAccepted == null || match.PlayerTwoAccepted == null) && match.WonDate == null && match.EndDate == null)
                        result.Mode = PlayMode.None;
                    else if (match.WonDate == null && match.EndDate == null)
                        result.Mode = PlayMode.Playing;
                    else if (match.WonDate != null)
                        result.Mode = PlayMode.Won;
                    else
                        result.Mode = PlayMode.Ended;

                    result.StateDateString = match.StateDate.ToString("yyyyMMddHHmmssfffff");

                    if (match.WinningPlayerId != null)
                    {
                        Player winner = gameDataServcie.GetPlayer(match.WinningPlayerId.Value);
                        result.YouWon = playerId == match.WinningPlayerId;
                        result.WinningPlayerName = winner.PlayerName;
                    }
                }
            }

            return result;
        }
        ///// <summary>
        ///// Set up a new game between two players. Will return the id of the created game.
        ///// </summary>
        ///// <param name="config">The parameters necessary to set up the game.</param>
        ///// <returns></returns>
        //public int ConfigureGame(GameConfiguration config)
        //{
        //    return ConfigureGame(config, null, true, true);
        //}
        public int ConfigureGame(int matchId)
        {
            using (IGameDataService gameDataService = new GameDataService())
            {
                //Create a game, as well as a match in case the players play multiple games in a row.
                Models.Match match = gameDataService.GetMatch(matchId, null);

                if (match == null)
                    throw new InvalidOperationException("A match is required for game play.");

                Models.Player playerOne = gameDataService.GetPlayer(match.PlayerOneId);
                Models.Player playerTwo = gameDataService.GetPlayer(match.PlayerTwoId);

                Models.Game game = gameDataService.CreateGame(playerOne, playerTwo, match);
                GameConfiguration config = GameConfigCache.Instance.GetConfig(matchId);

                //Make an entry in the table for AI to track the game.
                Models.AIGame aiPlayerOne;
                if (config.PlayerOne.PlayerType == PlayerType.AI)
                    aiPlayerOne = gameDataService.CreateAIGame(playerOne, game, match);

                //We only want to be responsible for managing local AIs.
                //If it's networked, don't record it.
                Models.AIGame aiPlayerTwo;
                if (config.PlayerTwo.PlayerType == PlayerType.AI && config.GameType != GameType.Network)
                    aiPlayerTwo = gameDataService.CreateAIGame(playerTwo, game, match);

                gameDataService.Attach(match);
                match.CurrentGameId = game.GameId;
                match.StateDate = game.StateDate;

                gameDataService.Save();

                return game.GameId;
            }
        }
        public void CancelChallenge(int matchId, string reason)
        {
            using (IGameDataService gameDataService = new GameDataService())
            {
                Match match = gameDataService.GetMatch(matchId, null);
                gameDataService.Attach(match);
                match.EndDate = DateTime.Now;
                match.StateDate = match.EndDate.Value;

                List<Game> matchGames = gameDataService.Repository.GetGames().Where(game => game.MatchId == matchId).ToList();
                foreach (var game in matchGames)
                {
                    if (game.EndDate == null)
                    {
                        gameDataService.Attach(game);
                        game.EndDate = match.EndDate;
                        game.StateDate = match.EndDate.Value;
                    }
                }

                gameDataService.Save();
            }
            Logger.Instance.Log("MatchCancelled", string.Format("match:{0}", matchId), reason);
        }