/*
    SPDX-FileCopyrightText: 2008 Nicola Gigante <nicola.gigante@gmail.com>
    SPDX-FileCopyrightText: 2009-2012 Dario Freddi <drf@kde.org>

    SPDX-License-Identifier: LGPL-2.1-or-later
*/

#ifndef KAUTH_ACTION_REPLY_H
#define KAUTH_ACTION_REPLY_H

#include "kauthcore_export.h"

#include <QDataStream>
#include <QMap>
#include <QSharedDataPointer>
#include <QString>
#include <QVariant>

namespace KAuth
{
class ActionReplyData;

/*!
 * \class KAuth::ActionReply
 * \inmodule KAuth
 * \inheaderfile KAuth/ActionReply
 *
 * \brief Class that encapsulates a reply coming from the helper after executing
 * an action.
 *
 * Helper applications will return this to describe the result of the action.
 *
 * Callers should access the reply though the KAuth::ExecuteJob job.
 *
 * \since 4.4
 */
class KAUTHCORE_EXPORT ActionReply
{
public:
    /*!
     * Enumeration of the different kinds of replies.
     *
     * \value KAuthErrorType An error reply generated by the library itself
     * \value HelperErrorType An error reply generated by the helper
     * \value SuccessType The action has been completed successfully
     */
    enum Type {
        KAuthErrorType,
        HelperErrorType,
        SuccessType,
    };

    /*!
     * An empty successful reply. Same as using the default constructor
     */
    static const ActionReply SuccessReply();

    /*!
     * An empty reply with type() == HelperError and errorCode() == -1
     */
    static const ActionReply HelperErrorReply();

    /*!
     * An empty reply with type() == HelperError and error is set to the passed value
     */
    static const ActionReply HelperErrorReply(int error);

    /*!
     * errorCode() == NoResponder
     */
    static const ActionReply NoResponderReply();

    /*!
     * errorCode() == NoSuchAction
     */
    static const ActionReply NoSuchActionReply();

    /*!
     * errorCode() == InvalidAction
     */
    static const ActionReply InvalidActionReply();

    /*!
     * errorCode() == AuthorizationDenied
     */
    static const ActionReply AuthorizationDeniedReply();

    /*!
     * errorCode() == UserCancelled
     */
    static const ActionReply UserCancelledReply();

    /*!
     * errorCode() == HelperBusy
     */
    static const ActionReply HelperBusyReply();

    /*!
     * errorCode() == AlreadyStartedError
     */
    static const ActionReply AlreadyStartedReply();

    /*!
     * errorCode() == DBusError
     */
    static const ActionReply DBusErrorReply();

    /*!
     * The enumeration of the possible values of errorCode() when type() is ActionReply::KAuthError
     *
     * \value NoError No error
     * \value NoResponderError The helper responder object hasn't been set. This shouldn't happen if you use the KAUTH_HELPER macro in the helper source
     * \value NoSuchActionError The action you tried to execute doesn't exist
     * \value InvalidActionError You tried to execute an invalid action object
     * \value AuthorizationDeniedError You don't have the authorization to execute the action
     * \value UserCancelledError Action execution has been cancelled by the user
     * \value HelperBusyError The helper is busy executing another action (or group of actions). Try later
     * \value AlreadyStartedError The action was already started and is currently running
     * \value DBusError An error from D-Bus occurred
     * \value BackendError The underlying backend reported an error
     */
    enum Error {
        NoError = 0,
        NoResponderError,
        NoSuchActionError,
        InvalidActionError,
        AuthorizationDeniedError,
        UserCancelledError,
        HelperBusyError,
        AlreadyStartedError,
        DBusError,
        BackendError,
    };

    /*!
     * Default constructor. Sets type() to Success and errorCode() to zero.
     */
    ActionReply();

    /*!
     * \brief Constructor to directly set the type.
     *
     * This constructor directly sets the reply type. You shouldn't need to
     * directly call this constructor, because you can use the more convenient
     * predefined replies constants. You also shouldn't create a reply with
     * the KAuthError type because it's reserved for errors coming from the
     * library.
     *
     * \a type The type of the new reply
     */
    ActionReply(Type type);

    /*!
     * \brief Constructor that creates a KAuthError reply with a specified error code.
     *        Do not use outside the library.
     *
     * This constructor is for internal use only, since it creates a reply
     * with KAuthError type, which is reserved for errors coming from the library.
     *
     * \a errorCode The error code of the new reply
     */
    ActionReply(int errorCode);

    ActionReply(const ActionReply &reply);

    virtual ~ActionReply();

    /*!
     * \brief Sets the custom data to send back to the application
     *
     * In the helper's code you can use this function to set an QVariantMap
     * with custom data that will be sent back to the application.
     *
     * \a data The new QVariantMap object.
     */
    void setData(const QVariantMap &data);

    /*!
     * \brief Returns the custom data coming from the helper.
     *
     * This method is used to get the object that contains the custom
     * data coming from the helper. In the helper's code, you can set it
     * using setData() or the convenience method addData().
     *
     * Returns the data coming from (or that will be sent by) the helper
     */
    QVariantMap data() const;

    /*!
     * \brief Convenience method to add some data to the reply.
     *
     * This method adds the pair \c key/value to the QVariantMap used to
     * report back custom data to the application.
     *
     * Use this method if you don't want to create a new QVariantMap only to
     * add a new entry.
     *
     * \a key The new entry's key
     * \a value The value of the new entry
     */
    void addData(const QString &key, const QVariant &value);

    /*!
     * Returns the reply's type
     */
    Type type() const;

    /*!
     * \brief Sets the reply type
     *
     * Every time you create an action reply, you implicitly set a type.
     * Default constructed replies or ActionReply::SuccessReply have
     * type() == Success.
     * ActionReply::HelperErrorReply has type() == HelperError.
     * Predefined error replies have type() == KAuthError.
     *
     * This means you rarely need to change the type after the creation,
     * but if you need to, don't set it to KAuthError, because it's reserved
     * for errors coming from the library.
     *
     * \a type The new reply type
     */
    void setType(Type type);

    /*!
     * Returns true if type() == Success
     */
    bool succeeded() const;

    /*!
     * Returns true if type() != Success
     */
    bool failed() const;

    /*!
     * \brief Returns the error code of an error reply
     *
     * The error code returned is one of the values in the ActionReply::Error
     * enumeration if type() == KAuthError, or is totally application-dependent if
     * type() == HelperError. It also should be zero for successful replies.
     *
     * Returns the reply error code
     */
    int error() const;

    /*!
     * \brief Returns the error code of an error reply
     *
     * The error code returned is one of the values in the ActionReply::Error
     * enumeration if type() == KAuthError.
     * Result is only valid if the type() == HelperError
     *
     * Returns the reply error code
     */
    Error errorCode() const;

    /*!
     * \brief Sets the error code of an error reply
     *
     * If you're setting the error code in the helper because
     * you need to return an error to the application, please make sure
     * you already have set the type to HelperError, either by calling
     * setType() or by creating the reply in the right way.
     *
     * If the type is Success when you call this method, it will become KAuthError
     *
     * \a error The new reply error code
     */
    void setError(int error);

    /*!
     * \brief Sets the error code of an error reply
     *
     * If you're setting the error code in the helper, use setError(int)
     *
     * If the type is Success when you call this method, it will become KAuthError
     *
     * \a errorCode The new reply error code
     */
    void setErrorCode(Error errorCode);

    /*!
     * \brief Gets a human-readble description of the error, if available
     *
     * Currently, replies of type KAuthError rarely report an error description.
     * This situation could change in the future.
     *
     * By now, you can use this method for custom errors of type HelperError.
     *
     * Returns the error human-readable description
     */
    QString errorDescription() const;

    /*!
     * \brief Sets a human-readble description of the error
     *
     * Call this method from the helper if you want to send back a description for
     * a custom error. Note that this method doesn't affect the errorCode in any way
     *
     * \a error The new error description
     */
    void setErrorDescription(const QString &error);

    /*!
     * \brief Serialize the reply into a QByteArray.
     *
     * This is a convenience method used internally to sent the reply to a remote peer.
     * To recreate the reply, use deserialize()
     *
     * Returns a QByteArray representation of this reply
     */
    QByteArray serialized() const;

    /*!
     * \brief Deserialize a reply from a QByteArray
     *
     * This method returns a reply from a QByteArray obtained from
     * the serialized() method.
     *
     * \a data A QByteArray obtained with serialized()
     */
    static ActionReply deserialize(const QByteArray &data);

    ActionReply &operator=(const ActionReply &reply);

    /*!
     * \brief Comparison operator
     *
     * Returns true if the type and the error code of this and \a reply are the same.
     * It \e doesn't compare the data or the error descriptions, so be careful.
     *
     * The suggested use is to compare a reply against one of the predefined error replies:
     * \code
     * if(reply == ActionReply::HelperBusyReply) {
     *    // Do something...
     * }
     * \endcode
     *
     * Note that you can do it also by compare errorCode() with the relative enumeration value.
     */
    bool operator==(const ActionReply &reply) const;

    /*!
     * \brief Negated comparison operator
     *
     * See the operator==() for an important notice.
     */
    bool operator!=(const ActionReply &reply) const;

private:
    QSharedDataPointer<ActionReplyData> d;
};

} // namespace Auth

Q_DECLARE_METATYPE(KAuth::ActionReply)

#endif
