/* This file is part of the Chakra project

   Copyright (C) 2010 Lukas Appelhans <l.appelhans@gmx.de>

   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 AKABEICLIENTQUEUE_H
#define AKABEICLIENTQUEUE_H

#include <QObject>
#include "akabeiclient_global.h"
#include <akabeipackage.h>
#include <akabeierror.h>
#include <QMap>

class QNetworkAccessManager;

namespace AkabeiClient {
/**
 * \class QueueItem akabeiclientqueue.h "akabeiclientqueue.h"
 *
 * \brief This class represents a queue item within akabeiclient.
 * 
 * This class is thread-safe.
 */
class AKABEICLIENTSHARED_EXPORT QueueItem
{
    public:
        typedef QList<QueueItem*> List;
        ~QueueItem();
        
        /**
         * @returns the corresponding package which is going to be processed during the transaction
         */
        Akabei::Package * package();
        /**
         * @returns a possible local package (e.g. for upgrade operations)
         */
        Akabei::Package * localPackage();
        /**
         * @returns the list of replaced packages (e.g. for replacement operations)
         */
        QList<Akabei::Package*> replacedPackages();
        /**
         * @returns the action which is going to be done to the package during transaction
         */
        PackageAction action();

        /**
         * Set a new action (e.g. to transform an install action to a replace)
         */
        void setaction(PackageAction);
        
        /**
         * @returns true if there's a cyclic dependency for this package
         */
        bool isCyclicDependency();
        
        /**
         * @returns a list of errors occurred while computing the trees
         */
        Akabei::Error::List errors();
        
        /**
         * Computes the dependencyTree and requiredByTree
         * Both functions do more than just Package::computeDependencies or Package::computeRequiredBy
         * They find all dependencies:
         * If a package depends on foo which depends on bar, Package::computeDependencies will only show foo,
         * while this method will show foo and bar.
         */
        void computeTrees();
        
        /**
         * @returns a complete list of dependencies for the package
         */
        Akabei::Package::List dependencyTree();
        
        /**
         * List only packages from the local database which require this package()
         * @returns a complete list of packages which require this package
         */
        Akabei::Package::List requiredByTree();
        
    private:
        QueueItem(Akabei::Package * package, PackageAction action);
        
        class Private;
        Private * d;
        
        friend class Queue;
};

/**
 * \class Queue akabeiclientqueue.h "akabeiclientqueue.h"
 *
 * \brief This class represents a queue which gets processed by the TransactionHandler.
 * 
 * When a client wants to process a list of packages, this object needs to get filled with each of them.
 * 
 * This class is thread-safe.
 */
class AKABEICLIENTSHARED_EXPORT Queue : public QObject
{
    Q_OBJECT
    public:
        virtual ~Queue();

        /**
         * Removes all packages from the queue
         */
        void clear();
        
        /**
         * Computes the dependencyTree and requiredByTree for each package
         */
        void computeAllTrees();

        /**
         * Computes the replacement search by looking at the remote servers
         * if some new packages provides a replacement are added automatically
         * to the current queue
         */
        void computeReplacements();

        void clearReplacements();

        /**
         * Adds a package to the queue with a given action.
         * @param package the package which is going to be processed
         * @param action the action which is going to be done on the package
         */
        void addPackage(Akabei::Package * package, PackageAction action);
        /**
         * Removes a certain package from the transaction.
         * @param package the package which gets removed
         */
        void removePackage(Akabei::Package * package);
        
        /**
         * Only explicitely marked packages
         */
        QueueItem::List items() const;

        /**
         * @returns the number of items in the list.
         */
        int size() const;
        
        QMap<QString, Akabei::Package::List> unresolvedProviders();
        void setProvider(const QString &p, Akabei::Package * package);

    private:
        Queue(QObject * parent = 0);
        class Private;
        Private * const d;
        
        friend class Backend;
        friend class TransactionHandler;
};
}

#endif
