#ifndef PASTELSYS_DEPTH_FIRST_TRAVERSAL_HPP
#define PASTELSYS_DEPTH_FIRST_TRAVERSAL_HPP
#include "pastel/sys/graph/depth_first/depth_first.h"
#include <boost/bind.hpp>
#include <functional>
namespace Pastel
{
    class DepthFirst_GraphTraversal
    {
    public:
        template <
            typename Vertex,
            typename ForEachSeedVertex,
            typename ForEachAdjacent,
            typename Mark,
            typename Marked>
        void work(
            const ForEachSeedVertex& forEachSeedVertex,
            const ForEachAdjacent& forEachAdjacent,
            const Mark& mark,
            const Marked& marked) const
        {
            Work<Vertex, ForEachSeedVertex, 
                ForEachAdjacent, Mark, Marked> work(
                forEachSeedVertex, forEachAdjacent,
                mark, marked);
        }
    private:
        template <
            typename Vertex,
            typename ForEachSeedVertex,
            typename ForEachAdjacent,
            typename Mark,
            typename Marked>
        class Work
        {
        public:
            Work(
                const ForEachSeedVertex& forEachSeedVertex_,
                const ForEachAdjacent& forEachAdjacent_,
                const Mark& mark_,
                const Marked& marked_)
                : forEachSeedVertex(forEachSeedVertex_)
                , forEachAdjacent(forEachAdjacent_)
                , mark(mark_)
                , marked(marked_)
            {
                // Traverse each seed-vertex depth-first.
                forEachSeedVertex(
                    boost::bind(&Work::visit, 
                    boost::ref(*this), _1));
            }
            void visit(const Vertex& vertex)
            {
                // Avoid visiting the same vertex twice.
                if (!marked(vertex))
                {
                    // Mark as visited.
                    mark(vertex);
                    // Traverse the edges.
                    forEachAdjacent(
                        vertex,
                        boost::bind(&Work::visit, 
                        boost::ref(*this), _1));
                }
            }
        private:
            const ForEachSeedVertex& forEachSeedVertex;
            const ForEachAdjacent& forEachAdjacent;
            const Mark& mark;
            const Marked& marked;
        };
    };
}
#endif