/*
* EuroCarbDB, a framework for carbohydrate bioinformatics
*
* Copyright (c) 2006-2009, Eurocarb project, or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
* A copy of this license accompanies this distribution in the file LICENSE.txt.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* Last commit: $Rev: 1147 $ by $Author: glycoslave $ on $Date:: 2009-06-04 #$
*/
package org.eurocarbdb.util.graph;
import java.util.Set;
import java.util.HashSet;
import org.apache.log4j.Logger;
import org.eurocarbdb.util.Visitor;
/**
* Walks a {@link Graph}, visiting every Vertex and Edge in order.
* See the {@link accept(Graph)} method for details.
*
* Note that this traversal class is not re-entrant; the default
* implementation cannot traverse a Graph that contains nested Graphs.
*
* @author mjh
*/
public class GraphVisitor<E,V> extends Visitor
{
/** Inheritable logging handle */
protected static Logger log = Logger.getLogger( DepthFirstGraphVisitor.class );
/** Set of visited {@link Vertex}es. */
protected Set<Vertex<E,V>> visitedVertices = new HashSet<Vertex<E,V>>();
/** Set of unvisited {@link Vertex}es. */
protected Set<Vertex<E,V>> unvisitedVertices = new HashSet<Vertex<E,V>>();
/** Set of visited {@link Edge}s. */
protected Set<Edge<E,V>> visitedEdges = new HashSet<Edge<E,V>>();
/**
* Resets this visitor to its starting state, including the
* {@link Set} of {@link #visitedVertices visited} vertices.
*/
public void clear()
{
visitedVertices.clear();
visitedEdges.clear();
}
/**
* Called when visiting a {@link Graph}.
*
* The default implementation visits all {@link Vertex}es and {@link Edge}s
* in depth-first order, starting from the Graph's root vertex, as given
* by the method {@link Graph#getRootVertex()}.
*
*/
public void accept( Graph<E,V> g )
{
log.debug("visiting graph of size=" + g.size() );
if ( g.isEmpty() )
{
log.debug("graph is empty, returning...");
return;
}
this.clear();
Vertex<E,V> cursor = g.getRootVertex();
unvisitedVertices.addAll( g.getAllVertices() );
while ( cursor != null && ! unvisitedVertices.isEmpty() )
{
visit( cursor );
cursor = unvisitedVertices.iterator().next();
}
}
/**
* This method is called on visiting a Vertex; the default implementation
* first visits this {@link Vertex}'s {@link Vertex.getValue() value},
* then each of this Vertex's {@link Vertex.getAttachedEdges() attached edges}.
*
* @see Vertex.getValue()
* @see Vertex.getAttachedEdges()
*/
public void accept( Vertex<E,V> v )
{
// return if Vertex already visited (ie: add returns false)
if ( ! visitedVertices.add( v ) )
return;
unvisitedVertices.remove( v );
log.debug("visiting vertex: " + v );
// visit Vertex value first
visit( v.getValue() );
// then visit attached Edges
for ( Edge<E,V> e : v.getAttachedEdges() )
if ( ! visitedEdges.contains( e ) )
visit( e );
return;
}
/**
* This method is called on visiting an Edge; the default implementation
* first visits this {@link Edge}'s {@link Edge.getValue() value},
* then the {@link Edge.getParent() parent} and {@link Edge.getChild() child}
* vertexes of this Edge.
*
* @see Edge.getValue()
* @see Edge.getParent()
* @see Edge.getChild()
*/
public void accept( Edge<E,V> e )
{
// return if Edge already visited (ie: add returns false)
if ( ! visitedEdges.add( e ) )
return;
log.debug("visiting edge: " + e );
// visit value first
visit( e.getValue() );
Vertex<E,V> v;
// visit edge's parent vertex (if not already)
v = e.getParent();
if ( ! visitedVertices.contains( v ) )
visit( v );
// visit edge's child vertex (if not already)
v = e.getChild();
if ( ! visitedVertices.contains( v ) )
visit( v );
}
} // end class