/* Manages a graph to check out for cyclic dependencies: header file

   Copyright (C) 2011 Lisa Vitolo <shainer@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 AKABEIDEPENDENCYGRAPH_H
#define AKABEIDEPENDENCYGRAPH_H

#include "akabeiclient_global.h"
#include <akabeipackage.h>

#include <QSet>
#include <QString>
#include <QStringList>
#include <QMap>

#include <exception>

typedef QSet<QString> QStringSet;

namespace AkabeiClient
{
class AKABEICLIENTSHARED_EXPORT DependencyComputator
{
public:
    DependencyComputator(Akabei::Package * p);
    ~DependencyComputator();
    
    Akabei::Package * package() const;
    bool isValid();
    Akabei::Package::List dependencies();
    QMap<QString, Akabei::Package::List> providerOptions();
    void setProvider(const QString &prov, Akabei::Package * p);

private:
    class Private;
    Private* d;
};

/**
 * This class is not thread-safe.
 */
class AKABEICLIENTSHARED_EXPORT DependencyGraph
{
public:
    enum Type
    {
        Dependency,
        RequiredBy, /* here, installed packages are automatically included */
        DependencyForRecursiveRemoval /* special rules apply in this case, which are checked here for efficiency reasons */
    };
    /**
     * Constructor
     *
     * @param p the package for which we need to compute the dependency tree.
     */
    DependencyGraph(Akabei::Package *, Type t = Dependency);
    
    bool isValid();

    /**
     * @returns true if a cyclic dependency occurred, false otherwise.
     */
    bool cyclicDependency();

    /**
     * @returns in case of no cyclic dependency, the (not installed) dependencies of the package are returned,
     * otherwise it's an empty list.
     */
    Akabei::Package::List dependencies();

    /**
     * @returns in case of a cyclic dependency, the names of the packages involved are returned, otherwise it's empty.
     * What is really returned is the path followed from the root (the package to install) to the package causing trouble
     * (or one of them if there's more than one).
     */
    Akabei::Package::List affected();
    
    QMap<QString, Akabei::Package::List> providerOptions();
    void setProvider(const QString &prov, Akabei::Package * p);

private:
    class Private;
    Private* d;
};

class BadCycleFound : public std::exception
{
public:
    virtual const char *what() const throw() {
        return "";
    }
};
}

#endif