/// <summary>
        /// Establish new game session.
        /// If the player is a guest, they must first download the game settings first (not implemented)
        /// </summary>
        /// <returns>True if the establishment is successful or false on failure</returns>
        public void Establish()
        {
            _tokenSource = new CancellationTokenSource();
            _cancelToken = _tokenSource.Token;

            // change multiplayer game state depending on role
            switch (_role)
            {
            case MultiplayerRole.Guest:
                var task = Firebase.Get(GetLink("state"));
                task.Wait();

                // malformed state
                if (!int.TryParse(task.Result, out int _state))
                {
                    Close();
                }
                GameState state = (GameState)_state;
                if (state == GameState.Connecting || state == GameState.Waiting)
                {
                    CurrentData.ChangeGameState(GameState.Playing);
                }

                break;

            case MultiplayerRole.Host:
                CurrentData.ChangeGameState(GameState.Waiting);
                break;
            }

            // overall upload task
            _uploadTask = UploadTask.CreateInstance(_cancelToken);

            // overall download task
            _downloadTask = DownloadTask.CreateInstance(_cancelToken, (result) =>
            {
                // must try here because exception could throw in following code of try block
                try
                {
                    // the result will be merged
                    Logger.Log(result);
                    MergeData(result);
                }
                catch (Exception e)
                {
                    Logger.Log("Exception raised: " + e.Message);
                    Close();
                }
            });

            // main task to initiate both uploading and downloading tasks
            _mainTask = Task.Run(() =>
            {
                PlayerData data = _role == MultiplayerRole.Host ? CurrentData.Host : CurrentData.Guest;
                while (!_cancelToken.IsCancellationRequested)
                {
                    Logger.Log("Doing main task here...");
                    data.Time = TimePlayed;
                    UploadData(data);
                    DownloadData();
                    Thread.Sleep(1000);
                }
            }, _cancelToken);

            // set a running thread for closing connection from another thread
            Task.Run(() =>
            {
                // preventing multiple threads "data racing" with closing this connection
                // only one thread can request closing the connection
                // the thread that is trying to close is actually a part
                // of one player's program that is passively waiting
                // for further instruction on closing the multiplayer game
                // -> the last one to close is the one to delete data, simple
                while (!_requestCloseConnection && !IsConnectionClosed)
                {
                }
                Close(true);
            });
        }