private void AddOrMatch(UserQueueWrapper queueWrapper)
        {
            UserQueueWrapper otherPlayer = null;

            lock (matchingLock)
            {
                AsyncUserToken          userToken = queueWrapper.Token;
                ServerSideTokenIdentity identity  = (ServerSideTokenIdentity)userToken.info;
                if (userWaitingForMatch == null)
                {
                    userWaitingForMatch        = queueWrapper;
                    identity.MatchmakingStatus = UserMatchmakingStatus.QUEUE;
                }
                else
                {
                    otherPlayer         = userWaitingForMatch;
                    userWaitingForMatch = null;

                    var otherPlayerIdentity = (ServerSideTokenIdentity)otherPlayer.Token.info;

                    identity.MatchmakingStatus = UserMatchmakingStatus.PREPARING_GAME;
                    lock (otherPlayerIdentity.MatchmakingLock)
                    {
                        otherPlayerIdentity.MatchmakingStatus = UserMatchmakingStatus.PREPARING_GAME;
                    }
                }
            }
            if (otherPlayer != null)
            {
                Console.WriteLine("Creating match!");
                GAME_MANAGER.PrepareGame(queueWrapper, otherPlayer);
            }
        }
        public void CancelGamePreparation(AsyncUserToken userToken)
        {
            ServerSideTokenIdentity identity = (ServerSideTokenIdentity)userToken.info;

            lock (identity.MatchmakingLock)
            {
                if (identity.MatchmakingStatus != UserMatchmakingStatus.PREPARING_GAME)
                {
                    return;
                }

                GameWrapper gameWrapper = identity.GameWrapper;

                var game = gameWrapper.Game;

                lock (gameWrapper.@lock)
                {
                    GameCanceledNotification gameCanceledNotification = new GameCanceledNotification();

                    foreach (var token in gameWrapper.Tokens)
                    {
                        if (token != userToken)
                        {
                            Config.GameServer.Send(token, gameCanceledNotification);
                        }
                    }

                    TerminateGame(gameWrapper);
                }
            }
        }
        public override void OnUserConnect(AsyncUserToken userToken)
        {
            ServerSideTokenIdentity identity = (ServerSideTokenIdentity)userToken.info;

            if (userToken.info == null)
            {
                identity       = new ServerSideTokenIdentity();
                userToken.info = identity;
            }
            identity.Token             = userToken;
            identity.MatchmakingStatus = UserMatchmakingStatus.NON_LOGGED;
            Console.WriteLine("User connected");
        }
        public void AddUserToQueue(UserQueueWrapper queueWrapper)
        {
            AsyncUserToken          userToken = queueWrapper.Token;
            ServerSideTokenIdentity identity  = userToken.info as ServerSideTokenIdentity;

            lock (identity.MatchmakingLock)
            {
                if (identity.MatchmakingStatus != UserMatchmakingStatus.LOBBY)
                {
                    throw new MatchmakingException("Korisnik nije u lobiju ili je u redu");
                }
                AddOrMatch(queueWrapper);
            }
        }
        public void SuddenlyEndGameOnPlayerDisconnect(AsyncUserToken userToken)
        {
            ServerSideTokenIdentity identity = (ServerSideTokenIdentity)userToken.info;

            lock (identity.MatchmakingLock)
            {
                if (identity.MatchmakingStatus != UserMatchmakingStatus.GAME)
                {
                    return;
                }

                GameWrapper gameWrapper = identity.GameWrapper;

                var game = gameWrapper.Game;

                if (game.Players.Length != 2)
                {
                    // Only for 2 player games
                    return;
                }

                lock (gameWrapper.@lock)
                {
                    GameFinishedNotification gameFinishedNotification = new GameFinishedNotification();


                    for (int i = 0; i < gameWrapper.Tokens.Length; i++)
                    {
                        var token = gameWrapper.Tokens[i];
                        if (token == userToken)
                        {
                            gameFinishedNotification.WinnerPlayerId = 1 - i;
                            break;
                        }
                    }

                    foreach (var token in gameWrapper.Tokens)
                    {
                        if (token != userToken)
                        {
                            Config.GameServer.Send(token, gameFinishedNotification);
                        }
                    }

                    TerminateGame(gameWrapper);
                }
            }
        }
        public void ExitQueue(AsyncUserToken token)
        {
            ServerSideTokenIdentity identity = (ServerSideTokenIdentity)token.info;

            lock (matchingLock)
            {
                lock (identity.MatchmakingLock)
                {
                    if (userWaitingForMatch == null || userWaitingForMatch.Token != token)
                    {
                        throw new MatchmakingException("Korisnik ne ceka u redu");
                    }
                    identity.MatchmakingStatus = UserMatchmakingStatus.LOBBY;
                    userWaitingForMatch        = null;
                }
            }
        }