/**************************************************************************
*   Copyright (C) 2010-2011 by Eugene V. Lyubimkin                        *
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License                  *
*   (version 3 or above) as published by the Free Software Foundation.    *
*                                                                         *
*   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 General Public License for more details.                          *
*                                                                         *
*   You should have received a copy of the GNU GPL                        *
*   along with this program; if not, write to the                         *
*   Free Software Foundation, Inc.,                                       *
*   51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA               *
**************************************************************************/
#ifndef CUPT_INTERNAL_NATIVERESOLVER_DEPENDENCY_GRAPH_SEEN
#define CUPT_INTERNAL_NATIVERESOLVER_DEPENDENCY_GRAPH_SEEN

#include <map>
#include <vector>
using std::vector;

#include <cupt/common.hpp>
#include <cupt/fwd.hpp>
#include <cupt/system/resolver.hpp>
typedef cupt::system::Resolver::Reason Reason;
typedef cupt::system::Resolver::RequestImportance RequestImportance;
using cupt::cache::BinaryVersion;
using cupt::cache::RelationExpression;

#include <internal/graph.hpp>

namespace cupt {
namespace internal {

struct PackageEntry;

namespace dependencygraph {

struct UserRelationExpression
{
	RelationExpression expression;
	bool invert;
	string annotation;
	RequestImportance importance;
	bool asAuto;
};

struct Unsatisfied
{
	enum Type { None, Recommends, Suggests, Sync, Custom };
};

struct BasicVertex;
typedef const BasicVertex* Element;
struct BasicVertex
{
 private:
	static uint32_t __next_id;
 public:
	const uint32_t id;
	virtual string toString() const = 0;
	virtual size_t getTypePriority() const;
	virtual shared_ptr< const Reason > getReason(const BasicVertex& parent) const;
	virtual bool isAnti() const;
	virtual const vector<Element>* getRelatedElements() const;
	virtual Unsatisfied::Type getUnsatisfiedType() const;
	virtual const RequestImportance& getUnsatisfiedImportance() const;
	virtual bool asAuto() const;
	virtual Element getFamilyKey() const;

	BasicVertex();
	virtual ~BasicVertex();
};
struct VersionVertex: public BasicVertex
{
 private:
	typedef map< string, vector<Element> > FamilyMap;
	const FamilyMap::iterator __related_element_ptrs_it;
 public:
	const BinaryVersion* version;

	VersionVertex(const FamilyMap::iterator&);
	string toString() const;
	const vector<Element>* getRelatedElements() const;
	const string& getPackageName() const;
	string toLocalizedString() const;
	Element getFamilyKey() const;
};
typedef const VersionVertex* VersionElement;

namespace {

template< class T >
struct PointeredAlreadyTraits
{
	typedef T PointerType;
	static T toPointer(T vertex)
	{
		return vertex;
	}
};

}

class DependencyGraph: protected Graph< Element, PointeredAlreadyTraits >
{
	const Config& __config;
	const Cache& __cache;

	class FillHelper;
	friend class FillHelper;

	std::unique_ptr< FillHelper > __fill_helper;

	vector< pair< Element, shared_ptr< const PackageEntry > > > p_generateSolutionElements(
			const map< string, const BinaryVersion* >&);
	void p_populatePackage(const string& packageName);
 public:
	typedef Graph< Element, PointeredAlreadyTraits > BaseT;

	DependencyGraph(const Config& config, const Cache& cache);
	~DependencyGraph();
	vector< pair< Element, shared_ptr< const PackageEntry > > > fill(
			const map< string, const BinaryVersion* >&);
	void addUserRelationExpression(const UserRelationExpression&);

	Element getCorrespondingEmptyElement(Element);
	void unfoldElement(Element);

	using BaseT::getSuccessors;
	using BaseT::getPredecessors;
	using BaseT::CessorListType;
};

}
}
}

#endif

