//==========================================================================
//
//   dfs.h
//
//==========================================================================
// $Id: dfs.h,v 1.22 2000/03/07 07:41:34 raitner Exp $

#ifndef GTL_DFS_H
#define GTL_DFS_H

#include <GTL/GTL.h>
#include <GTL/algorithm.h>

__GTL_BEGIN_NAMESPACE

/**
 * @short Depth-First-Search (DFS) algorithm 
 * 
 * Encapsulates the DFS-algoritm together with all the data produced by a  
 * run of DFS. 
 * <p>
 * Since there exits so much different things which one might want to 
 * calculate during a DFS this class provides basically two different
 * customization features. First it is possible to take influence on 
 * the behaviour of this algortihm by changing some of the
 * following options:
 * 
 * <ul>
 * <li> @ref dfs#start_node 
 *      (default: an arbitrary node will be chosen)
 * <li> @ref dfs#scan_whole_graph states whether BFS will be 
 *      continued in the unused part of the graph, if not all
 *      nodes were touched at the end of DFS started at the start-node.
 *      (default: disabled)
 * <li> @ref dfs#calc_comp_num toggle storing of completion-numbers 
 *      for each node, i.e. a numbering which reflects the order in which 
 *      nodes were finished. (default: disabled)
 * <li> @ref dfs#store_preds toggle storing the predecessor of each
 *      node, i.e. the father in DFS-tree. (default: disabled)
 * <li> @ref dfs#store non_tree_edges toggle storing of all non_tree_edges
 *      (tree_edges are always stored) in a list and thus enable or disable
 *      iteration through all non_tree_edges.
 *      (default: disabled)
 * </ul>
 * 
 * <p>
 * But the trouble with most DFS-algorithm is that one always wants to
 * add a little bit of code somewhere in the algorithm. And then there are
 * only two ways to  get this done. The more efficient one (in terms of
 * runtime) is to implement the DFS anew and add the new code where
 * necessary. The other way (which is more efficient in terms of
 * code-writing) is to take the algorithm as provided and run through the list
 * of nodes it returns (resulting in an extra factor of 2)
 *
 * <p>
 * Our DFS-algoritm class provides a new method to add small pieces of
 * code to  the algorithm: Handler. These are virtual functions called at
 * certain important states of the algorithm (e.g. before a new recursive
 * call). So the only thing to do is to derive your extended DFS from this
 * class and to override the handlers where needed. In detail there are the
 * following handler supported (have a look at the source code for details):
 * 
 * <ul>
 * <li> @ref dfs#init_handler
 * <li> @ref dfs#end_handler 
 * <li> @ref dfs#entry_handler 
 * <li> @ref dfs#leave_handler
 * <li> @ref dfs#before_recursive_call_handler 
 * <li> @ref dfs#after_recursive_call_handler 
 * <li> @ref dfs#old_adj_node_handler
 * <li> @ref dfs#new_start_handler
 * </ul>
 *
 * <p>
 * Please note: We do <em>not</em> claim that this set of handler 
 * is sufficient in any way. So if you believe that some new handler is 
 * needed urgently please let us know.
 *
 * <p>
 * There is a lot of information stored during DFS (e.g. nodes in
 * dfs-order, list of non-tree edges). Some of it can be obtained directly
 * by using the corresponding member-function (e.g. @ref dfs#dfs_num),
 * but all information that can be thought of as a list (e.g. nodes in
 * dfs-order) can be accessed through iterators. In detail these are (of
 * course depending on what options are chosen!): 
 * 
 * <ul>
 * <li> @ref dfs#dfs_iterator
 * <li> @ref dfs#tree_edges_iterator
 * <li> @ref dfs#non_tree_edges_iterator
 * <li> @ref dfs#roots_iterator
 * </ul>
 */

class GTL_EXTERN dfs : public algorithm 
{
public:
    //---------------------------------------------------------------------
    //   algorithm -- Interface
    //---------------------------------------------------------------------

    /**
     * Default constructor. Options default like described above.
     * 
     * @see algorithm#algorithm
     */
    dfs ();


    /**
     * Destructor.
     * 
     * @see algorithm#~algorithm
     */
    virtual ~dfs ();
    

    /**
     * Performs DFS. 
     *
     * @param <code>G</code> graph.
     * @return <code>algorithm::GTL_OK</code> on success,
     * <code>algorithm::GTL_ERROR</code> otherwise.
     * @see algorithm#run
     */
    int run (graph& G);


    /**
     * Checks whether the preconditions for DFS are satisfied.
     *
     * @param <code>G</code> graph.
     * @return <code>algorithm::GTL_OK</code> on success,
     * <code>algorithm::GTL_ERROR</code> otherwise.
     * @see algorithm#check
     */
    virtual int check (graph& G);


    /**
     * Reset. Please note that options like scanning of whole graph 
     * are <em>not</em> reset, but the chosen start node will be set back. 
     * So if applying this algorithm more than once with the same start 
     * node, it has to be set explicitly before every run.
     *
     * @see algorithm#reset
     */
    virtual void reset ();


    //---------------------------------------------------------------------
    //   Parameters
    //---------------------------------------------------------------------
    
    /**
     * Sets start-node for DFS. The default start-node is the invalid node
     * <code>node()</code>, in this case an arbitrary node is chosen and 
     * stored, when DFS is run.
     *
     * @param <code>n</code> start-node.
     */
    void start_node (const node& n) 
	{ start = n; }

    /**
     * Returns start-node for DFS.
     *
     * @return start-node.
     */
    node start_node () const {return start;}
    
    /**
     * Enables or disables scanning of the whole graph. If enabled and the
     * DFS started at the given start-node stops without having touched all 
     * nodes,  it will be continued with the next unused node, and so on
     * until all nodes were used. This makes sure that for every node
     * dfs_number is defined. 
     *
     * <p>On the other hand, if this feature is disabled,
     * one will be able to check what nodes can be reached, when starting a
     * DFS at the start-node, because for those not reached dfs-number will
     * be 0. 
     * 
     * @param <code>set</code> if true enable scanning the whole graph.
     * @see dfs#roots_begin
     * @see dfs#roots_end
     */
    void scan_whole_graph (bool set) {whole_graph = set;}
    
    /**
     * Returns true iff the  whole graph will be scanned.
     * 
     * @return true iff the  whole graph will be scanned.
     * @see dfs#roots_begin
     * @see dfs#roots_end
     */
    bool scan_whole_graph () const {return whole_graph;}

    /**
     * Enables or Disables the calculation of the completion number.
     *
     * @param <code>set</code> if true completion-numbers will be calculated.
     * @see dfs#comp_num
     */
    void calc_comp_num (bool set);

    /**
     * Returns true iff completion-numbers will be calculated.
     * 
     * @return true iff completion-numbers will be calculated.
     * @see dfs#comp_num
     */
    bool calc_comp_num () const {return comp_number != 0;}


    /**
     * Enables or disables the storing of predecessors. If enabled for
     * every node the predecessor in DFS will be stored.
     *
     * @param <code>set</code> if true predecessors will be stored.
     * @see dfs#father
     */
    void store_preds (bool set);

    /**
     * Returns true iff the storing of predecessors is enabled.
     * 
     * @return true iff the storing of predecessors is enabled.
     * @see dfs#father
     */
    bool store_preds () const {return preds != 0;}
    
    /**
     * Enables the storing of back-edges. If enabled the list of
     * non-tree-edges can 
     * be traversed in the order they occured using
     * <code>non_tree_edges_iterator</code> 
     *
     * @param <code>set</code> if true non_tree_edges will be stored.
     * @see dfs#non_tree_edges_begin
     * @see dfs#non_tree_edges_end
     */
    void store_non_tree_edges (bool set);

    /**
     * Returns true iff the storing of non-tree-edges is enabled.
     * 
     * @return true iff the storing of non-tree-edges is enabled.
     * @see dfs#non_tree_edges_begin
     * @see dfs#non_tree_edges_end
     */
    bool store_non_tree_edges () const {return back_edges != 0;}

    //---------------------------------------------------------------------
    //   Access 
    //----------------------------------------------------------------------

    /**
     * Checks whether node <code>n</code> was reached in last DFS.
     *
     * @param <code>n</code> node to be checked.
     * @return true iff <code>n</code> was reached.
     */
    bool reached (const node& n) const
	{return dfs_number[n] != 0;}

    /**
     * DFS-Number of <code>n</code>. Please note that DFS-Number 0 means
     * that this node wasn't reached.
     *
     * @param <code>n</code> node.
     * @return DFS-Number of <code>n</code>.
     */
    int dfs_num (const node& n) const 
	{return dfs_number[n];}

   /**
    * DFS-Number of <code>n</code>. Please note that DFS-Number 0 means
    * that this node wasn't reached.
    *
    * @param <code>n</code> node.
    * @return DFS-Number of <code>n</code>.
    */
    int operator[] (const node& n) const 
	{return dfs_number[n];}

    /**
     * Returns completion-number of node <code>n</code>, if enabled in last
     * run.
     *
     * @param <code>n</code> node.
     * @return Completion-number of <code>n</code>.
     * @see dfs#calc_comp_num
     */
    int comp_num (const node& n) const
	{assert (comp_number); return (*comp_number)[n];}

    /**
     * Returns father of node <code>n</code> in DFS-forest. If
     * <code>n</code> is a root  
     * in the forest or wasn't reached the return 
     * value is <code>node()</code>.
     *
     * @param <code>n</code> node.
     * @return Father of <code>n</code>.
     * @see dfs#store_preds
     */    
    node father (const node& n) const
	{assert (preds); return (*preds)[n];}

    /**
     * @internal
     */
    typedef list<edge>::const_iterator tree_edges_iterator;

    /**
     * Iterate through all edges picked in last DFS. Please note that this 
     * edges not always form a tree. In case the graph is not (strongly) 
     * connected they form a forest.
     * 
     * @return start for iteration through all edges followed in DFS.
     */
    tree_edges_iterator tree_edges_begin () const 
	{return tree.begin();}

    /**
     * End-Iterator for iteration through all edges picked in last DFS.
     *
     * @return end for iteration through all edges followed in DFS.
     */
    tree_edges_iterator tree_edges_end () const
	{return tree.end();}

    /**
     * @internal
     */
    typedef list<node>::const_iterator dfs_iterator; 

    /**
     * Iterate through all (reached) nodes in DFS-order.
     *
     * @return start for iteration through all nodes in DFS-order.
     */
    dfs_iterator begin () const 
	{return dfs_order.begin();}

    /**
     * End-Iterator for iteration through all (reached) nodes in DFS-order.
     *
     * @return end for iteration through all (reached) nodes
     */
    dfs_iterator end () const 
	{return dfs_order.end();}

    /**
     * @internal
     */
    typedef list<edge>::const_iterator non_tree_edges_iterator;

    /**
     * Iterate through all non_tree_edges (if enabled).
     *
     * @return start for iteration through all non-tree-edges.
     * @see dfs#store_non_tree_edges
     */
    non_tree_edges_iterator non_tree_edges_begin () const 
	{assert (back_edges);  return back_edges->begin(); }

    /**
     * End-iterator for iteration through all non-tree-edges (if enabled).
     *
     * @return end for iteration through all non-tree-edges.
     * @see dfs#store_non_tree_edges
     */
    non_tree_edges_iterator non_tree_edges_end () const 
	{assert (back_edges); return back_edges->end(); }

    /**
     * @internal
     */
    typedef list<dfs_iterator>::const_iterator roots_iterator;

    /**
     * Iterator pointing towards the first root in the DFS-forest.
     * <em>Please note</em> that intstead of pointing directly towards the node
     * (i.e. <code>*it</code> is of type node) the iterator points towards
     * a dfs-iterator, which represents the root (i.e. <code>*it</code>
     * is of type <code>dfs_iterator</code>). 
     * 
     * <p>Using this technique 
     * makes it possible not only to obtain all the roots in the forest, 
     * but also the whole trees associated with each one. This can be achieved 
     * because a <code>root_iterator</code> specifies the exact position of 
     * the root in the DFS-ordering and by definition of DFS all the descendents of 
     * the root, i.e. the whole tree, will come later in DFS, such that by 
     * incrementing the <code>dfs_iterator</code>, a 
     * <code>roots_iterator</code>
     * points at, one can traverse the whole tree with this given root.
     * 
     * <p>Of course if the root isn't the last node in the DFS-forest on will
     * also traverse all following trees, but since the first node of such 
     * a tree one will discover is its root, the successor of the 
     * <code>roots_iterator</code> can be used as end-iterator.
     * 
     * @return start for iteration through all roots in DFS-forest.
     * @see dfs#scan_whole_graph
     */
    roots_iterator roots_begin () const 
	{return roots.begin();}

    /**
     * Iterator pointing to the end of all roots.
     * 
     * @return end for iteration through all roots in DFS-forest.
     * @see dfs#scan_whole_graph
     */
    roots_iterator roots_end () const 
	{return roots.end();}

    /**
     * Number of nodes reached in last DFS.
     *
     * @return number of reached nodes.
     * @see dfs#scan_whole_graph
     */
    int number_of_reached_nodes () const
	{return reached_nodes;}


    //-----------------------------------------------------------------------
    //   Handler - for customization purposes
    //-----------------------------------------------------------------------

    /**
     * Handler called before the start of DFS.
     *
     * @param <code>G</code> graph for which DFS was invoked.
     */
    virtual void init_handler (graph& G) {}
    
    /**
     * Handler called at the end of DFS.
     *
     * @param <code>G</code> graph for which DFS was invoked.
     */
    virtual void end_handler (graph& G) {}

    /**
     * Handler called when touching node <code>n</code>.
     *
     * @param <code>G</code> graph for which DFS was invoked.
     * @param <code>n</code> actual node.
     * @param <code>f</code> predecessor.
     */
    virtual void entry_handler (graph& G, node& n, node& f) {}

    /**
     * Handler called after all the adjacent edges of <code>n</code> have been 
     * examined.
     *
     * @param <code>G</code> graph for which DFS was invoked.
     * @param <code>n</code> actual node.
     * @param <code>f</code> predecessor.
     */
    virtual void leave_handler (graph& G, node& n, node& f) {}

    /**
     * Handler called when a unused node <code>n</code> connected to the
     * actual node by <code>e</code> is found. 
     *
     * @param <code>G</code> graph for which DFS was invoked.
     * @param <code>e</code> edge connecting the actual node to the unused one.
     * @param <code>n</code> unused node.
     */
    virtual void before_recursive_call_handler (graph& G, edge& e, node& n) {}
    
    /**
     * Handler called after the algorithm return from the subtree starting 
     * at <code>n</code> connected to the actual node by <code>e</code>. 
     *
     * @param <code>G</code> graph for which DFS was invoked.
     * @param <code>e</code> edge connecting the actual node to the unused one.
     * @param <code>n</code> unused node.
     */
    virtual void after_recursive_call_handler (graph& G, edge& e, node& n) {}
    
    /**
     * Handler called when a already marked node <code>n</code> connected 
     * to the actual node by <code>e</code> is found during the search of all 
     * adjacent edges of the actual node
     *
     * @param <code>G</code> graph for which DFS was invoked.
     * @param <code>e</code> edge connecting the actual node to the old one.
     * @param <code>n</code> used node.
     */
    virtual void old_adj_node_handler (graph& G, edge& e, node& n) {}

    /**
     * Called when DFS is started with start-node
     * <code>n</code>. This is particularly useful when 
     * DFS was invoked with the <code>scan_whole_graph</code>
     * option.
     *
     * @param <code>G</code> graph for which DFS was invoked.
     * @param <code>n</code> start-node.
     */
    virtual void new_start_handler (graph& G, node& n) { };

private:

    /**
     * @internal
     */
    void dfs_sub (graph&, node&, node&);

protected:    

    //----------------------------------------------------------------------
    //   Data
    //----------------------------------------------------------------------

    /**
     * @internal
     */
    int act_dfs_num;
    /**
     * @internal
     */
    int act_comp_num;
    /**
     * @internal
     */
    list<edge> tree;
    /**
     * @internal
     */
    list<node> dfs_order;
    /**
     * @internal
     */
    node_map<int> dfs_number;
    /**
     * @internal
     */
    int reached_nodes;
    /**
     * @internal
     */
    edge_map<int>* used;
    /**
     * @internal
     */
    list<dfs_iterator> roots;
    

    //-----------------------------------------------------------------------
    // Optional 
    //-----------------------------------------------------------------------
    
    /**
     * @internal
     */
    node_map<int>* comp_number;
    /**
     * @internal
     */
    node_map<node>* preds;
    /**
     * @internal
     */
    list<edge>* back_edges;
    /**
     * @internal
     */
    node start;
    /**
     * @internal
     */
    bool whole_graph;
};

__GTL_END_NAMESPACE

#endif // GTL_DFS_H

//--------------------------------------------------------------------------
//   end of file
//--------------------------------------------------------------------------
