/**
         * Handles any client connection changes that occur during each frame update.
         * If the state listener is connected, it will call its update function.
         * If the Controller Interface has any status changes, it will invoke the OnConnected and OnDisconnected callbacks accordingly.
         * If the Controller Interface has any presence events, it will invoke the OnHandlePresence callback.
         * If the Controller Interface receives a game registration event message it will invoke the OnRegistered callback.
         * If the Controller Interface receives a game registration event message it will invoke the OnInitialized callback.
         * Consumes network events and converts them to EscEvent objects to be processed by the controller.
         * Will propagate any client state changes to the server while respecting the state update frequency.
         *
         * @see Esc.Client
         * @see Esc.StateListener
         * @see Esc.ClientConnection.SetStateUpdateFrequency
         */
        public void Update()
        {
            // consume new state changes
            if (this.stateListener.IsConnected())
            {
                this.stateListener.Update();
            }

            // attempt a reconnection if necessary
            if (this.willReconnect)
            {
                this.willReconnect = false;
                ControllerInterface.startClientInterface(ClientConnection.serverAddress);
            }
            else if (!ControllerInterface.isConnected())
            {
                // reconnect?
            }

            // process status changes
            while (ControllerInterface.hasMoreStatusChanges())
            {
                int stat;
                if (0 == ControllerInterface.getNextStatusChange(out stat))
                {
                    switch (stat)
                    {
                    case 0:                     // connected
                        break;

                    case 1:                     // TLS connected
                        break;

                    case 2:                     // disconnected
                        if (null != OnDisconnected)
                        {
                            OnDisconnected();
                        }
                        if (this.autoReconnect)
                        {
                            willReconnect = true;
                        }
                        break;

                    case 3:                     // roster loaded
                        if (null != OnConnected)
                        {
                            OnConnected();
                        }
                        break;

                    case 4:                     // error
                        break;

                    default:
                        break;
                    }
                }
            }

            // process presence events
            while (ControllerInterface.hasMorePresenceEvents())
            {
                StringBuilder user = new StringBuilder(48);
                int           presence;
                if (0 == ControllerInterface.getNextPresenceEvent(user, (uint)user.Capacity, out presence))
                {
                    string username = user.ToString();
                    this.server = new Server(username);
                    if (this.server.Username() == username)
                    {
                        this.server.SetStatus(presence);
                        OnHandlePresence(presence);
                    }
                }
            }

            // process all incoming events
            while (ControllerInterface.hasMoreEvents())
            {
                StringBuilder user    = new StringBuilder(48);
                StringBuilder message = new StringBuilder(256);
                if (0 == ControllerInterface.getNextEvent(user, (uint)user.Capacity, message, (uint)message.Capacity))
                {
                    string username  = user.ToString();
                    string msgString = message.ToString();

                    // handle registration
                    if (msgString.StartsWith(API_KEYWORD_REGISTERED))
                    {
                        string[] commaDelimiter  = new string[] { "," };
                        string   parameterString = msgString.Substring(API_KEYWORD_REGISTERED.Length);
                        string[] parameters      = parameterString.Split(commaDelimiter, StringSplitOptions.None);
                        if (parameters.Length != 3)
                        {
                            Debug.LogError("ClientConnection: Registration message is malformed.");
                        }

                        // Establish connection to server with the remote IP address
                        string remoteIpAddress = parameters[0];
                        this.client.SetRemoteEndpoint(remoteIpAddress);

                        this.clientIndex = Convert.ToInt32(parameters[1]);
                        this.gameId      = parameters[2];

                        // Load different level if game id is different than the game scene name
                        if (!this.gameId.Equals(this.gameSceneName))
                        {
                            if (Application.CanStreamedLevelBeLoaded(this.gameId))
                            {
                                Application.LoadLevel(this.gameId);
                            }
                            break;
                        }

                        string registrationMessage = API_KEYWORD_REGISTERED + this.clientIpAddress;
                        ControllerInterface.dispatchEvent(username, registrationMessage);

                        if (null != OnRegistered)
                        {
                            OnRegistered();
                        }
                    }
                    // handle initialization
                    else if (msgString.StartsWith(API_KEYWORD_INIT))
                    {
                        if (null != OnInitialized)
                        {
                            OnInitialized();
                        }
                    }
                    // handle loading another game
                    else if (msgString.StartsWith(API_KEYWORD_GAME_ID))
                    {
                        string parameterString = msgString.Substring(API_KEYWORD_GAME_ID.Length);
                        if (!parameterString.Equals(this.gameSceneName))
                        {
                            if (Application.CanStreamedLevelBeLoaded(parameterString))
                            {
                                Application.LoadLevel(parameterString);
                            }
                        }
                    }

                    EscEvent evt = EscEvent.FromString(msgString);
                    this.server.AppendEvent(evt);
                }
            }

            // check frequency of state update frequency
            if (cumulativeStateTime > stateUpdateFrequency)
            {
                if (null != this.client && this.client.StateVarsAreStale())
                {
                    this.client.PropagateStateVars(clientIndex);
                }
                cumulativeStateTime = 0.0f;
            }
            else
            {
                cumulativeStateTime += Time.deltaTime;
            }

            // check interval of device update frequency
            if (cumulativeDeviceTime > deviceUpdateFrequency)
            {
                if (ControllerInterface.isDeviceCharging())
                {
                    if (null != OnPlugged)
                    {
                        OnPlugged();
                    }
                    ControllerInterface.dimScreen();
                }
                else
                {
                    if (null != OnUnplugged)
                    {
                        OnUnplugged();
                    }
                    if (ControllerInterface.isDeviceWifiConnected())
                    {
                        if (null != OnWifiConnected)
                        {
                            OnWifiConnected();
                        }
                        ControllerInterface.brightenScreen();
                    }
                    else
                    {
                        if (null != OnWifiDisconnected)
                        {
                            OnWifiDisconnected();
                        }
                        ControllerInterface.dimScreen();
                    }
                }
                cumulativeDeviceTime = 0.0f;
            }
            else
            {
                cumulativeDeviceTime += Time.deltaTime;
            }
        }