libtagcoll

	TagConsumer // Base class for datastructure to be filled by the
		// TagcollParser::parseTagcoll() function (attention, TagcollParser is a namespace)
		// The parser calls the consume(itemset) or consume(itemset, tagset) function on reading
		// of a line
		An example is found at debtags.cc in readFullCollection(const std::string& file, TagcollConsumer<string>& consumer)
		TagcollSerializer -> write the data to a FILE*
		TagcollSink -> discards all data
		ImplicationList -> this maps the tags to their parent tags (map<string, OpSet<string>>)
			// BMthis is constructed with the file: const char* fn_impls = "/var/lib/debtags/implications";
				// this reads the implications
				// Expand implications
				ImplicationList implications;
				readCollection(fn_impls, implications);
				// Pack the structure for faster expansions
				implications.pack();
				TagcollFilter<string>* ximpl = new ApplyImplications(implications);
					// BM ApplyImplications maps every call of consume(tags) through consume(implications->expand(tags))
				filters.appendFilter(ximpl);
		DerivedTagList // will most likely be very similar to ImplicationList

		HandleMaker - maps strings to handle and vice versa (getHandle(string) inserts into the handle maker)

		TagcollBuilder - builds a tagged collection using an int to string mapping

		FilterChain - if we add consumer and there is no filter yet, it becomes the consumer, else
			it will be attached at the last filter as consumer
	

	SmartHierarchyNode - this is what should be used to build the tree!!
	HierarchyNode<ITEM, TAG> nodes to iterate through the herarchy

tagcoll
	Vocabulary - can read the tag database including the implications and description, it maps the 
		tags to the associated data
	
	
// Definition of tag implication:
//   tag1 is implied by tag2 if all items associated to tag2 are also
//   associated to tag1
// Also said:
//   tag1 implies tag2 if all items associated to tag1 are also associated
//   to tag2


// Container for bookmarks stored for computation
template<class ITEM, class TAG=std::string>
class TagCollection
{
protected:

	class TagContainer : public std::map<TAG, int> // BM int means cardinality
		// TAG is template class - string by default.
	{
	public:
		void add(const TAG& tag, int card = 1) throw ();
		void del(const TAG& tag, int card = 1) throw ();
	};

	// Tags in this collection, with their cardinality
	TagContainer tags;

	// Tag sets in this collection, with their cardinality
	typedef std::map<OpSet<TAG>, OpSet<ITEM> > tagsets_t;
	tagsets_t tagsets;	// BM maps the set of tags to a set of items, most likely the packages that
		// contains these tags

	// Items that have no tags in this collection
	OpSet<ITEM> untagged;


	OpSet<TAG>	// BM set of tags
	// Get the list of tags that imply one of the tags in `tags'
	OpSet<TAG> TagCollection::getImplyingOneOf(const OpSet<TAG>& tags) const throw ();

public:
	// Represent a change to the TagCollection
	class Change : public std::map< ITEM, OpSet<TAG> > {};

	TagCollection() throw () {}

	TagCollection(const TagCollection& tc) throw ()
		: tags(tc.tags), tagsets(tc.tagsets), untagged(tc.untagged) {}

	~TagCollection() throw () {}

	TagCollection& operator=(const TagCollection& tc) throw ()
	{
		tags = tc.tags;
		tagsets = tc.tagsets;
		untagged = tc.untagged;
		return *this;
	}


	// Get the number of different tags in this collection
	int tagCount() const throw () { return tags.size(); }

	// Get the number of different tag sets in this collection
	int tagsetCount() const throw () { return tagsets.size(); }

	// Get the number of untagged items in this collection
	int untaggedCount() const throw () { return untagged.size(); }

	// Get the total number of items in this collection
	int totalCount() const throw ();

	// Get the set of untagged items in this collection
	OpSet<ITEM> getUntaggedItems() const throw () { return untagged; }

	// Get the set of items with the given tagset
	OpSet<ITEM> getItemsForTagset(const OpSet<TAG>& ts) const throw ();

	// Get the set of tags for the given item
	// Warning: it iterates over all tagsets to find out which one is attached
	// to the given item
	OpSet<TAG> getTagsetForItem(const ITEM& item) const throw ();

	// Get the set of all tags in this collection
	OpSet<TAG> getAllTags() const throw ();

	// Get the set of all tags in this collection that appear in tagsets
	// containing `ts'
	OpSet<TAG> getCompanionTags(const OpSet<TAG>& ts) const throw ();

	// Get the set of all items in this collection
	OpSet<ITEM> getAllItems() const throw ();

	// Get the set of all items in this collection whose tagsets contain `ts'
	OpSet<ITEM> getCompanionItems(const OpSet<TAG>& ts) const throw ();

	// Get the set of all items in this collection whose tagsets contain `ts'
	std::map< ITEM, OpSet<TAG> > getCompanionItemsAndTagsets(const OpSet<TAG>& ts) const throw ();

	// Get the list of tagsets related to the given one, with distance > 0 and <= maxdistance
	std::list< OpSet<TAG> > getRelatedTagsets(const OpSet<TAG>& ts, int maxdistance = 1) const throw ();

	// Apply a Change to the collection; return a reverse change that can be
	// reused to undo the operation
	Change applyChange(const Change& change) throw ();

	// Add an untagged item to the collection
	void add(const ITEM& item) throw ();

	// Add a set of untagged items to the collection
	void add(const OpSet<ITEM>& items) throw ();

	// Add an item with the given tagset to the tagged collection
	void add(const OpSet<TAG>& tagset, const ITEM& item) throw ();

	// Add a set of items with the given tagset to the tagged collection
	void add(const OpSet<TAG>& tagset, const OpSet<ITEM>& items) throw ();

	// Return a tagged collection with all tagsets of this one that contain the
	// tag `tag', but with the tag removed
	TagCollection<ITEM, TAG> getChildCollection(const TAG& tag) const throw ();

	// Return a tagged collection with all tagsets of this one that are
	// nonempty when stripped by the tag `tag' and all tags that imply it 
	TagCollection<ITEM, TAG> getCollectionWithoutTags(const OpSet<TAG>& tag) const throw ();

	// Return the tagged collection with all tagsets of this one that do not
	// contain the tag `tag'
	TagCollection<ITEM, TAG> getCollectionWithoutTagsetsHaving(const TAG& tag) const throw ();

	// Return the tagged collection with all tagsets of this one that do not
	// contain the tags in `tags'
	TagCollection<ITEM, TAG> getCollectionWithoutTagsetsHavingAnyOf(const OpSet<TAG>& tag) const throw ();

	// Return the tag with maximum cardinality
	TAG findTagWithMaxCardinalityNotIn(const OpSet<TAG>& tags, int* card = 0) const throw ();
		
	// Return the list of tags that the given tag implies
	OpSet<TAG> TagCollection::getImpliedBy(const TAG& tag) const throw ();

	// Return a collection where equivalent tags are merged.
	// Equivalent tags are tags which are attached to the same set of items
	// Merging two equivalent tags A and B is done renaming both of them in the
	// tag "A, B"
	void mergeEquivalentTags() throw ();

	// Remove all the tags with cardinality less than `card'
	void removeTagsWithCardinalityLessThan(int card) throw ();
	
	// Output the contents of the collection to a TagcollConsumer
	void output(TagcollConsumer<ITEM, TAG>& cons) const throw ();
};

