#pragma once

#include "imodule.h"
#include "inode.h"
#include <set>

#include <sigc++/signal.h>

namespace selection
{

class ISelectionSet
{
public:
	// The name of this set
	virtual const std::string& getName() = 0;

	// Checks whether this set is empty
	virtual bool empty() = 0;

	// Selects all member nodes of this set
	virtual void select() = 0;

	// De-selects all member nodes of this set
	virtual void deselect() = 0;

	// Removes all members, leaving this set as empty
	virtual void clear() = 0;

	// Clears this set and loads the currently selected nodes in the
	// scene as new members into this set.
	virtual void assignFromCurrentScene() = 0;

	// Adds the given node to this set
	virtual void addNode(const scene::INodePtr& node) = 0;

	// Returns the nodes contained in this selection set.
	virtual std::set<scene::INodePtr> getNodes() = 0;
};
typedef std::shared_ptr<ISelectionSet> ISelectionSetPtr;

class ISelectionSetManager
{
public:
	typedef std::shared_ptr<ISelectionSetManager> Ptr;

	virtual ~ISelectionSetManager() {}

    /**
     * Signal emitted when the list of selection sets has been changed, by
     * deletion or addition.
     */
    virtual sigc::signal<void> signal_selectionSetsChanged() const = 0;

	class Visitor
	{
	public:
        virtual ~Visitor() {}
		virtual void visit(const ISelectionSetPtr& set) = 0;
	};

	/**
	 * greebo: Traverses the list of selection sets using
	 * the given visitor class.
	 */
	virtual void foreachSelectionSet(Visitor& visitor) = 0;

	typedef std::function<void(const ISelectionSetPtr&)> VisitorFunc;

	/**
	 * greebo: Traverses the list of selection sets using the given functor.
	 */
	virtual void foreachSelectionSet(const VisitorFunc& functor) = 0;

	/**
	 * greebo: Creates a new selection set with the given name.
	 * If a selection with that name is already registered, the existing
	 * one is returned.
	 */
	virtual ISelectionSetPtr createSelectionSet(const std::string& name) = 0;

	/**
	 * Removes the named selection set. If the named set is
	 * not existing, nothing happens.
	 */
	virtual void deleteSelectionSet(const std::string& name) = 0;

	/**
	 * Deletes all sets.
	 */
	virtual void deleteAllSelectionSets() = 0;

	/**
	 * Finds the named selection set.
	 *
	 * @returns the found selection set or NULL if the set is not existent.
	 */
	virtual ISelectionSetPtr findSelectionSet(const std::string& name) = 0;
};

class ISelectionSetModule :
	public RegisterableModule
{
public:
	virtual ~ISelectionSetModule() {}

	virtual ISelectionSetManager::Ptr createSelectionSetManager() = 0;
};

} // namespace

const char* const MODULE_SELECTIONSETS = "SelectionSetModule";

inline selection::ISelectionSetModule& GlobalSelectionSetModule()
{
	static module::InstanceReference<selection::ISelectionSetModule> _reference(MODULE_SELECTIONSETS);
	return _reference;
}
