//////////////////////////////////////////////////////////////////////////////////////
//    akashi - a server for Attorney Online 2                                       //
//    Copyright (C) 2020  scatterflower                                             //
//                                                                                  //
//    This program is free software: you can redistribute it and/or modify          //
//    it under the terms of the GNU Affero General Public License as                //
//    published by the Free Software Foundation, either version 3 of the            //
//    License, or (at your option) any later version.                               //
//                                                                                  //
//    This program is distributed in the hope that it will be useful,               //
//    but WITHOUT ANY WARRANTY; without even the implied warranty of                //
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                 //
//    GNU Affero General Public License for more details.                           //
//                                                                                  //
//    You should have received a copy of the GNU Affero General Public License      //
//    along with this program.  If not, see <https://www.gnu.org/licenses/>.        //
//////////////////////////////////////////////////////////////////////////////////////
#ifndef AOCLIENT_H
#define AOCLIENT_H

#include <algorithm>

#include <QDateTime>
#include <QHostAddress>
#include <QRegularExpression>
#include <QTimer>
#include <QtGlobal>

#include "include/acl_roles_handler.h"
#include "include/network/aopacket.h"
#include "include/network/network_socket.h"

class AreaData;
class DBManager;
class MusicManager;
class Server;
class NetworkSocket;
class AOPacket;

/**
 * @brief Represents a client connected to the server running Attorney Online 2 or one of its derivatives.
 */
class AOClient : public QObject
{
    Q_OBJECT

  public:
    /**
     * @brief Describes a command's details.
     */
    struct CommandInfo
    {
        QVector<ACLRole::Permission> acl_permissions; //!< The permissions necessary to be able to run the command. @see ACLRole::Permission.
        int minArgs;                                  //!< The minimum mandatory arguments needed for the command to function.
        void (AOClient::*action)(int, QStringList);
    };

    /**
     * @property CommandInfo::action
     *
     * @brief A function reference that contains what the command actually does.
     *
     * @param int When called, this parameter will be filled with the argument count. @anchor commandArgc
     * @param QStringList When called, this parameter will be filled the list of arguments. @anchor commandArgv
     */

    /**
     * @brief The list of commands available on the server.
     *
     * @details Generally called with the format of `/command parameters` in the out-of-character chat.
     * @showinitializer
     *
     * @tparam QString The name of the command, without the leading slash.
     * @tparam CommandInfo The details of the command.
     * See @ref CommandInfo "the type's documentation" for more details.
     */
    static const QMap<QString, CommandInfo> COMMANDS;

    /**
     * @brief Creates an instance of the AOClient class.
     *
     * @param p_server A pointer to the Server instance where the client is joining to.
     * @param p_socket The socket associated with the AOClient.
     * @param user_id The user ID of the client.
     * @param parent Qt-based parent, passed along to inherited constructor from QObject.
     */
    AOClient(Server *p_server, NetworkSocket *socket, QObject *parent = nullptr, int user_id = 0, MusicManager *p_manager = nullptr);

    /**
     * @brief Destructor for the AOClient instance.
     *
     * @details Sets the socket to delete later.
     */
    ~AOClient();

    /**
     * @brief Getter for the client's IPID.
     *
     * @return The IPID.
     *
     * @see #ipid
     */
    QString getIpid() const;

    /**
     * @brief Getter for the client's HWID.
     *
     * @return The HWID.
     *
     * @see #hwid
     */
    QString getHwid() const;

    /**
     * @brief Returns true if the client has completed the participation handshake. False otherwise.
     *
     * @return True if the client has completed the participation handshake. False otherwise.
     */
    bool hasJoined() const;

    /**
     * @brief Returns true if the client has logged-in as a role.
     *
     * @return True if loggged-in, false otherwise.
     */
    bool isAuthenticated() const;

    /**
     * @brief Calculates the client's IPID based on a hashed version of its IP.
     */
    void calculateIpid();

    /**
     * @brief Getter for the pointer to the server.
     *
     * @return See brief description.
     *
     * @note Unused. There isn't really a point to this existing, either.
     *
     * @see #server
     */
    Server *getServer();

    /**
     * @brief The user ID of the client.
     */
    int m_id;

    /**
     * @brief The IP address of the client.
     */
    QHostAddress m_remote_ip;

    /**
     * @brief The stored character password for the client, used to be able to select passworded characters.
     */
    QString m_password;

    /**
     * @brief True if the client is actually in the server.
     *
     * @details To explain: In AO, clients immediately establish connection to the server when the user clicks on the server's name in the server
     * browser. Thus, as the user browses servers, they constantly connect and disconnect to and from servers.
     *
     * The purpose of this variable is to determine if the user isn't just doing that, but has actually double-clicked the server, and
     * its client has sent the standard handshake packets, which does signify that the client intended to 'join' this server.
     */
    bool m_joined;

    /**
     * @brief The ID of the area the client is currently in.
     */
    int m_current_area;

    /**
     * @brief The internal name of the character the client is currently using.
     */
    QString m_current_char;

    /**
     * @brief The internal name of the character the client is iniswapped to.
     *
     * @note This will be the same as current_char if the client is not iniswapped.
     */
    QString m_current_iniswap;

    /**
     * @brief If using advanced authentication, this is the moderator name that the client has logged in with.
     */
    QString m_moderator_name = "";

    /**
     * @brief The out-of-character name of the client, generally the nickname of the user themself.
     */
    QString m_ooc_name = "";

    /**
     * @brief The custom showname of the client, used when "renaming" already existing characters in-character.
     */
    QString m_showname = "";

    /**
     * @brief If true, the client is willing to receive global messages.
     *
     * @see AOClient::cmdG and AOClient::cmdToggleGlobal
     */
    bool m_global_enabled = true;

    /**
     * @brief If true, the client's messages will be sent in first-person mode.
     *
     * @see AOClient::cmdFirstPerson
     */
    bool m_first_person = false;

    /**
     * @brief If true, the client may not use in-character chat.
     */
    bool m_is_muted = false;

    /**
     * @brief If true, the client may not use out-of-character chat.
     */
    bool m_is_ooc_muted = false;

    /**
     * @brief If true, the client may not use the music list.
     */
    bool m_is_dj_blocked = false;

    /**
     * @brief If true, the client may not use the judge controls.
     */
    bool m_is_wtce_blocked = false;

    /**
     * @brief Represents the client's client software, and its version.
     *
     * @note Though the version number and naming scheme looks vaguely semver-like,
     * do not be misled into thinking it is that.
     */
    struct ClientVersion
    {
        QString string;   //!< The name of the client software, for example, `AO2`.
        int release = -1; //!< The 'release' part of the version number. In Attorney Online's case, this is fixed at `2`.
        int major = -1;   //!< The 'major' part of the version number. In Attorney Online's case, this increases when a new feature is introduced (generally).
        int minor = -1;   //!< The 'minor' part of the version number. In Attorney Online's case, this increases for bugfix releases (generally).
    };

    /**
     * @brief The software and version of the client.
     *
     * @see The struct itself for more details.
     */
    ClientVersion m_version;

    /**
     * @brief A list of 5 casing preferences (def, pro, judge, jury, steno)
     */
    QList<bool> m_casing_preferences = {false, false, false, false, false};

    /**
     * @brief If true, the client's in-character messages will have their word order randomised.
     */
    bool m_is_shaken = false;

    /**
     * @brief If true, the client's in-character messages will have their vowels (English alphabet only) removed.
     */
    bool m_is_disemvoweled = false;

    /**
     * @brief If true, the client's in-character messages will be overwritten by a randomly picked predetermined message.
     */
    bool m_is_gimped = false;

    /**
     * @brief If true, the client will be marked as AFK in /getarea. Automatically applied when a configurable
     * amount of time has passed since the last interaction, or manually applied by /afk.
     */
    bool m_is_afk = false;

    /**
     * @brief If true, the client will not recieve PM messages.
     */
    bool m_pm_mute = false;

    /**
     * @brief If true, the client will recieve advertisements.
     */
    bool m_advert_enabled = true;

    /**
     * @brief If true, the client is restricted to only changing into certain characters.
     */
    bool m_is_charcursed = false;

    /**
     * @brief Timer for tracking user interaction. Automatically restarted whenever a user interacts (i.e. sends any packet besides CH)
     */
    QTimer *m_afk_timer;

    /**
     * @brief The list of char IDs a charcursed player is allowed to switch to.
     */
    QList<int> m_charcurse_list;

    /**
     * @brief Temporary client permission if client is allowed to save a testimony to server storage.
     */
    bool m_testimony_saving = false;

    /**
     * @brief If true, the client's next OOC message will be interpreted as a moderator login.
     */
    bool m_is_logging_in = false;

    /**
     * @brief If true, the client is a spectator and his IC interactions will be limtied.
     */
    bool m_is_spectator = true;

    /**
     * @brief The hardware ID of the client.
     *
     * @details Generated based on the client's own supplied hardware ID.
     * The client supplied hardware ID is generally a machine unique ID.
     */
    QString m_hwid;

    /**
     * @brief The network socket used by the client. Can either be a Websocket or TCP Socket.
     */
    NetworkSocket *m_socket;

    /**
     * @brief The IPID of the client.
     *
     * @details Generated based on the client's IP, but cannot be reversed to identify the client's IP.
     */
    QString m_ipid;

    /**
     * @brief The type of area update, used for area update (ARUP) packets.
     */
    enum ARUPType
    {
        PLAYER_COUNT, //!< The packet contains player count updates.
        STATUS,       //!< The packet contains area status updates.
        CM,           //!< The packet contains updates about who's the CM of what area.
        LOCKED        //!< The packet contains updates about what areas are locked.
    };

    /**
     * @brief Checks if the client's ACL role has permission for the given permission.
     *
     * @param f_permission The permission flags.
     *
     * @return True if the client has permission, false otherwise.
     */
    bool checkPermission(ACLRole::Permission f_permission) const;

    /**
     * @brief Returns if the client is a spectator.
     *
     * @return True if the client is a spectator, false otherwise.
     */
    bool isSpectator() const;

    /**
     * @brief Sets the spectator state for the client.
     *
     * @param f_spectator
     */
    void setSpectator(bool f_spectator);

    /**
     * @brief Sends or announces an ARUP update.
     *
     * @param type The type of ARUP to send.
     * @param broadcast If true, the update is sent out to all clients on the server. If false, it is only sent to this client.
     *
     * @see AOClient::ARUPType
     */
    void arup(ARUPType type, bool broadcast);

    /**
     * @brief Sends all four types of ARUP to the client.
     */
    void fullArup();
    /**
     * @brief Sends an out-of-character message originating from the server to the client.
     *
     * @param message The text of the message to send.
     */
    void sendServerMessage(QString message);

    /**
     * @brief Like with AOClient::sendServerMessage(), but to every client in the client's area.
     *
     * @param message The text of the message to send.
     */
    void sendServerMessageArea(QString message);

    /**
     * @brief Like with AOClient::sendServerMessage(), but to every client in the server.
     *
     * @param message The text of the message to send.
     */
    void sendServerBroadcast(QString message);

    /**
     * @brief Calls AOClient::updateEvidenceList() for every client in the current client's area.
     *
     * @param area The current client's area.
     */
    void sendEvidenceList(AreaData *area) const;

    /**
     * @brief Updates the evidence list in the area for the client.
     *
     * @param area The client's area.
     */
    void updateEvidenceList(AreaData *area);

    /**
     * @brief Removes excessive combining characters from a text.
     *
     * @param p_text The text to clear of its excessive combining characters.
     *
     * @return See brief description.
     *
     * @see https://en.wikipedia.org/wiki/Zalgo_text
     */
    QString dezalgo(QString p_text);

    /**
     * @brief Checks if the client can modify the evidence in the area.
     *
     * @param area The client's area.
     *
     * @return True if the client can modify the evidence, false if not.
     */
    bool checkEvidenceAccess(AreaData *area);

    /**
     * @brief Changes the client's character.
     *
     * @param char_id The character ID of the client's new character.
     */
    bool changeCharacter(int char_id);

    /**
     * @brief A helper function for logging in a client as moderator.
     *
     * @param message The OOC message the client has sent.
     */
    void loginAttempt(QString message);

    /**
     * @brief Changes the area the client is in.
     *
     * @param new_area The ID of the new area.
     */
    void changeArea(int new_area);

    /**
     * @brief Handles an incoming command, checking for authorisation and minimum argument count.
     *
     * @param command The incoming command.
     * @param argc The amount of arguments the command was called with. Equivalent to `argv.size()`.
     * @param argv The arguments the command was called with.
     */
    void handleCommand(QString command, int argc, QStringList argv);

    /**
     * @brief A helper function for decoding AO encoding from a QString.
     *
     * @param incoming_message QString to be decoded.
     */
    QString decodeMessage(QString incoming_message);

    /**
     * @brief Adds the last send IC-Message to QVector of the respective area.
     *
     * @details This one pulls double duty to both append IC-Messages to the QVector or insert them, depending on the current recorder enum.
     *
     * @param packet The MS-Packet being recorded with their color changed to green.
     */
    void addStatement(QStringList packet);

    /**
     * @brief Updates the currently displayed IC-Message with the next one send
     * @param packet The IC-Message that will overwrite the currently stored one.
     * @return Returns the updated IC-Message to be send to the other users. It also changes the color to green.
     */
    QStringList updateStatement(QStringList packet);

    /**
     * @brief Convenience function to generate a random integer number between the given minimum and maximum values.
     *
     * @param min The minimum possible value for the random integer, inclusive.
     * @param max The maximum possible value for the random integer, exclusive.
     *
     * @warning `max` must be greater than `min`.
     *
     * @return A randomly generated integer within the bounds given.
     */
    int genRand(int min, int max);

    /**
     * @brief A helper function to add recorded packets to an area's judgelog.
     *
     * @param area Pointer to the area where the packet was sent.
     *
     * @param client Pointer to the client that sent the packet.
     *
     * @param action String containing the info that is being recorded.
     */
    void updateJudgeLog(AreaData *area, AOClient *client, QString action);

    /**
     * @brief Pointer to the servers music manager instance.
     */
    MusicManager *m_music_manager;

    /**
     * @brief The text of the last in-character message that was sent by the client.
     *
     * @details Used to determine if the incoming message is a duplicate.
     */
    QString m_last_message;

    /**
     * @brief The time in seconds since the client last sent a Witness Testimony / Cross Examination
     * popup packet.
     *
     * @details Used to filter out potential spam.
     */
    long m_last_wtce_time;

    /**
     * @name Packet helper global variables
     */
    ///@{

    /**
     * @brief If true, the client is a logged-in moderator.
     */
    bool m_authenticated = false;

    /**
     * @brief The ACL role identifier, used to determine what ACL role the client is linked to.
     */
    QString m_acl_role_id;

    /**
     * @brief The character ID of the other character that the client wants to pair up with.
     *
     * @details Though this uses character ID, a client with *that* character ID must exist in the area for the pairing to work.
     * Furthermore, the owner of that character ID must also do the reverse to this client, making their `pairing_with` equal
     * to this client's character ID.
     */
    int m_pairing_with = -1;

    /**
     * @brief The name of the emote last used by the client. No extension.
     *
     * @details This is used for pairing mainly, for the server to be able to craft a smooth-looking transition from one
     * paired-up client talking to the next.
     */
    QString m_emote = "";

    /**
     * @brief The amount the client was last offset by.
     *
     * @details This used to be just a plain number ranging from -100 to 100, but then Crystal mangled it by building some extra data into it.
     * Cheers, love.
     */
    QString m_offset = "";

    /**
     * @brief The last flipped state of the client.
     */
    QString m_flipping = "";

    /**
     * @brief The last reported position of the client.
     */
    QString m_pos = "";

    ///@}

    /**
     * @brief The client's character ID.
     *
     * @details A character ID is just the character's index in the server's character list.
     *
     * In general, the client assumes that this is a continuous block starting from 0.
     */
    int m_char_id = -1;

    /**
     * @brief The spectator character ID
     *
     * @details You may assume that AO has a sane way to determine if a user is a spectator
     * or an actual player. Well, to nobodys surprise, this is not the case, so the character id -1 is used
     * to determine if a client has entered spectator or user mode. I am making this a const mostly
     * for the case this could change at some point in the future, but don't count on it.
     */
    const int SPECTATOR_ID = -1;

  public slots:
    /**
     * @brief Handles an incoming packet, checking for authorisation and minimum argument count.
     *
     * @param packet The incoming packet.
     */
    void handlePacket(AOPacket *packet);

    /**
     * @brief A slot for when the client disconnects from the server.
     */
    void clientDisconnected();

    /**
     * @brief A slot for sending a packet to the client.
     *
     * @param packet The packet to send.
     */
    void sendPacket(AOPacket *packet);

    /**
     * @overload
     */
    void sendPacket(QString header, QStringList contents);

    /**
     * @overload
     */
    void sendPacket(QString header);

    /**
     * @brief A slot for when the client's AFK timer runs out.
     */
    void onAfkTimeout();

  signals:
    /**
     * @brief This signal is emitted when the client has completed the participation handshake.
     */
    void joined();

  private:
    /**
     * @brief A pointer to the Server, used for updating server variables that depend on the client (e.g. amount of players in an area).
     */
    Server *server;

    /**
     * @brief Changes the client's in-character position.
     *
     * @param new_pos The new position of the client.
     */
    void changePosition(QString new_pos);

    /**
     * @name Packet helper functions
     */
    ///@{

    ///@}

    /**
     * @property PacketInfo::action
     *
     * @brief A function reference that contains what the packet actually does.
     *
     * @param AreaData This is always just a reference to the data of the area the sender client is in. Used by some packets.
     * @param int When called, this parameter will be filled with the argument count.
     * @param QStringList When called, this parameter will be filled the list of arguments.
     * @param AOPacket This is a duplicated version of the QStringList above, containing the same data.
     */

    /**
     * @name Authentication
     */
    ///@{

    /**
     * @brief Sets the client to be in the process of logging in, setting is_logging_in to **true**.
     *
     * @details No arguments.
     *
     * @iscommand
     */
    void cmdLogin(int argc, QStringList argv);

    /**
     * @brief Starts the authorisation type change from `"simple"` to `"advanced"`.
     *
     * @details No arguments.
     *
     * @iscommand
     */
    void cmdChangeAuth(int argc, QStringList argv);

    /**
     * @brief Sets the root user's password.
     *
     * @details Accepts a single argument that will be the **root user's password**.
     *
     * @iscommand
     *
     * @pre AOClient::cmdChangeAuth()
     */
    void cmdSetRootPass(int argc, QStringList argv);

    /**
     * @brief Adds a user to the moderators in `"advanced"` authorisation type.
     *
     * @details The first argument is the **user's name**, the second is their **password**.
     *
     * @iscommand
     */
    void cmdAddUser(int argc, QStringList argv);

    /**
     * @brief Removes a user from the moderators in `"advanced"` authorisation type.
     *
     * @details Takes the **targer user's name** as the argument.
     *
     * @iscommand
     */
    void cmdRemoveUser(int argc, QStringList argv);

    /**
     * @brief Lists the permission of a given user.
     *
     * @details If called without argument, lists the caller's permissions.
     *
     * If called with one argument, **a username**, lists that user's permissions.
     *
     * @iscommand
     */
    void cmdListPerms(int argc, QStringList argv);

    /**
     * @brief Sets the role of the user.
     *
     * @details The first argument is the **target user**, the second is the **role** (in string form) to set to that user.
     *
     * @iscommand
     */
    void cmdSetPerms(int argc, QStringList argv);

    /**
     * @brief Removes the role from a given user.
     *
     * @details The first argument is the **target user**, the second is the **permission** (in string form) to remove from that user.
     *
     * @iscommand
     */
    void cmdRemovePerms(int argc, QStringList argv);

    /**
     * @brief Lists all users in the server's database.
     *
     * @details No arguments.
     *
     * @iscommand
     */
    void cmdListUsers(int argc, QStringList argv);

    /**
     * @brief Logs the caller out from their moderator user.
     *
     * @details No arguments.
     *
     * @iscommand
     */
    void cmdLogout(int argc, QStringList argv);

    /**
     * @brief Changes a moderator's password.
     *
     * @details If it is called with **one argument**, that argument is the **new password** to change to.
     *
     * If it is called with **two arguments**, the first argument is the **new password** to change to,
     * and the second argument is the **username** of the moderator to change the password of.
     */
    void cmdChangePassword(int argc, QStringList argv);

    ///@}

    /**
     * @name Areas
     *
     * @brief All functions that detail the actions of commands,
     * that are also related to area management.
     */
    ///@{

    /**
     * @brief Promotes a client to CM status.
     *
     * @details If called without arguments, promotes the caller.
     *
     * If called with a **user ID** as an argument, and the caller is a CM, promotes the target client to CM status.
     *
     * @iscommand
     */
    void cmdCM(int argc, QStringList argv);

    /**
     * @brief Removes the CM status from the caller.
     *
     * @details No arguments.
     *
     * @iscommand
     */
    void cmdUnCM(int argc, QStringList argv);

    /**
     * @brief Invites a client to the area.
     *
     * @details Needs a **user ID** as an argument.
     *
     * @iscommand
     *
     * @see AreaData::LOCKED and AreaData::SPECTATABLE for the benefits of being invited.
     */
    void cmdInvite(int argc, QStringList argv);

    /**
     * @brief Uninvites a client to the area.
     *
     * @details Needs a **user ID** as an argument.
     *
     * @iscommand
     *
     * @see AreaData::LOCKED and AreaData::SPECTATABLE for the benefits of being invited.
     */
    void cmdUnInvite(int argc, QStringList argv);

    /**
     * @brief Locks the area.
     *
     * @details No arguments.
     *
     * @iscommand
     *
     * @see AreaData::LOCKED
     */
    void cmdLock(int argc, QStringList argv);

    /**
     * @brief Sets the area to spectatable.
     *
     * @details No arguments.
     *
     * @iscommand
     *
     * @see AreaData::SPECTATABLE
     */
    void cmdSpectatable(int argc, QStringList argv);

    /**
     * @brief Unlocks the area.
     *
     * @details No arguments.
     *
     * @iscommand
     *
     * @see AreaData::FREE
     */
    void cmdUnLock(int argc, QStringList argv);

    /**
     * @brief Lists all clients in all areas.
     *
     * @details No arguments.
     *
     * @iscommand
     */
    void cmdGetAreas(int argc, QStringList argv);

    /**
     * @brief Lists all clients in the area the caller is in.
     *
     * @details No arguments.
     *
     * @iscommand
     */
    void cmdGetArea(int argc, QStringList argv);

    /**
     * @brief Moves the caller to the area with the given ID.
     *
     * @details Takes an **area ID** as an argument.
     *
     * @iscommand
     */
    void cmdArea(int argc, QStringList argv);

    /**
     * @brief Kicks a client from the area, moving them back to the default area.
     *
     * @details Takes one argument, the **client's ID** to kick.
     *
     * @iscommand
     */
    void cmdAreaKick(int argc, QStringList argv);

    /**
     * @brief Changes the background of the current area.
     *
     * @details Takes the **background's internal name** (generally the background's directory's name for the clients) as the only argument.
     *
     * @iscommand
     */
    void cmdSetBackground(int argc, QStringList argv);

    /**
     * @brief Locks the background, preventing it from being changed.
     *
     * @details No arguments.
     *
     * @iscommand
     */
    void cmdBgLock(int argc, QStringList argv);

    /**
     * @brief Unlocks the background, allowing it to be changed again.
     *
     * @details No arguments.
     *
     * @iscommand
     */
    void cmdBgUnlock(int argc, QStringList argv);

    /**
     * @brief Changes the status of the current area.
     *
     * @details Takes a **status** as an argument. See AreaData::Status for permitted values.
     *
     * @iscommand
     */
    void cmdStatus(int argc, QStringList argv);

    /**
     * @brief Sends an out-of-character message with the judgelog of an area.
     *
     * @details No arguments.
     *
     * @iscommand
     */
    void cmdJudgeLog(int argc, QStringList argv);

    /**
     * @brief Toggles whether the BG list is ignored in an area.
     *
     * @details No arguments.
     *
     * @iscommand
     */
    void cmdIgnoreBgList(int argc, QStringList argv);

    /**
     * @brief Returns the area message in OOC. Double to set the current area message.
     *
     * @details See short description.
     *
     * @iscommand
     */
    void cmdAreaMessage(int argc, QStringList argv);

    /**
     * @brief Clears the areas message and disables automatic sending.
     *
     * @details No arguments.
     *
     * @iscommand
     */
    void cmdClearAreaMessage(int argc, QStringList argv);

    /**
     * @brief Toggles wether the client shows the area message when joining the current area.
     *
     * @details No arguments.
     *
     * @iscommand
     */
    void cmdToggleAreaMessageOnJoin(int argc, QStringList argv);

    /**
     * @brief Toggles wether the client can use testimony animations in the area.
     *
     * @details No arguments.
     *
     * @iscommand
     */
    void cmdToggleWtce(int argc, QStringList argv);

    /**
     * @brief Toggles wether the client can send game shouts in the area.
     *
     * @details No arguments.
     *
     * @iscommand
     */
    void cmdToggleShouts(int argc, QStringList argv);

    ///@}

    /**
     * @name Moderation
     *
     * @brief All functions that detail the actions of commands,
     * that are also related to the moderation and administration of the server.
     */
    ///@{

    /**
     * @brief Lists all the commands that the caller client has the permissions to use.
     *
     * @details No arguments.
     *
     * @iscommand
     */
    void cmdCommands(int argc, QStringList argv);

    /**
     * @brief Lists help information to the command requested. Includes syntax and brief explanation.
     *
     * @details Takes the command name as an argument.
     */
    void cmdHelp(int argc, QStringList argv);

    /**
     * @brief Gets the server's Message Of The Day.
     *
     * @iscommand
     */
    void cmdMOTD(int argc, QStringList argv);

    /**
     * @brief Sets the server's Message Of The Day.
     *
     * @iscommand
     */
    void cmdSetMOTD(int argc, QStringList argv);

    /**
     * @brief Gives a very brief description of Akashi.
     *
     * @details No arguments.
     *
     * @iscommand
     */
    void cmdAbout(int argc, QStringList argv);

    /**
     * @brief Lists the currently logged-in moderators on the server.
     *
     * @details No arguments.
     *
     * @iscommand
     */
    void cmdMods(int argc, QStringList argv);

    /**
     * @brief Bans a client from the server, forcibly severing its connection to the server,
     * and disallowing their return.
     *
     * @details The first argument is the **target's IPID**, the second is the **duration**,
     * and the third is the **reason** why the client was banned.
     *
     * The duration can be `perma`, meaning a forever ban, otherwise, it must be given in the format of `YYyWWwDDdHHhMMmSSs` to
     * mean a YY years, WW weeks, DD days, HH hours, MM minutes and SS seconds long ban. Any of these may be left out, for example,
     * `1h30m` for a 1.5 hour long ban.
     *
     * Besides banning, this command kicks all clients having the given IPID,
     * thus a multiclienting user will have all their clients be kicked from the server.
     *
     * The target's hardware ID is also recorded in a ban, so users with dynamic IPs will not be able to
     * cirvumvent the ban without also changing their hardware ID.
     *
     * @iscommand
     */
    void cmdBan(int argc, QStringList argv);

    /**
     * @brief Removes a ban from the database.
     *
     * @details Takes a single argument, the **ID** of the ban.
     *
     * @iscommand
     */
    void cmdUnBan(int argc, QStringList argv);

    /**
     * @brief Kicks a client from the server, forcibly severing its connection to the server.
     *
     * @details The first argument is the **target's IPID**, while the remaining arguments are the **reason**
     * the client was kicked. Both arguments are mandatory.
     *
     * This command kicks all clients having the given IPID, thus a multiclienting user will have all
     * their clients be kicked from the server.
     *
     * @iscommand
     */
    void cmdKick(int argc, QStringList argv);

    /**
     * @brief Mutes a client.
     *
     * @details The only argument is the **target client's user ID**.
     *
     * @iscommand
     *
     * @see #is_muted
     */
    void cmdMute(int argc, QStringList argv);

    /**
     * @brief Removes the muted status from a client.
     *
     * @details The only argument is the **target client's user ID**.
     *
     * @iscommand
     *
     * @see #is_muted
     */
    void cmdUnMute(int argc, QStringList argv);

    /**
     * @brief OOC-mutes a client.
     *
     * @details The only argument is the **target client's user ID**.
     *
     * @iscommand
     *
     * @see #is_ooc_muted
     */
    void cmdOocMute(int argc, QStringList argv);

    /**
     * @brief Removes the OOC-muted status from a client.
     *
     * @details The only argument is the **target client's user ID**.
     *
     * @iscommand
     *
     * @see #is_ooc_muted
     */
    void cmdOocUnMute(int argc, QStringList argv);

    /**
     * @brief WTCE-blocks a client.
     *
     * @details The only argument is the **target client's user ID**.
     *
     * @iscommand
     *
     * @see #is_wtce_blocked
     */
    void cmdBlockWtce(int argc, QStringList argv);

    /**
     * @brief Removes the WTCE-blocked status from a client.
     *
     * @details The only argument is the **target client's user ID**.
     *
     * @iscommand
     *
     * @see #is_wtce_blocked
     */
    void cmdUnBlockWtce(int argc, QStringList argv);

    /**
     * @brief Lists the last five bans made on the server.
     *
     * @details No arguments.
     *
     * @iscommand
     */
    void cmdBans(int argc, QStringList argv);

    /**
     * @brief Toggle whether or not in-character messages purely consisting of spaces are allowed.
     *
     * @details Takes no arguments. Against all common sense this also allows you to disable blankposting.
     *
     * @iscommand
     */
    void cmdAllowBlankposting(int argc, QStringList argv);

    /**
     * @brief Looks up info on a ban.
     *
     * @details If it is called with **one argument**, that argument is the ban ID to look up.
     *
     * If it is called with **two arguments**, then the first argument is either a ban ID, an IPID,
     * or an HDID, and the the second argument specifies the ID type.
     *
     * @iscommand
     */
    void cmdBanInfo(int argc, QStringList argv);

    /**
     * @brief Reloads all server configuration files.
     *
     * @details No arguments.
     *
     * @iscommand
     */
    void cmdReload(int argc, QStringList argv);

    /**
     * @brief Toggles immediate text processing in the current area.
     *
     * @details No arguments.
     *
     * @iscommand
     */
    void cmdForceImmediate(int argc, QStringList argv);

    /**
     * @brief Toggles whether iniswaps are allowed in the current area.
     *
     * @details No arguments.
     *
     * @iscommand
     */
    void cmdAllowIniswap(int argc, QStringList argv);

    /**
     * @brief Grants a client the temporary permission to save a testimony.
     *
     * @details ClientID as the target of permission
     *
     * @iscommand
     *
     */
    void cmdPermitSaving(int argc, QStringList argv);

    /**
     * @brief Kicks a client from the server, forcibly severing its connection to the server.
     *
     * @details The first argument is the **target's UID**, while the remaining arguments are the **reason**
     * the client was kicked. Both arguments are mandatory.
     *
     * Unlike cmdKick, this command will only kick a single client, thus a multiclienting user will not have all their clients kicked.
     *
     * @iscommand
     *
     * @see #cmdKick
     */
    void cmdKickUid(int argc, QStringList argv);

    /**
     * @brief Updates a ban in the database, changing either its reason or duration.
     *
     * @details The first argument is the **ID** of the ban to update. The second argument is the **field** to update, either `reason` or `duration`
     *
     * and the remaining arguments are the **duration** or the **reason** to update to.
     *
     * @iscommand
     */
    void cmdUpdateBan(int argc, QStringList argv);

    /**
     * @brief Pops up a notice for all clients in the targeted area with a given message.
     *
     * @details The only argument is the message to send. This command only works on clients with support for the BB#%
     *
     * generic message box packet (i.e. Attorney Online versions 2.9 and up). To support earlier versions (as well as to make the message
     *
     * re-readable if a user clicks out of it too fast) the message will also be sent in OOC to all affected clients.
     *
     * @iscommand
     */
    void cmdNotice(int argc, QStringList argv);

    /**
     * @brief Pops up a notice for all clients in the server with a given message.
     *
     * @details Unlike cmdNotice, this command will send its notice to every client connected to the server.
     *
     * @see #cmdNotice
     *
     * @iscommand
     */
    void cmdNoticeGlobal(int argc, QStringList argv);

    /**
     * @brief Removes all CMs from the current area.
     *
     * @details This command is a bandaid fix to the issue that clients may end up ghosting when improperly disconnected from the server.
     *
     * @iscommand
     */
    void cmdClearCM(int argc, QStringList argv);

    /**
     * @brief Removes all multiclient instances of a client on the server, excluding the one using the command.
     *
     * @details This command gracefully removes all multiclients from the server, disconnecting them and freeing their used character.
     *
     * @arg argv This command allows the user to specify if it should look for IPID or HWID matches. This is useful when a client mayb
     * have been connected over IPv6 and the second connection is made over IPv4
     *
     * @iscommand
     */
    void cmdKickOther(int argc, QStringList argv);

    ///@}

    /**
     * @name Roleplay
     *
     * @brief All functions that detail the actions of commands,
     * that are also related to various kinds of roleplay actions in some way.
     */
    ///@{

    /**
     * @brief Flips a coin, returning heads or tails.
     *
     * @details No arguments.
     *
     * @iscommand
     */
    void cmdFlip(int argc, QStringList argv);

    /**
     * @brief Rolls dice and sends the results.
     *
     * @details The first argument is the **amount of faces** each die should have.
     * The second argument is the **amount of dice** that should be rolled.
     *
     * Both arguments are optional.
     *
     * @iscommand
     *
     * @see AOClient::diceThrower
     */
    void cmdRoll(int argc, QStringList argv);

    /**
     * @brief Rolls dice, but sends the results in private to the roller.
     *
     * @copydetails AOClient::cmdRoll
     */
    void cmdRollP(int argc, QStringList argv);

    /**
     * @brief Gets or sets the global or one of the area-specific timers.
     *
     * @details If called without arguments, sends an out-of-character message listing the statuses of both
     * the global timer and the area-specific timers.
     *
     * If called with **one argument**, and that argument is between `0` and `4` (inclusive on both ends),
     * sends an out-of-character message about the status of the given timer, where `0` is the global timer,
     * and the remaining numbers are the first, second, third and fourth timers in the current area.
     *
     * If called with **two arguments**, and the second argument is
     * * in the format of `hh:mm:ss`, then it starts the given timer,
     *   with `hh` hours, `mm` minutes, and `ss` seconds on it, making it appear if needed.
     * * `start`, it (re)starts the given timer, making it appear if needed.
     * * `pause` or `stop`, it pauses the given timer.
     * * `hide` or `unset`, it stops the timer and hides it.
     *
     * @iscommand
     */
    void cmdTimer(int argc, QStringList argv);

    /**
     * @brief Changes the subtheme of the clients in the current area.
     *
     * @details The only argument is the **name of the subtheme**. Reloading is always forced.
     *
     * @iscommand
     */

    void cmdSubTheme(int argc, QStringList argv);

    /**
     * @brief Writes a "note card" in the current area.
     *
     * @details The note card is not readable until all note cards in the area are revealed by a **CM**.
     * A message will appear to all clients in the area indicating that a note card has been written.
     *
     * @iscommand
     */
    void cmdNoteCard(int argc, QStringList argv);

    /**
     * @brief Reveals all note cards in the current area.
     *
     * @iscommand
     */
    void cmdNoteCardReveal(int argc, QStringList argv);

    /**
     * @brief Erases the client's note card from the area's list of cards.
     *
     * @details A message will appear to all clients in the area indicating that a note card has been erased.
     *
     * @iscommand
     */
    void cmdNoteCardClear(int argc, QStringList argv);

    /**
     * @brief Randomly selects an answer from 8ball.txt to a question.
     *
     * @details The only argument is the question the client wants answered.
     *
     * @iscommand
     */
    void cmd8Ball(int argc, QStringList argv);

    ///@}

    /**
     * @name Messaging
     *
     * @brief All functions that detail the actions of commands,
     * that are also related to messages or the client's self-management in some way.
     */
    ///@{

    /**
     * @brief Changes the client's position.
     *
     * @details The only argument is the **target position** to move the client to.
     *
     * @iscommand
     */
    void cmdPos(int argc, QStringList argv);

    /**
     * @brief Forces a client, or all clients in the area, to a specific position.
     *
     * @details The first argument is the **client's ID**, or `\*` if the client wants to force all
     * clients in their area into the position.
     * If a specific client ID is given, this command can reach across areas, i.e., the caller and target
     * clients don't have to share areas.
     *
     * The second argument is the **position** to force the clients to.
     * This is not checked for nonsense values.
     *
     * @iscommand
     */
    void cmdForcePos(int argc, QStringList argv);

    /**
     * @brief Switches to a different character based on character ID.
     *
     * @details The only argument is the **character's ID** that the client wants to switch to.
     *
     * @iscommand
     */
    void cmdSwitch(int argc, QStringList argv);

    /**
     * @brief Picks a new random character for the client.
     *
     * @details No arguments.
     *
     * @iscommand
     */
    void cmdRandomChar(int argc, QStringList argv);

    /**
     * @brief Sends a global message (i.e., all clients in the server will be able to see it).
     *
     * @details The arguments are **the message** that the client wants to send.
     *
     * @iscommand
     */
    void cmdG(int argc, QStringList argv);

    /**
     * @brief Toggles whether the client will ignore @ref cmdG "global" messages or not.
     *
     * @details No arguments.
     *
     * @iscommand
     */
    void cmdToggleGlobal(int argc, QStringList argv);

    /**
     * @brief Sends a direct message to another client on the server based on ID.
     *
     * @details Has two arguments, the first is **the target's ID** whom the client wants to send the message to,
     * while the second is **the message** the client wants to send.
     *
     * The "second" part is technically everything that isn't the first argument.
     *
     * @iscommand
     */
    void cmdPM(int argc, QStringList argv);

    /**
     * @brief A global message expressing that the client needs something (generally: players for something).
     *
     * @details The arguments are **the message** that the client wants to send.
     *
     * @iscommand
     */
    void cmdNeed(int argc, QStringList argv);

    /**
     * @brief Sends out a decorated global message, for announcements.
     *
     * @details The arguments are **the message** that the client wants to send.
     *
     * @iscommand
     *
     * @see AOClient::cmdG()
     */
    void cmdAnnounce(int argc, QStringList argv);

    /**
     * @brief Sends a message in the server-wide, moderator only chat.
     *
     * @details The arguments are **the message** that the client wants to send.
     *
     * @iscommand
     */
    void cmdM(int argc, QStringList argv);

    /**
     * @brief Sends out a global message that is marked with an `[M]` to mean it is coming from a moderator.
     *
     * @details The arguments are **the message** that the client wants to send.
     *
     * @iscommand
     *
     * @see AOClient::cmdG()
     */
    void cmdGM(int argc, QStringList argv);

    /**
     * @brief Sends out a local message that is marked with an `[M]` to mean it is coming from a moderator.
     *
     * @details The arguments are **the message** that the client wants to send.
     *
     * @iscommand
     *
     * @see AOClient::cmdLM()
     */
    void cmdLM(int argc, QStringList argv);

    /**
     * @brief Replaces a target client's in-character messages with strings randomly selected from gimp.txt.
     *
     * @details The only argument is the **the target's ID** whom the client wants to gimp.
     *
     * @iscommand
     */
    void cmdGimp(int argc, QStringList argv);

    /**
     * @brief Allows a gimped client to speak normally.
     *
     * @details The only argument is **the target's ID** whom the client wants to ungimp.
     *
     * @iscommand
     */
    void cmdUnGimp(int argc, QStringList argv);

    /**
     * @brief Removes all vowels from a target client's in-character messages.
     *
     * @details The only argument is **the target's ID** whom the client wants to disemvowel.
     *
     * @iscommand
     */
    void cmdDisemvowel(int argc, QStringList argv);

    /**
     * @brief Allows a disemvoweled client to speak normally.
     *
     * @details The only argument is **the target's ID** whom the client wants to undisemvowel.
     *
     * @iscommand
     */
    void cmdUnDisemvowel(int argc, QStringList argv);

    /**
     * @brief Scrambles the words of a target client's in-character messages.
     *
     * @details The only argument is **the target's ID** whom the client wants to shake.
     *
     * @iscommand
     */
    void cmdShake(int argc, QStringList argv);

    /**
     * @brief Allows a shaken client to speak normally.
     *
     * @details The only argument is **the target's ID** whom the client wants to unshake.
     *
     * @iscommand
     */
    void cmdUnShake(int argc, QStringList argv);

    /**
     * @brief Toggles whether a client will recieve @ref cmdPM private messages or not.
     *
     * @details No arguments.
     *
     * @iscommand
     */
    void cmdMutePM(int argc, QStringList argv);

    /**
     * @brief Toggles whether a client will recieve @ref cmdNeed "advertisement" messages.
     *
     * @details No arguments.
     *
     * @iscommand
     */
    void cmdToggleAdverts(int argc, QStringList argv);

    /**
     * @brief Toggles whether this client is considered AFK.
     *
     * @details No arguments.
     *
     * @iscommand
     */
    void cmdAfk(int argc, QStringList argv);

    /**
     * @brief Restricts a target client to a set of characters that they can switch from, blocking them from other characters.
     *
     * @details The first argument is the **target's ID** whom the client wants to charcurse.
     *
     * The second argument is one or more character names the client wants to restrict to, comma separated.
     *
     * @iscommand
     */
    void cmdCharCurse(int argc, QStringList argv);

    /**
     * @brief Removes the charcurse status from a client.
     *
     * @details The only argument is the **target's ID** whom the client wants to uncharcurse.
     *
     * @iscommand
     */
    void cmdUnCharCurse(int argc, QStringList argv);

    /**
     * @brief Forces the caller's client into the charselect screen.
     *
     * @iscommand
     */
    void cmdCharSelect(int argc, QStringList argv);

    /**
     * @brief Forces the target's client into the charselect screen.
     *
     * @details The only argument is the **target's ID** whom the client wants to force into charselect.
     *
     * @iscommand
     */
    void cmdForceCharSelect(int argc, QStringList argv);

    /**
     * @brief Sends a message to an area that you a CM in.
     *
     * @details Usage: /a <area> <message>
     *
     * @iscommand
     */
    void cmdA(int argc, QStringList argv);

    /**
     * @brief Send a message to all areas that you are a CM in.
     *
     * @details Usage: /s <message>
     *
     * @iscommand
     */
    void cmdS(int argc, QStringList argv);

    /**
     * @brief Toggle whether the client's messages will be sent in first person mode.
     *
     * @details No arguments.
     *
     * @iscommand
     */
    void cmdFirstPerson(int argc, QStringList argv);

    ///@}

    /**
     * @name Casing
     *
     * @brief All functions that detail the actions of commands,
     * that are related to casing.
     */
    ///@{

    /**
     * @brief Sets the `/doc` to a custom text.
     *
     * @details The arguments are **the text** that the client wants to set the doc to.
     *
     * @iscommand
     */
    void cmdDoc(int argc, QStringList argv);

    /**
     * @brief Sets the `/doc` to `"No document."`.
     *
     * @details No arguments.
     *
     * @iscommand
     */
    void cmdClearDoc(int argc, QStringList argv);

    /**
     * @brief Changes the evidence mod in the area.
     *
     * @details The only argument is the **evidence mod** to change to.
     *
     * @iscommand
     *
     * @see AreaData::EvidenceMod
     */
    void cmdEvidenceMod(int argc, QStringList argv);

    /**
     * @brief Changes position of two pieces of evidence in the area.
     *
     * @details The two arguments are the indices of the evidence items you want to swap the position of.
     *
     * @iscommand
     *
     * @see Area::Evidence_Swap
     *
     */
    void cmdEvidence_Swap(int argc, QStringList argv);

    /**
     * @brief Sets are to PLAYBACK mode
     *
     * @details Enables control over the stored testimony, prevent new messages to be added and
     * allows people to navigate trough it using > and <.
     */
    void cmdExamine(int argc, QStringList argv);

    /**
     * @brief Enables the testimony recording functionality.
     *
     * @details Any IC-Message send after this command is issues will be recorded by the testimony recorder.
     */
    void cmdTestify(int argc, QStringList argv);

    /**
     * @brief Allows user to update the currently displayed IC-Message from the testimony replay.
     *
     * @details Using this command replaces the content of the current statement entirely. It does not append information.
     */
    void cmdUpdateStatement(int argc, QStringList argv);

    /**
     * @brief Deletes a statement from the testimony.
     *
     * @details Using this deletes the entire entry in the QVector and resizes it appropriately to prevent empty record indices.
     */
    void cmdDeleteStatement(int argc, QStringList argv);

    /**
     * @brief Pauses testimony playback.
     *
     * @details Disables the testimony playback controls.
     */
    void cmdPauseTestimony(int argc, QStringList argv);

    /**
     * @brief Adds a statement to an existing testimony.
     *
     * @details Inserts new statement after the currently displayed recorded message. Increases the index by 1.
     *
     */
    void cmdAddStatement(int argc, QStringList argv);

    /**
     * @brief Sends a list of the testimony to OOC of the requesting client
     *
     * @details Retrieves all stored IC-Messages of the area and dumps them into OOC with some formatting.
     *
     */
    void cmdTestimony(int argc, QStringList argv);

    /**
     * @brief Saves a testimony recording to the servers storage.
     *
     * @details Saves a titled text file which contains the edited packets into a text file.
     *          The filename will always be lowercase.
     *
     */
    void cmdSaveTestimony(int argc, QStringList argv);

    /**
     * @brief Loads testimony for the testimony replay. Argument is the testimony name.
     *
     * @details Loads a titled text file which contains the edited packets to be loaded into the QVector.
     *          Validates the size of the testimony to ensure the entire testimony can be replayed.
     *          Testimony name will always be converted to lowercase.
     *
     */
    void cmdLoadTestimony(int argc, QStringList argv);

    ///@}

    /**
     * @name Music
     *
     * @brief All functions that detail the actions of commands,
     * that are also related to music in some way.
     */
    ///@{

    /**
     * @brief Plays music in the area.
     *
     * @details The arguments are **the song's filepath** originating from `base/sounds/music/`,
     * or **the song's URL** if it's a stream.
     *
     * As described above, this command can be used to play songs by URL (for clients at and above version 2.9),
     * but it can also be used to play songs locally available for the clients but not listed in the music list.
     *
     * @iscommand
     */
    void cmdPlay(int argc, QStringList argv);

    /**
     * @brief DJ-blocks a client.
     *
     * @details The only argument is the **target client's user ID**.
     *
     * @iscommand
     *
     * @see #is_dj_blocked
     */
    void cmdBlockDj(int argc, QStringList argv);

    /**
     * @brief Removes the DJ-blocked status from a client.
     *
     * @details The only argument is the **target client's user ID**.
     *
     * @iscommand
     *
     * @see #is_dj_blocked
     */
    void cmdUnBlockDj(int argc, QStringList argv);

    /**
     * @brief Returns the currently playing music in the area, and who played it.
     *
     * @details No arguments.
     *
     * @iscommand
     */
    void cmdCurrentMusic(int argc, QStringList argv);

    /**
     * @brief Toggles music playing in the current area.
     *
     * @details No arguments.
     */
    void cmdToggleMusic(int argc, QStringList argv);

    /**
     * @brief Toggles jukebox status in the current area.
     *
     * @details No arguments.
     */
    void cmdToggleJukebox(int argc, QStringList argv);

    /**
     * @brief Adds a song to the custom list.
     */
    void cmdAddSong(int argc, QStringList argv);

    /**
     * @brief Adds a category to the areas custom music list.
     */
    void cmdAddCategory(int argc, QStringList argv);

    /**
     * @brief Removes any matching song or category from the custom area.
     */
    void cmdRemoveCategorySong(int argc, QStringList argv);

    /**
     * @brief Toggles the prepending behaviour of the servers root musiclist.
     */
    void cmdToggleRootlist(int argc, QStringList argv);

    /**
     * @brief Clears the entire custom list of this area.
     */
    void cmdClearCustom(int argc, QStringList argv);

    /**
     * @brief Skips the current song in the Jukebox and plays the next available one.
     */
    void cmdJukeboxSkip(int argc, QStringList argv);

    ///@}

    /**
     * @name Command helper functions
     *
     * @brief A collection of functions of shared behaviour between command functions,
     * allowing the abstraction of technical details in the command function definition,
     * or the avoidance of repetition over multiple definitions.
     */
    ///@{

    /**
     * @brief Literally just an invalid default command. That's it.
     *
     * @note Can be used as a base for future commands.
     *
     * @iscommand
     */
    void cmdDefault(int argc, QStringList argv);

    /**
     * @brief Returns a textual representation of the time left in an area's Timer.
     *
     * @param area_idx The ID of the area whose timer to grab.
     * @param timer_idx The ID of the timer to grab
     *
     * @return A textual representation of the time left over on the Timer,
     * or `"Timer is inactive"` if the timer wasn't started.
     */
    QString getAreaTimer(int area_idx, int timer_idx);

    /**
     * @brief Generates a tsuserver3-style area list to be displayed to the user in the out-of-character chat.
     *
     * @details This list shows general details about the area the caller is currently in,
     * like who is the owner, what players are in there, the status of the area, etc.
     *
     * @param area_idx The index of the area whose details should be generated.
     *
     * @return A QStringList of details about the given area, with every entry in the string list amounting to
     * roughly a separate line.
     */
    QStringList buildAreaList(int area_idx);

    /**
     * @brief A convenience function for rolling dice.
     *
     * @param sides The number of sides the dice to be rolled have
     *
     * @param dice The number of dice to be rolled
     *
     * @param p_roll Bool to determine of a roll is private or not.
     *
     * @param roll_modifier Option parameter to add or subtract from each
     * rolled value
     */
    void diceThrower(int sides, int dice, bool p_roll, int roll_modifier = 0);

    /**
     * @brief Interprets an expression of time into amount of seconds.
     *
     * @param input A string in the format of `"XXyXXwXXdXXhXXmXXs"`, where every `XX` is some integer.
     * There is no limit on the length of the integers, the `XX` text is just a placeholder, and is not intended to
     * indicate a limit of two digits maximum.
     *
     * The string gets interpreted as follows:
     * * `XXy` is parsed into `XX` amount of years,
     * * `XXw` is parsed into `XX` amount of weeks,
     * * `XXd` is parsed into `XX` amount of days,
     * * `XXh` is parsed into `XX` amount of hours,
     * * `XXm` is parsed into `XX` amount of minutes, and
     * * `XXs` is parsed into `XX` amount of seconds.
     *
     * Any of these may be left out, but the order must be kept (i.e., `"10s5y"` is a malformed text).
     *
     * @return The parsed text, converted into their respective durations, summed up, then converted into seconds.
     */
    long long parseTime(QString input);
    QString getReprimand(bool f_positive = false);

    /**
     * @brief Clears QVector of the current area.
     *
     * @details It clears both its content and trims it back to size 0
     *
     */
    void clearTestimony();

    /**
     * @brief Called when area enum is set to PLAYBACK. Sends the IC-Message stored at the current statement.
     * @return IC-Message stored in the QVector.
     */
    QStringList playTestimony();

    /**
     * @brief Checks if a password meets the server's password requirements.
     *
     * @param username The chosen username.
     *
     * @param password The password to check.
     *
     * @return True if the password meets the requirements, otherwise false.
     */
    bool checkPasswordRequirements(QString f_username, QString f_password);

    /**
     * @brief Sends a server notice.
     *
     * @param notice The notice to send out.
     *
     * @param global Whether or not the notice should be server-wide.
     */
    void sendNotice(QString f_notice, bool f_global = false);

    /**
     * @brief Checks if a testimony contains '<' or '>'.
     *
     * @param message The IC Message that might contain unproper symbols.
     *
     * @return True if it contains '<' or '>' symbols, otherwise false.
     */
    bool checkTestimonySymbols(const QString &message);
    ///@}

    /**
     * @brief A helper variable that is used to direct the called of the `/changeAuth` command through the process
     * of changing the authorisation method from simple to advanced.
     *
     * @see cmdChangeAuth and cmdSetRootPass
     */
    bool change_auth_started = false;

    /**
     * @brief Filled with part of a packet if said packet could not be read fully from the client's socket.
     *
     * @details Per AO2's network protocol, a packet is finished with the character `%`.
     *
     * @see #is_partial
     */
    QString partial_packet;

    /**
     * @brief True when the previous `readAll()` call from the client's socket returned an unfinished packet.
     *
     * @see #partial_packet
     */
    bool is_partial;

    /**
     * @brief The size, in bytes, of the last data the client sent to the server.
     */
    int last_read = 0;

  signals:

    /**
     * @brief Signal connected to universal logger. Sends IC chat usage to the logger.
     */
    void logIC(const QString &f_charName, const QString &f_oocName, const QString &f_ipid,
               const QString &f_areaName, const QString &f_message);

    /**
     * @brief Signal connected to universal logger. Sends OOC chat usage to the logger.
     */
    void logOOC(const QString &f_charName, const QString &f_oocName, const QString &f_ipid,
                const QString &f_areaName, const QString &f_message);

    /**
     * @brief Signal connected to universal logger. Sends login attempt to the logger.
     */
    void logLogin(const QString &f_charName, const QString &f_oocName, const QString &f_moderatorName,
                  const QString &f_ipid, const QString &f_areaName, const bool &f_success);

    /**
     * @brief Signal connected to universal logger. Sends command usage to the logger.
     */
    void logCMD(const QString &f_charName, const QString &f_ipid, const QString &f_oocName, const QString f_command,
                const QStringList f_args, const QString f_areaName);

    /**
     * @brief Signal connected to universal logger. Sends player kick information to the logger.
     */
    void logKick(const QString &f_moderator, const QString &f_targetIPID, const QString &f_reason);

    /**
     * @brief Signal connected to universal logger. Sends ban information to the logger.
     */
    void logBan(const QString &f_moderator, const QString &f_targetIPID, const QString &f_duration, const QString &f_reason);

    /**
     * @brief Signal connected to universal logger. Sends modcall information to the logger, triggering a write of the buffer
     *        when modcall logging is used.
     */
    void logModcall(const QString &f_charName, const QString &f_ipid, const QString &f_oocName, const QString &f_areaName);

    /**
     * @brief Signals the server that the client has disconnected and marks its userID as free again.
     */
    void clientSuccessfullyDisconnected(const int &f_user_id);
};

#endif // AOCLIENT_H