/* This file is part of the Chakra project

   Copyright (C) 2010 Dario Freddi <drf@chakra-project.org>

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.
*/

#ifndef AKABEI_AKABEIERROR_H
#define AKABEI_AKABEIERROR_H

#include <QString>
#include <QList>
#include <QSharedDataPointer>

#include <akabeipackage.h>

namespace Akabei {
class Operation;

/**
 * \class Error akabeierror.h "akabeierror.h"
 *
 * \brief Class for describing an error which occurred.
 *
 * This class is not thread-safe.
 */
class Error
{
    public:
        /**
         * \enum Type
         * This enum describes the type of error which occurred.
         * @see type()
         */
        enum Type {
            UnknownError = 0,
            FilesystemConflictError = 1,
            PackageConflictError = 2,
            DuplicateTargetError = 3,
            UnresolvableDependenciesError = 4,
            DatabaseError = 5,
            ScriptletError = 6,
            NetworkError = 7,
            NetworkContentNotFoundError = 8,
            NetworkOperationCanceledError = 9,
            ArchiveError = 10,
            SignatureError = 11,
            BackendInitializationError = 12,
            ChecksumError = 13,
            OpenFileError = 14,
            FullDiskError = 15,
            PermissionError = 16,
            FilesystemError = 17,
            RemoveRequiredByError = 18,
            //
            GenericError = 128,
            AkabeiInternalError = 129
        };

        /**
         * \typedef List
         * A QList of Error objects.
         */
        typedef QList< Error > List;

        /**
         * Creates an new error object.
         * @param type the type of the error
         * @param description the description of the error
         * @param op the operation associated with the error
         */
        explicit Error(Type type = UnknownError, const QString& description = QString(), Operation* operation = nullptr);
        Error(const Error &error);
        virtual ~Error();

        /**
         * @returns the type of error which occurred
         */
        Type type() const;

        /**
         * Sets a new type of error
         * @param type the error type
         */
        void setType(Type type);

        /**
         * @returns the description of the error
         */
        QString description() const;

        /**
         * Sets a new description of the error.
         * @param description the new description
         */
        void setDescription(QString const& description);

        /**
         * @returns the operation in which the error occurred. Can theoretically be 0.
         */
        Operation* operation();

        /**
         * Sets a new operation associated with the error
         * @param op the new operation associated with the error
         */
        void setOperation(Operation* op);

        /**
         * @returns the targets which are associated with the error
         */
        Package::List targets() const;

        /**
         * Sets new targets associated with the error
         * @param targets the new targets associated with the error
         */
        void setTargets(Package::List const& targets);

        Error &operator=(const Error &other);

    private:
        class Private;
        QSharedDataPointer<Private> d;
};

/**
 * \class ErrorQueue akabeierror.h "akabeierror.h"
 *
 * \brief Class for registering errors
 *
 * This class is thread-safe.
 */
class ErrorQueue
{
    Q_DISABLE_COPY(ErrorQueue)
    
public:
    virtual ~ErrorQueue();
    
    /**
     * @returns the static ErrorQueue object
     */
    static ErrorQueue* instance();
    
    /**
     * Takes an error off the queue
     * @returns the error taken off
     */
    Error takeError();
    /**
     * @returns the type of the error which sits at the first position of the queue
     */
    Error::Type headType() const;
    /**
     * @returns true when the queue is empty
     */
    bool isEmpty() const;
    
    /**
     * Appends an error onto the queue
     */
    void appendError(const Error &);
    /**
     * Appends a list of errors onto the queue
     */
    void appendErrors(const Error::List &);
    
    /**
     * Registers an error handler for a certain error type
     */
    void registerForErrorType(Error::Type, QObject *, const char *);
    /**
     * Registers an error handler for all errors
     */
    void registerForAllErrors(QObject *, const char *);
    
private:
    ErrorQueue();
    
    class Private;
    Private* d;
};

}

#endif // AKABEI_AKABEIERROR_H
