#ifndef DEPENDENCY_GRAPH_H_A254DOQ
#define DEPENDENCY_GRAPH_H_A254DOQ

namespace oak
{
	struct dependency_graph
	{
		// a node is an integer and represents a task to perform
		void add_node (size_t node)
		{
			dependencies.insert(std::make_pair(node, std::set<size_t>()));
		}

		// an edge establishes a dependency from one node (first argument) to another (second argument)
		// e.g. if node RUN depends on node BUILD we call: add_edge(RUN, NODE)
		void add_edge (size_t node, size_t dependsOn)
		{
			dependencies[node].insert(dependsOn);
		}

		// mark a node as “modified” and return all nodes which in effect are then also modified
		std::set<size_t> touch (size_t node) const
		{
			std::set<size_t> res;
			std::vector<size_t> active(1, node);

			while(!active.empty())
			{
				size_t n = active.back();
				res.insert(n);
				active.pop_back();

				iterate(it, dependencies)
				{
					std::set<size_t>::const_iterator node = it->second.find(n);
					if(node == it->second.end() || res.find(it->first) != res.end())
						continue;

					active.push_back(it->first);
				}
			}

			return res;
		}

		// return list of all nodes ordered so that for each node, all it depends on is before that node in this list
		std::vector<size_t> topological_order () const
		{
			std::vector<size_t> res, active;
			iterate(it, dependencies)
			{
				if(it->second.empty())
					active.push_back(it->first);
			}

			std::map< size_t, std::set<size_t> > tmp = dependencies;
			while(!active.empty())
			{
				size_t n = active.back();
				res.push_back(n);
				active.pop_back();

				iterate(it, tmp)
				{
					std::set<size_t>::const_iterator node = it->second.find(n);
					if(node == it->second.end())
						continue;

					it->second.erase(node);
					if(it->second.empty())
						active.push_back(it->first);
				}
			}

			return res;
		}

	private:
		std::map< size_t, std::set<size_t> > dependencies;
	};

} /* oak */ 

#endif /* end of include guard: DEPENDENCY_GRAPH_H_A254DOQ */
