//==========================================================================
//
//   biconnectivity.h
//
//==========================================================================
// $Id: biconnectivity.h,v 1.15 2000/01/05 16:32:33 raitner Exp $

#ifndef GTL_BICONNECTIVITY_H
#define GTL_BICONNECTIVITY_H

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

#include <list>
#include <stack>

__GTL_BEGIN_NAMESPACE

/**
 * @short Biconnectivity-test and low-numbers.
 *
 * Obviously there is a close relationship between DFS and the testing of
 * biconnectivity. Thus this test takes advantage of the possibility to 
 * add pieces of code to the DFS-class in order to calculate the
 * low-numbers. 
 */

class GTL_EXTERN biconnectivity : public dfs 
{
public:
    /**
     * Creates biconnectivity algorithm object.
     *
     * @see dfs#dfs
     */
    biconnectivity ();

    /**
     * Destroys biconnectivity algorithm object.
     *
     * @see dfs#~dfs
     */
    virtual ~biconnectivity () {}

    /**
     * Necessary preconditions:
     * <ul>
     * <li> <code>G</code> is undirected.
     * <li> storing of predecessors is enabled.
     * <li> DFS may be applied 
     * </ul>
     * 
     * @param <code>G</code> graph.
     * @return <code>algorithm::GTL_OK</code> if binconnectivity-test can
     * be applied to <code>G</code>.
     * @see dfs#scan_whole_graph
     * @see dfs#store_preds
     */
    virtual int check (graph& G);

    
    /**
     * Reset
     */
    virtual void reset ();


    /**
     * Low-number. 
     *
     * @param <code>n</code> node.
     * @return Low-number of <code>n</code>.
     */
    int low_number (const node& n) const 
	{return low_num[n];}

    /**
     * Biconnectivity-test. 
     * 
     * @return true iff graph is biconnected.
     */
    bool is_biconnected () const 
	{return num_of_components == 1;}

    /**
     * Returns whether the storing of components is enabled.
     * 
     * @return true iff storing of components is enabled.
     * @see biconnectivity#components_begin
     * @see biconnectivity#components_end
     */
    bool store_components () const
	{ return store_comp; }

    /**
     * Enables or disables the storing of biconnected components.
     * If this feature is enabled, the whole graph will be scanned
     * in order to get all the biconnected components even if the graph
     * isn't connected. By default this feature is disabled.
     * 
     * @param <code>set</code> if true each biconnected component will be
     *   stored.
     * @see biconnectivity#components_begin
     * @see biconnectivity#components_end
     */
    void store_components (bool set) 
	{ store_comp  = set; if (set) scan_whole_graph (set); }
    
    /**
     * If enabled edges will be added to the graph in order to make it 
     * biconnected, if cutpoints are discovered. The list of added edges 
     * can be accessed via <code>additional_begin</code> and
     * <code>additional_end</code>.
     *
     * @param <code>set</code> if true additional edges will we inserted
     *    to make the graph biconnected.
     * @see biconnectivity#additional_begin
     * @see biconnectivity#additional_end
     */
    void make_biconnected (bool set) 
	{ add_edges = set; if (set) scan_whole_graph (set); }
    
    /**
     * Returns whether addition of edges neccessary to make graph
     * biconnected is enabled. 
     * 
     * @return true iff addition edges is enabled.
     * @see biconnectivity#additional_begin
     * @see biconnectivity#additional_end
     */
    bool make_biconnected () const 
	{ return add_edges; }
    
    /**
     * Begin of edges added to make graph biconnected.
     * 
     * @return begin of additional edges
     * @see biconnectivity#make_biconnected
     * @see biconnectivity#make_biconnected
     */
    list<edge>::iterator additional_begin ()
	{ return additional.begin (); }

    /**
     * End of edges added to make graph biconnected
     * 
     * @return end of additional edges
     * @see biconnectivity#make_biconnected
     * @see biconnectivity#make_biconnected
     */
    list<edge>::iterator additional_end ()
	{ return additional.end (); }
    
    /**
     * @internal
     */
    typedef list<node>::iterator cutpoint_iterator;

    /**
     * Start iteration over all cutpoints found. A cutpoints is a node 
     * whose removal will disconnect the graph, thus a graph with no
     * cutpoints is biconnected and vice versa.
     * 
     * @return iterator to first cutpoint.
     * @see biconnectivity#cut_points_end
     */
    cutpoint_iterator cut_points_begin () 
	{ return cut_points.begin(); }

    /**
     * End of iteration over all cutpoints.
     * 
     * @return one-past-the-end iterator.
     * @see biconnectivity#cut_points_begin
     */
    cutpoint_iterator cut_points_end () 
	{ return cut_points.end(); }


    /**
     * @internal
     */
    typedef list<pair<list<node>, list<edge> > >::iterator component_iterator;

    /**
     * Start iteration over all biconnected components (if enabled during
     * last call to run). Components are represented as a pair consisting of
     * a list of nodes and a list of edges,
     * i.e. if <code>it</code> is of type <code>component_iterator</code>
     * then <code>*it</code> is of type 
     * <code>pair&lt;list&lt;node&gt;,list&lt;edge&gt; &gt;</code>. 
     *
     * @return iterator to first component 
     * @see biconnectivity#store_components
     * @see graph#induced_subgraph
     */
    component_iterator components_begin ()
	{ return components.begin(); }


    /**
     * End of iteration over all biconnected components.
     *
     * @return end of iteration over biconnected components
     * @see biconnectivity#store_components
     */
    component_iterator components_end ()
	{ return components.end(); }

    /**
     * Number von biconnected components detected during the last run.
     * 
     * @return number of biconnected components.
     */
    int number_of_components () const
	{return num_of_components; }

    //-----------------------------------------------------------------------
    //   Handler used to extend dfs to biconnectivity
    //-----------------------------------------------------------------------
    /**
     * @internal
     */
    virtual void init_handler (graph&);

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

    /**
     * @internal
     */
    virtual void before_recursive_call_handler (graph&, edge&, node&);

    /**
     * @internal
     */
    virtual void after_recursive_call_handler (graph&, edge&, node&);

    /**
     * @internal
     */
    virtual void old_adj_node_handler (graph&, edge&, node&);

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

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


protected:

    /**
     * @internal
     */
    node_map<int> low_num;
    /**
     * @internal
     */
    int num_of_components;
    /**
     * @internal
     */
    bool store_comp;
    /**
     * @internal
     */
    bool add_edges;
    /**
     * @internal
     */
    node last;
    /**
     * @internal
     */
    stack<node> node_stack;
    /**
     * @internal
     */
    stack<edge> edge_stack;
    /**
     * @internal
     */
    list<pair<list<node>, list<edge> > > components;
    /**
     * @internal
     */
    list<node> cut_points;
    /**
     * @internal
     */
    node_map<int> cut_count;
    /**
     * @internal
     */
    list<edge> additional;
    /**
     * @internal
     */
    node_map<node> first_child;
};

__GTL_END_NAMESPACE

#endif // GTL_BICONNECTIVITY_H

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