//----------------------------------------------------------------------------//
// //
// B a s i c V e r t e x //
// //
//----------------------------------------------------------------------------//
// <editor-fold defaultstate="collapsed" desc="hdr"> //
// Copyright © Hervé Bitteur and others 2000-2013. All rights reserved. //
// This software is released under the GNU General Public License. //
// Goto http://kenai.com/projects/audiveris to report bugs or suggestions. //
//----------------------------------------------------------------------------//
// </editor-fold>
package omr.graph;
import net.jcip.annotations.NotThreadSafe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
/**
* Class {@code BasicVertex} is a basic implementation of {@link Vertex}.
*
* <p>NOTA: This plain Vertex type has no room for user-defined data, if such
* feature is needed then a proper subtype of BasicVertex should be used.
*
* <p>This class is not thread-safe, because it is not intended to be used by
* several threads simultaneously. However, the graph structure which contains
* instances of vertices is indeed thread-safe.
*
* @param <D> type for enclosing digraph precise subtype
* @param <V> type for Vertex precise subtype
*
* @author Hervé Bitteur
*/
@NotThreadSafe
@XmlAccessorType(XmlAccessType.NONE)
public abstract class BasicVertex<D extends Digraph, V extends Vertex<D, V>>
implements Vertex<D, V>
{
//~ Static fields/initializers ---------------------------------------------
/** Usual logger utility */
private static final Logger logger = LoggerFactory.getLogger(BasicVertex.class);
//~ Instance fields --------------------------------------------------------
/**
* Unique vertex Id (for debugging mainly)
*/
private int id;
/**
* Incoming edges from other vertices
*/
protected final List<V> sources = new ArrayList<>();
/**
* Outgoing edges to other vertices
*/
protected final List<V> targets = new ArrayList<>();
/**
* Containing graph
*/
protected D graph;
/**
* Sequence of views created on this vertex. Index in the sequence is
* important, since this sequence is kept parallel to the sequence of views
* on the containing graph.
*/
protected List<VertexView> views;
//~ Constructors -----------------------------------------------------------
//--------//
// Vertex //
//--------//
/**
* Create a Vertex.
*/
protected BasicVertex ()
{
logger.debug("new vertex");
}
//--------//
// Vertex //
//--------//
/**
* Create a Vertex in a graph.
*
* @param graph The containing graph where this vertex is to be hosted
*/
protected BasicVertex (D graph)
{
logger.debug("new vertex in graph {}", graph);
graph.addVertex(this); // Compiler warning here
}
//~ Methods ----------------------------------------------------------------
//-----------//
// addTarget //
//-----------//
@Override
public void addTarget (V target)
{
logger.debug("adding edge from {} to {}", this, target);
// Assert we have real target
if (target == null) {
throw new IllegalArgumentException(
"Cannot add an edge to a null target");
}
// Assert this vertex and target vertex belong to the same graph
if (this.getGraph() != target.getGraph()) {
throw new RuntimeException(
"An edge can link vertices of the same graph only");
}
// Avoid duplicates
getTargets().remove(target);
target.getSources().remove((V) this);
targets.add(target);
target.getSources().add((V) this);
}
//---------//
// addView //
//---------//
@Override
public void addView (VertexView view)
{
getViews().add(view);
}
//------------//
// clearViews //
//------------//
@Override
public void clearViews ()
{
getViews().clear();
}
//--------//
// delete //
//--------//
@Override
public void delete ()
{
try {
logger.debug("deleting vertex {}", this);
// Remove in vertices of the vertex
for (V source : new ArrayList<>(getSources())) {
source.removeTarget((V) this, false);
}
// Remove out vertices of the vertex
for (V target : new ArrayList<>(getTargets())) {
removeTarget(target, false);
}
// Remove from graph
graph.removeVertex(this);
} catch (Exception ex) {
logger.error("Error deleting " + this, ex);
}
}
//------//
// dump //
//------//
@Override
public void dump ()
{
StringBuilder sb = new StringBuilder();
// The vertex
sb.append(String.format("%s%n", this));
// The in edges
for (V vertex : sources) {
sb.append(String.format(" edge from %s%n", vertex));
}
// The out edges
for (V vertex : targets) {
sb.append(String.format(" edge to %s%n", vertex));
}
logger.info(sb.toString());
}
//----------//
// getGraph //
//----------//
@Override
public D getGraph ()
{
return graph;
}
//-------//
// getId //
//-------//
@Override
public int getId ()
{
return id;
}
//-------------//
// getInDegree //
//-------------//
@Override
public int getInDegree ()
{
return sources.size();
}
//--------------//
// getOutDegree //
//--------------//
@Override
public int getOutDegree ()
{
return targets.size();
}
//------------//
// getSources //
//------------//
@Override
public List<V> getSources ()
{
return sources;
}
//------------//
// getTargets //
//------------//
@Override
public List<V> getTargets ()
{
return targets;
}
//---------//
// getView //
//---------//
@Override
public VertexView getView (int index)
{
return getViews().get(index);
}
//---------------//
// getViewsCount //
//---------------//
@Override
public int getViewsCount ()
{
return getViews().size();
}
//--------------//
// removeTarget //
//--------------//
@Override
public void removeTarget (V target,
boolean strict)
{
// Assert we have real target
if (target == null) {
throw new IllegalArgumentException(
"Cannot remove an edge to a null target");
}
if (!this.targets.remove(target) && strict) {
throw new RuntimeException(
"Attempting to remove non-existing edge between " + this
+ " and " + target);
}
if (!target.getSources().remove((V) this) && strict) {
throw new RuntimeException(
"Attempting to remove non-existing edge between " + this
+ " and " + target);
}
}
//----------//
// setGraph //
//----------//
/**
* (package access from graph)
*/
@Override
public void setGraph (D graph)
{
this.graph = graph;
}
//-------//
// setId //
//-------//
@XmlAttribute
@Override
public void setId (int id)
{
this.id = id;
}
//----------//
// toString //
//----------//
@Override
public String toString ()
{
StringBuilder sb = new StringBuilder();
sb.append("{").append(getClass().getSimpleName()).append("#").append(id);
sb.append(internalsString());
sb.append("}");
return sb.toString();
}
//-----------------//
// internalsString //
//-----------------//
/**
* Return the string of the internals of this class, typically for inclusion
* in a toString. The overriding methods, if any, should return a string
* that begins with a " " followed by some content.
*
* @return the string of internals
*/
protected String internalsString ()
{
StringBuilder sb = new StringBuilder(100);
sb.append(" ").append(getInDegree());
sb.append("/").append(getOutDegree());
return sb.toString();
}
//----------//
// getViews //
//----------//
/**
* Report the sequence of the related views, lazily created.
*
* @return the views collection (perhaps empty, but not null)
*/
private List<VertexView> getViews ()
{
if (views == null) {
views = new ArrayList<>();
}
return views;
}
}