/// <summary>
        ///
        /// </summary>
        /// <param name="ActionId"></param>
        public void CancelRemoteAction(Guid ActionId)
        {
            if (!Client.Connection.IsReadyForData)
            {
                Logger.Log(LogLevel.Info, LogCategory.Main, "Failed to start cancel remote action. No connection.");
                return;
            }

            RemoteActionClientState State = GetActionState(ActionId);

            if (State != null && !State.Completed)
            {
                NetMessage_CancelRemoteAction Msg = new NetMessage_CancelRemoteAction();
                Msg.ActionId = ActionId;
                Client.Connection.Send(Msg);
            }

            RemoveActionState(ActionId);
        }
        /// <summary>
        ///
        /// </summary>
        /// <returns></returns>
        public void Poll()
        {
            for (int i = 0; i < States.Count; i++)
            {
                RemoteActionServerState State = States[i];

                // If this action has been allocated a client, wait for result.
                if (State.AllocatedClient != null)
                {
                    // Client has not updated us in quite a while :(
                    if (TimeUtils.Ticks - State.LastUpdateRecieved > RemoteActionServerState.LastUpdateTimeout)
                    {
                        Logger.Log(LogLevel.Info, LogCategory.Main, "Remote action '{0}' failed as no response has been heard from allocated client.", State.Id.ToString());

                        State.ResultMessage = "Remote client failed to send update in time.";
                        State.Completed     = true;
                        State.Failed        = true;
                        State.Dirty         = true;
                    }

                    // Client who was allocated this action has disconnected, so abort.
                    else if (!State.AllocatedClient.IsConnected)
                    {
                        Logger.Log(LogLevel.Info, LogCategory.Main, "Remote action '{0}' failed as allocated client disconnected.", State.Id.ToString());

                        State.ResultMessage = "Remote client unexpected disconnected.";
                        State.Completed     = true;
                        State.Failed        = true;
                        State.Dirty         = true;
                    }
                }

                // Otherwise send out a solicitation to perform action.
                else
                {
                    // Client who requested this action has disconnected, so abort.
                    if (!State.ForClient.IsConnected)
                    {
                        Logger.Log(LogLevel.Info, LogCategory.Main, "Remote action '{0}' failed as requesting client disconnected.", State.Id.ToString());

                        State.ResultMessage = "Requesting client unexpected disconnected.";
                        State.Completed     = true;
                        State.Failed        = true;
                        State.Dirty         = true;
                    }

                    // Client has cancelled this state.
                    else if (State.Cancelled)
                    {
                        Logger.Log(LogLevel.Info, LogCategory.Main, "Remote action '{0}' failed as client cancelled it.", State.Id.ToString());

                        State.ResultMessage = "Cancelled by user.";
                        State.Completed     = true;
                        State.Failed        = true;
                        State.Dirty         = true;

                        // Tell client allocated the job to cancel.
                        if (State.AllocatedClient != null && State.AllocatedClient.IsConnected)
                        {
                            NetMessage_CancelRemoteAction Msg = new NetMessage_CancelRemoteAction();
                            Msg.ActionId = State.Id;
                            State.AllocatedClient.Send(Msg);
                        }
                    }

                    // Send new solicitation.
                    else if (TimeUtils.Ticks - State.LastSolicitBroadcast > RemoteActionServerState.SolicitInterval)
                    {
                        Logger.Log(LogLevel.Info, LogCategory.Main, "Remote action '{0}' sending new solicitation request.", State.Id.ToString());

                        List <NetConnection> Clients = Server.ListenConnection.AllClients;
                        foreach (NetConnection ClientConnection in Clients)
                        {
                            if (ClientConnection != State.ForClient && ClientConnection.Metadata != null)
                            {
                                ServerConnectedClient ClientState = ClientConnection.Metadata as ServerConnectedClient;
                                if (ClientState.AllowRemoteActions)
                                {
                                    NetMessage_SolicitRemoteAction Msg = new NetMessage_SolicitRemoteAction();
                                    Msg.ActionId = State.Id;
                                    Msg.Type     = State.Type;
                                    Msg.Settings = State.Settings;
                                    ClientConnection.Send(Msg);
                                }
                            }
                        }

                        State.LastSolicitBroadcast = TimeUtils.Ticks;
                    }

                    // Nobody responded saying they can perform the action :|
                    else if (TimeUtils.Ticks - State.RecievedTime > RemoteActionServerState.SolicitTimeout)
                    {
                        Logger.Log(LogLevel.Info, LogCategory.Main, "Remote action '{0}' failed as nobody responded to solicitation.", State.Id.ToString());

                        State.ResultMessage = "No remote clients accepted request.";
                        State.Completed     = true;
                        State.Failed        = true;
                        State.Dirty         = true;
                    }

                    // We have a client who can do the job!
                    else if (State.SolicitationReplies.Count > 0 && TimeUtils.Ticks - State.LastSolicitBroadcast > RemoteActionServerState.MinSolicitWait)
                    {
                        Logger.Log(LogLevel.Info, LogCategory.Main, "Remote action '{0}' recieved solicitation reply and is starting.", State.Id.ToString());

                        State.AllocatedClient = State.SolicitationReplies[SolicitSelectionRandom.Next(0, State.SolicitationReplies.Count - 1)];
                        State.SolicitationReplies.Clear();
                        State.LastUpdateRecieved = TimeUtils.Ticks;

                        NetMessage_RequestRemoteAction Msg = new NetMessage_RequestRemoteAction();
                        Msg.ActionId = State.Id;
                        Msg.Type     = State.Type;
                        Msg.Settings = State.Settings;
                        State.AllocatedClient.Send(Msg);
                    }
                }

                // Send progress update to the client.
                if (TimeUtils.Ticks - State.LastUpdateSent > RemoteActionServerState.UpdateInterval || State.Dirty)
                {
                    if (State.ForClient.IsConnected)
                    {
                        if (State.Completed || TimeUtils.Ticks - State.LastUpdateSent > RemoteActionClientState.MinUpdateInterval)
                        {
                            NetMessage_RemoteActionProgress Msg = new NetMessage_RemoteActionProgress();
                            Msg.ActionId      = State.Id;
                            Msg.Completed     = State.Completed;
                            Msg.Failed        = State.Failed;
                            Msg.ResultMessage = State.ResultMessage;
                            Msg.Progress      = State.Progress;
                            Msg.ProgressText  = State.ProgressText;
                            State.ForClient.Send(Msg);

                            State.LastUpdateSent = TimeUtils.Ticks;
                        }
                    }

                    State.Dirty = false;

                    // If completed, clean up state.
                    if (State.Completed)
                    {
                        RemoveActionState(State.Id);
                    }
                }
            }
        }