// Copyright (C) 1996 DIMACS Center, Rutgers, The State University of New Jersey
// Author(s): Chris Burrows (Trenton State College)

// This software is copyrighted by the DIMACS Center at Rutgers, The State
// University of New Jersey.  IT IS PROVIDED AS IS, AND THE AUTHORS, DIMACS, AND
// RUTGERS, THE STATE UNIVERSITY OF NEW JERSEY  DISCLAIM
// ALL LIABILITY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
// DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
// DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

// THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
// IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
// NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
// MODIFICATIONS.

// The authors hereby grant permission to use, copy, modify, distribute,
// and license this software and its documentation for any purpose, provided
// that existing copyright notices are retained in all copies and that this
// notice is included verbatim in any distributions. No written agreement,
// license, or royalty fee is required for any of the authorized uses.
// Modifications to this software may be copyrighted by their authors
// and need not follow the licensing terms described here, provided that
// the new terms are clearly indicated on the first page of each file where
// they apply.

// Last File Update: 17-Sep-1996
// 


#include <LINK/graph/Graph.h>
#include <LINK/graph/Vertex.h>
#include <LINK/graph/Edge.h>
#include <LINK/graph/Attribute.h>
#include <LINK/algorithm/Algorithms.h>

// rev_compare_vertices_by_finishtime()
// for sorting our list of vertices (reversed, by finishtime)
typedef Vertex* VertexPtr;
int rev_compare_vertices_by_finishtime(const VertexPtr& v1, 
				       const VertexPtr& v2) {
    int t1, t2;
    getAttribute((GraphObject*) v1, "finishtime", t1);
    getAttribute((GraphObject*) v2, "finishtime", t2);
    return (t2 - t1);
}


// root_vertex()
// after a DFS(), what is the root of this vertex's tree in the DFS forest?
Vertex*
root_vertex(Vertex*v) {
    Vertex* pred;
    getAttribute((GraphObject*)v, "pred", pred);
    if(pred) {
	return root_vertex(pred);
    }
    else {
	return v;
    }
}


// StronglyConnectedComponents()
// returns a set of the strongly connected components
Set< Set <Vertex*> >
StronglyConnectedComponents(Graph *graph, char *graph_view) {

    Set< Set<Vertex*> > result;

    //if (!graph->binaryQ() || !graph->directedQ()) {
    if (!graph->binaryQ()) {
	error("StronglyConnectedComponents: Graph must"
	      " be binary");
	return result;
    }

    DepthFirstSearch(graph);

    Graph* grapht = graph->transpose(CLONE);

    Sequence<Vertex*> dfs;
    dfs = DepthFirstSearch(grapht, rev_compare_vertices_by_finishtime, 0);

    Set<Vertex*> scc;
    Iterator<Vertex*> get_v(&dfs);
    Vertex *gt_v, *cur_leader_in_g, *g_v;
    int current_dfs_tree, new_dfs_tree;

    get_v(gt_v);
    cur_leader_in_g = graph->vertex(grapht->rank(gt_v));
    scc.insert(cur_leader_in_g);
    setAttribute((GraphObject*)cur_leader_in_g, "forefather", 
				   cur_leader_in_g);

    getAttribute((GraphObject*)gt_v, "type", current_dfs_tree);
    while(get_v(gt_v)) {
    	getAttribute((GraphObject*)gt_v, "type", new_dfs_tree);
	if (new_dfs_tree == current_dfs_tree) {
    		g_v = graph->vertex(grapht->rank(gt_v));
    		scc.insert(g_v);
    		setAttribute((GraphObject*)g_v, "forefather", 
					   cur_leader_in_g);
	} else {
		result.insert(scc);
    		scc.clear();
		cur_leader_in_g = graph->vertex(grapht->rank(gt_v));
    		scc.insert(cur_leader_in_g);
    		setAttribute((GraphObject*)cur_leader_in_g, "forefather", 
					   cur_leader_in_g);
	}
        current_dfs_tree = new_dfs_tree;
    }
    result.insert(scc);
    
    delete grapht;
    return result;
}
