//==================================================================================================
// G r a p h                                                                                   Java
// J a v a G r a p h
//                                                                                By Bruno Bachelet
//==================================================================================================
// Copyright (c) 1999-2016
// Bruno Bachelet - bruno@nawouak.net - http://www.nawouak.net
//
// This file is part of the B++ Library. This library is free software; you can redistribute it
// and/or modify it under the terms of the GNU Library General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This library 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 Library General Public License for more details (http://www.gnu.org).

/*DESCRIPTION*/
/* This module provides a class to model a graph in Java. */

// Package //---------------------------------------------------------------------------------------
package bpp.graph;

// Importation //-----------------------------------------------------------------------------------
import java.lang.Exception;
import java.util.Collection;
import java.util.Iterator;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.Vector;
import bpp.data_structure.extension.*;

@SuppressWarnings("unchecked")

// J a v a G r a p h  Class //----------------------------------------------------------------------
/*CLASS JavaGraph */ /* Represents a graph. */
public class JavaGraph {
 //---------------------------------------------------------------------------------------Attributes
 protected ExtendableMap atArcX;  // List of the arcs.
 protected ExtendableMap atNodeX; // List of the nodes.
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD JavaGraph */ /* Builds a new graph. */
 public JavaGraph() {
  atArcX=new ExtendableMap(new TreeMap());
  atNodeX=new ExtendableMap(new TreeMap());
 }
 //---------------------------------------------------------------------------------------------Arcs
 /*METHOD JavaGraph */ /* Returns a collection of the arcs of the graph. */
 public Collection arcs() { return (atArcX.values()); }
 //--------------------------------------------------------------------------------------------Nodes
 /*METHOD JavaGraph */ /* Returns a collection of the nodes of the graph. */
 public Collection nodes() { return (atNodeX.values()); }
 //----------------------------------------------------------------------------------------------Arc
 /*METHOD JavaGraph */ /* Returns the arc associated with a given key. */
 public Arc arc(long agKey) { return ((Arc)(atArcX.get(new Long(agKey)))); }
 //---------------------------------------------------------------------------------------------Node
 /*METHOD JavaGraph */ /* Returns the node associated with a given key. */
 public Node node(long agKey) { return ((Node)(atNodeX.get(new Long(agKey)))); }
 //-------------------------------------------------------------------------------------GetNewArcKey
 /*METHOD JavaGraph */ /* Gets randomly a new arc key that is not used yet. */
 public long getNewArcKey() {
  Long lcKey;

  do { lcKey=new Long((long)(Math.random()*((long)1 << 32))); }
  while (atArcX.containsKey(lcKey));

  return (lcKey.longValue());
 }
 //------------------------------------------------------------------------------------GetNewNodeKey
 /*METHOD JavaGraph */ /* Gets randomly a new node key that is not used yet. */
 public long getNewNodeKey() {
  Long lcKey;

  do { lcKey=new Long((long)(Math.random()*((long)1 << 32))); }
  while (atNodeX.containsKey(lcKey));

  return (lcKey.longValue());
 }
 //-------------------------------------------------------------------------------------------AddArc
 /*METHOD JavaGraph */
 /* Adds an arc between two nodes into the graph. Source and target nodes can be
    <CODE>null</CODE>. */
 public Arc addArc(long agKey,String agName,Node agSource,Node agTarget) throws Exception {
  Arc  lcArc = new Arc(this,agKey,agName,agSource,agTarget);
  Long lcKey = new Long(agKey);

  if (atArcX.containsKey(lcKey))
   throw new Exception("Graph - An arc already has this key in the graph.");

  if (agSource!=null && agSource.graph()!=this)
   throw new Exception("Graph - The source node doesn't belong to the graph.");

  if (agTarget!=null && agTarget.graph()!=this)
   throw new Exception("Graph - The target node doesn't belong to the graph.");

  atArcX.put(lcKey,lcArc);
  lcArc.setSourceNode(agSource);
  lcArc.setTargetNode(agTarget);
  return (lcArc);
 }
 //-------------------------------------------------------------------------------------------AddArc
 /*METHOD JavaGraph */ /* Adds an arc into the graph. Its name is an empty string. */
 public Arc addArc(long agKey,Node agSource,Node agTarget) throws Exception
 { return (addArc(agKey,"",agSource,agTarget)); }
 //-------------------------------------------------------------------------------------------AddArc
 /*METHOD JavaGraph */ /* Adds an arc into the graph. Its key is randomly chosen. */
 public Arc addArc(String agName,Node agSource,Node agTarget) throws Exception
 { return (addArc(getNewArcKey(),agName,agSource,agTarget)); }
 //-------------------------------------------------------------------------------------------AddArc
 /*METHOD JavaGraph */
 /* Adds an arc into the graph. Its name is an empty string and its key is randomly chosen. */
 public Arc addArc(Node agSource,Node agTarget) throws Exception
 { return (addArc(getNewArcKey(),"",agSource,agTarget)); }
 //------------------------------------------------------------------------------------------AddNode
 /*METHOD JavaGraph */ /* Adds a node into the graph. */
 public Node addNode(long agKey,String agName) throws Exception {
  Node lcNode = new Node(this,agKey,agName);
  Long lcKey  = new Long(agKey);

  if (atNodeX.containsKey(lcKey))
   throw new Exception("Graph - A node already has this key in the graph.");

  atNodeX.put(lcKey,lcNode);
  return (lcNode);
 }
 //------------------------------------------------------------------------------------------AddNode
 /*METHOD JavaGraph */ /* Adds a node into the graph. Its name is an empty string. */
 public Node addNode(long agKey) throws Exception { return (addNode(agKey,"")); }
 //------------------------------------------------------------------------------------------AddNode
 /*METHOD JavaGraph */ /* Adds a node into the graph. Its key is randomly chosen. */
 public Node addNode(String agName) throws Exception { return (addNode(getNewNodeKey(),agName)); }
 //------------------------------------------------------------------------------------------AddNode
 /*METHOD JavaGraph */
 /* Adds a node into the graph. Its name is an empty string and its key is randomly chosen. */
 public Node addNode() throws Exception { return (addNode(getNewNodeKey(),"")); }
 //----------------------------------------------------------------------------------------RemoveArc
 /*METHOD JavaGraph */ /* Removes the arc associated with a given key from the graph. */
 public void removeArc(long agKey) throws Exception {
  Long lcKey = new Long(agKey);
  Arc  lcArc = (Arc)atArcX.get(lcKey);

  if (lcArc==null) throw new Exception("Graph - No arc has this key in the graph.");
  removeArc(lcArc);
 }
 //----------------------------------------------------------------------------------------RemoveArc
 /*METHOD JavaGraph */ /* Removes a given arc from the graph. */
 public void removeArc(Arc agArc) throws Exception {
  if (agArc.graph()!=this) throw new Exception("Graph - This arc doesn't belong to the graph.");
  agArc.setSourceNode(null);
  agArc.setTargetNode(null);
  atArcX.remove(new Long(agArc.key()));
 }
 //---------------------------------------------------------------------------------------RemoveNode
 /*METHOD JavaGraph */ /* Removes the node associated with a given key from the graph. */
 public void removeNode(long agKey) throws Exception {
  Long lcKey  = new Long(agKey);
  Node lcNode = (Node)atNodeX.get(lcKey);

  if (lcNode==null) throw new Exception("Graph - No node has this key in the graph.");
  removeNode(lcNode);
 }
 //---------------------------------------------------------------------------------------RemoveNode
 /*METHOD JavaGraph */ /* Removes a given node from the graph. */
 public void removeNode(Node agNode) throws Exception {
  Arc      lcArc;
  Iterator lcIterator;

  if (agNode.graph()!=this) throw new Exception("Graph - This node doesn't belong to the graph.");
  lcIterator=agNode.incomingArcs().iterator();

  while (lcIterator.hasNext()) {
   lcArc=(Arc)lcIterator.next();
   lcArc.setSourceNode(null);
   atArcX.remove(new Long(lcArc.key()));
  }

  lcIterator=agNode.outgoingArcs().iterator();

  while (lcIterator.hasNext()) {
   lcArc=(Arc)lcIterator.next();
   lcArc.setTargetNode(null);
   atArcX.remove(new Long(lcArc.key()));
  }

  atNodeX.remove(new Long(agNode.key()));
 }
 //---------------------------------------------------------------------------------------RemoveArcs
 /*METHOD JavaGraph */ /* Removes all the arcs from the graph. */
 public void removeArcs() {
  Iterator lcIterator = atArcX.values().iterator();

  try {
   while (lcIterator.hasNext()) {
    removeArc((Arc)lcIterator.next());
    lcIterator=atArcX.values().iterator();
   }
  }

  catch (Exception agException) { System.out.println("[!] "+agException.getMessage()); }
 }
 //--------------------------------------------------------------------------------------RemoveNodes
 /*METHOD JavaGraph */ /* Removes all the nodes from the graph. */
 public void removeNodes() {
  Iterator lcIterator = atNodeX.values().iterator();

  try {
   while (lcIterator.hasNext()) {
    removeNode((Node)lcIterator.next());
    lcIterator=atNodeX.values().iterator();
   }
  }

  catch (Exception agException) { System.out.println("[!] "+agException.getMessage()); }
 }
 //--------------------------------------------------------------------------------------------Clear
 /*METHOD JavaGraph */ /* Removes all the nodes and arcs from the graph. */
 public void clear() {
  removeNodes();
  removeArcs();
 }
 //----------------------------------------------------------------------------------------Duplicate
 /*METHOD JavaGraph */ /* Duplicates the whole graph. */
 public JavaGraph duplicate() {
  Arc         lcArc1;
  Arc         lcArc2;
  Iterator    lcIterator1;
  Iterator    lcIterator2;
  Iterator    lcIterator3;
  Node        lcNode1;
  Node        lcNode2;
  PropertyMap lcPropertyMap1;
  PropertyMap lcPropertyMap2;

  JavaGraph lcGraph = new JavaGraph();

  try {
   // Arc Property Maps Duplication //
   lcIterator1=arcPropertyMaps().iterator();

   while (lcIterator1.hasNext()) {
    lcPropertyMap1=(PropertyMap)lcIterator1.next();
    lcGraph.attachArcProperty(lcPropertyMap1.name(),lcPropertyMap1.template().duplicate());
   }

   // Node Property Maps Duplication //
   lcIterator1=nodePropertyMaps().iterator();

   while (lcIterator1.hasNext()) {
    lcPropertyMap1=(PropertyMap)lcIterator1.next();
    lcGraph.attachNodeProperty(lcPropertyMap1.name(),lcPropertyMap1.template().duplicate());
   }

   // Nodes Duplication //
   lcIterator1=nodes().iterator();

   while (lcIterator1.hasNext()) {
    lcNode1=(Node)lcIterator1.next();
    lcNode2=lcGraph.addNode(lcNode1.key(),lcNode1.name());
    lcIterator2=nodePropertyMaps().iterator();
    lcIterator3=lcGraph.nodePropertyMaps().iterator();

    while (lcIterator2.hasNext()) {
     lcPropertyMap1=(PropertyMap)lcIterator2.next();
     lcPropertyMap2=(PropertyMap)lcIterator3.next();
     lcPropertyMap2.set(lcNode2,lcPropertyMap1.get(lcNode1));
    }
   }

   // Arcs Duplication //
   lcIterator1=arcs().iterator();

   while (lcIterator1.hasNext()) {
    lcArc1=(Arc)lcIterator1.next();

    lcArc2=lcGraph.addArc(lcArc1.key(),lcArc1.name(),lcGraph.node(lcArc1.sourceNode().key()),
                          lcGraph.node(lcArc1.targetNode().key()));

    lcIterator2=arcPropertyMaps().iterator();
    lcIterator3=lcGraph.arcPropertyMaps().iterator();

    while (lcIterator2.hasNext()) {
     lcPropertyMap1=(PropertyMap)lcIterator2.next();
     lcPropertyMap2=(PropertyMap)lcIterator3.next();
     lcPropertyMap2.set(lcArc2,lcPropertyMap1.get(lcArc1));
    }
   }
  }

  catch (Exception agException) { System.out.println("[!] "+agException.getMessage()); }

  return (lcGraph);
 }
 //---------------------------------------------------------------------------------------MergeNodes
 /*METHOD JavaGraph */ /* Merges two nodes. The resulting node is returned. */
 public Node mergeNodes(Node agNode1,Node agNode2) {
  Arc      lcArc;
  Vector   lcArcS;
  Iterator lcIterator;

  try {
   lcArcS=new Vector(agNode2.incomingArcs());
   lcIterator=lcArcS.iterator();

   while (lcIterator.hasNext()) {
    lcArc=(Arc)lcIterator.next();

    if (lcArc.sourceNode()==agNode1) removeArc(lcArc);
    else lcArc.setTargetNode(agNode1);
   }

   lcArcS=new Vector(agNode2.outgoingArcs());
   lcIterator=lcArcS.iterator();

   while (lcIterator.hasNext()) {
    lcArc=(Arc)lcIterator.next();

    if (lcArc.targetNode()==agNode1) removeArc(lcArc);
    else lcArc.setSourceNode(agNode1);
   }

   removeNode(agNode2);
  }

  catch (Exception agException) { System.out.println("[!] "+agException.getMessage()); }

  return (agNode1);
 }
 //-----------------------------------------------------------------------------------------ToString
 /*METHOD JavaGraph */ /* Returns a string that fully describes the state of the graph. */
 public String toString() {
  Iterator lcIterator;

  String lcString = "<graph_start>\n\n";

  lcString+="nb_nodes = "+atNodeX.size()+"\n";
  lcString+="nb_arcs = "+atArcX.size()+"\n";

  lcString+="\n<node_properties_start>\n";
  lcIterator=atNodeX.propertyMaps().iterator();
  while (lcIterator.hasNext()) lcString+=(PropertyMap)lcIterator.next()+"\n";
  lcString+="<node_properties_end>\n";

  lcString+="\n<arc_properties_start>\n";
  lcIterator=atArcX.propertyMaps().iterator();
  while (lcIterator.hasNext()) lcString+=(PropertyMap)lcIterator.next()+"\n";
  lcString+="<arc_properties_end>\n";

  lcString+="\n<nodes_start>\n";
  lcIterator=atNodeX.iterator();
  while (lcIterator.hasNext()) lcString+=(Node)lcIterator.next()+"\n";
  lcString+="<nodes_end>\n";

  lcString+="\n<arcs_start>\n";
  lcIterator=atArcX.iterator();
  while (lcIterator.hasNext()) lcString+=(Arc)lcIterator.next()+"\n";
  lcString+="<arcs_end>\n";

  return (lcString+"\n<graph_end>");
 }
 //---------------------------------------------------------------------------------------FromString
 /*METHOD JavaGraph */
 /* Changes the state of the graph according to the description provided by a given string. */
 public void fromString(String agString) throws Exception {
  Arc         lcArc;
  Node        lcNode;
  PropertyMap lcPropertyMap;
  String      lcString;

  StringTokenizer lcTokenizer = new StringTokenizer(agString);

  // Graph Start //
  lcString=lcTokenizer.nextToken();
  lcTokenizer=new StringTokenizer(agString=nextLine(agString));

  if (!lcString.equals("<graph_start>"))
   throw new Exception("Graph - Can't extract graph information from string.");

  // Node Property Maps //
  while (!agString.equals("") && !lcString.equals("<node_properties_start>")) {
   lcTokenizer=new StringTokenizer(agString=nextLine(agString));
   lcString=lcTokenizer.nextToken();
  }

  while (!agString.equals("") && lcString.equals("<node_properties_start>")) {
   lcTokenizer=new StringTokenizer(agString=nextLine(agString));
   lcString=lcTokenizer.nextToken();
  }

  if (agString.equals(""))
   throw new Exception("Graph - Can't extract graph information from string.");

  while (!agString.equals("") && lcString.equals("property")) {
   lcPropertyMap=new PropertyMap();
   lcPropertyMap.fromString(agString.substring(0,agString.indexOf('\n')));
   attachNodeProperty(lcPropertyMap.name(),lcPropertyMap.template().duplicate());
   lcTokenizer=new StringTokenizer(agString=nextLine(agString));
   lcString=lcTokenizer.nextToken();
  }

  if (!lcString.equals("<node_properties_end>"))
   throw new Exception("Graph - Can't extract graph information from string.");

  // Arc Property Maps //
  while (!agString.equals("") && !lcString.equals("<arc_properties_start>")) {
   lcTokenizer=new StringTokenizer(agString=nextLine(agString));
   lcString=lcTokenizer.nextToken();
  }

  while (!agString.equals("") && lcString.equals("<arc_properties_start>")) {
   lcTokenizer=new StringTokenizer(agString=nextLine(agString));
   lcString=lcTokenizer.nextToken();
  }

  if (agString.equals(""))
   throw new Exception("Graph - Can't extract graph information from string.");

  while (!agString.equals("") && lcString.equals("property")) {
   lcPropertyMap=new PropertyMap();
   lcPropertyMap.fromString(agString.substring(0,agString.indexOf('\n')));
   attachArcProperty(lcPropertyMap.name(),lcPropertyMap.template().duplicate());
   lcTokenizer=new StringTokenizer(agString=nextLine(agString));
   lcString=lcTokenizer.nextToken();
  }

  if (!lcString.equals("<arc_properties_end>"))
   throw new Exception("Graph - Can't extract graph information from string.");

  // Nodes //
  while (!agString.equals("") && !lcString.equals("<nodes_start>")) {
   lcTokenizer=new StringTokenizer(agString=nextLine(agString));
   lcString=lcTokenizer.nextToken();
  }

  while (!agString.equals("") && lcString.equals("<nodes_start>")) {
   lcTokenizer=new StringTokenizer(agString=nextLine(agString));
   lcString=lcTokenizer.nextToken();
  }

  if (agString.equals(""))
   throw new Exception("Graph - Can't extract graph information from string.");

  while (!agString.equals("") && lcString.equals("node")) {
   lcNode=addNode(Long.parseLong(lcTokenizer.nextToken()));
   lcNode.fromString(agString.substring(0,agString.indexOf('\n')));
   lcTokenizer=new StringTokenizer(agString=nextLine(agString));
   lcString=lcTokenizer.nextToken();
  }

  if (!lcString.equals("<nodes_end>"))
   throw new Exception("Graph - Can't extract graph information from string.");

  // Arcs //
  while (!agString.equals("") && !lcString.equals("<arcs_start>")) {
   lcTokenizer=new StringTokenizer(agString=nextLine(agString));
   lcString=lcTokenizer.nextToken();
  }

  while (!agString.equals("") && lcString.equals("<arcs_start>")) {
   lcTokenizer=new StringTokenizer(agString=nextLine(agString));
   lcString=lcTokenizer.nextToken();
  }

  if (agString.equals(""))
   throw new Exception("Graph - Can't extract graph information from string.");

  while (!agString.equals("") && lcString.equals("arc")) {
   lcArc=addArc(Long.parseLong(lcTokenizer.nextToken()),null,null);
   lcArc.fromString(agString.substring(0,agString.indexOf('\n')));
   lcTokenizer=new StringTokenizer(agString=nextLine(agString));
   lcString=lcTokenizer.nextToken();
  }
 }
 //-----------------------------------------------------------------------------------------NextLine
 protected String nextLine(String agString) {
  int lcPosition = agString.indexOf('\n');

  if (lcPosition==-1) return ("");
  return (agString.substring(lcPosition+1));
 }
 //--------------------------------------------------------------------------------AttachArcProperty
 /*METHOD JavaGraph */
 /* Attaches a property to all the arcs of the graph. A property map that allows to access this
    property for any arc is returned. */
 public PropertyMap attachArcProperty(String agName,Property agProperty)
 { return (atArcX.attachProperty(agName,agProperty)); }
 //-------------------------------------------------------------------------------AttachNodeProperty
 /*METHOD JavaGraph */
 /* Attaches a property to all the nodes of the graph. A property map that allows to access this
    property for any node is returned. */
 public PropertyMap attachNodeProperty(String agName,Property agProperty)
 { return (atNodeX.attachProperty(agName,agProperty)); }
 //--------------------------------------------------------------------------------DetachArcProperty
 /*METHOD JavaGraph */ /* Detaches a property from all the arcs of the graph. */
 public void detachArcProperty(PropertyMap agPropertyMap) { atArcX.detachProperty(agPropertyMap); }
 //-------------------------------------------------------------------------------DetachNodeProperty
 /*METHOD JavaGraph */ /* Detaches a property from all the nodes of the graph. */
 public void detachNodeProperty(PropertyMap agPropertyMap)
 { atNodeX.detachProperty(agPropertyMap); }
 //-----------------------------------------------------------------------------------ArcPropertyMap
 /*METHOD JavaGraph */
 /* Finds the property map for the arcs of the graph that is associated with a given name. */
 public PropertyMap arcPropertyMap(String agName) { return (atArcX.propertyMap(agName)); }
 //----------------------------------------------------------------------------------NodePropertyMap
 /*METHOD JavaGraph */
 /* Finds the property map for the nodes of the graph that is associated with a given name. */
 public PropertyMap nodePropertyMap(String agName) { return (atNodeX.propertyMap(agName)); }
 //----------------------------------------------------------------------------------ArcPropertyMaps
 /*METHOD JavaGraph */
 /* Returns a collection of all the property maps for the arcs of the graph. */
 public Collection arcPropertyMaps() { return (atArcX.propertyMaps()); }
 //---------------------------------------------------------------------------------NodePropertyMaps
 /*METHOD JavaGraph */
 /* Returns a collection of all the property maps for the nodes of the graph. */
 public Collection nodePropertyMaps() { return (atNodeX.propertyMaps()); }

 // J a v a G r a p h . A r c  Class //-------------------------------------------------------------
 /*CLASS JavaGraph.Arc */
 /* Represents an arc of a graph. Inner class of <CODE>JavaGraph</CODE>. */
 public static class Arc extends ExtendableObject {
  //--------------------------------------------------------------------------------------Attributes
  protected JavaGraph atGraph; // Graph that contains the arc.
  protected long      atKey;   // Key of the arc.
  protected String    atName;  // Name of the arc.

  protected Node  atSourceNode; // Node pointed by the source extremity of the arc.
  protected Node  atTargetNode; // Node pointed by the target extremity of the arc.
  //-------------------------------------------------------------------------------------Constructor
  protected Arc(JavaGraph agGraph,long agKey,String agName,Node agSource,Node agTarget) {
   atGraph=agGraph;
   atKey=agKey;
   atName=agName;
   atSourceNode=agSource;
   atTargetNode=agTarget;
  }
  //-------------------------------------------------------------------------------------------Graph
  /*METHOD JavaGraph.Arc */ /* Returns the graph that contains the arc. */
  public JavaGraph graph() { return (atGraph); }
  //---------------------------------------------------------------------------------------------Key
  /*METHOD JavaGraph.Arc */ /* Returns the key of the arc. */
  public long key() { return (atKey); }
  //--------------------------------------------------------------------------------------------Name
  /*METHOD JavaGraph.Arc */ /* Returns the name of the arc. */
  public String name() { return (atName); }
  //-----------------------------------------------------------------------------------------SetName
  /*METHOD JavaGraph.Arc */ /* Sets the name of the arc. */
  public void setName(String agName) { atName=agName; }
  //--------------------------------------------------------------------------------------SourceNode
  /*METHOD JavaGraph.Arc */ /* Returns the source node of the arc. */
  public Node sourceNode() { return (atSourceNode); }
  //--------------------------------------------------------------------------------------TargetNode
  /*METHOD JavaGraph.Arc */ /* Returns the target node of the arc. */
  public Node targetNode() { return (atTargetNode); }
  //-----------------------------------------------------------------------------------SetSourceNode
  /*METHOD JavaGraph.Arc */ /* Sets the source node of the arc, can be <CODE>null</CODE>. */
  public void setSourceNode(Node agNode) {
   if (atSourceNode!=null) atSourceNode.removeOutgoingArc(this);
   atSourceNode=agNode;
   if (atSourceNode!=null) atSourceNode.addOutgoingArc(this);
  }
  //-----------------------------------------------------------------------------------SetTargetNode
  /*METHOD JavaGraph.Arc */ /* Sets the target node of the arc, can be <CODE>null</CODE>. */
  public void setTargetNode(Node agNode) {
   if (atTargetNode!=null) atTargetNode.removeIncomingArc(this);
   atTargetNode=agNode;
   if (atTargetNode!=null) atTargetNode.addIncomingArc(this);
  }
  //-----------------------------------------------------------------------------------------Reverse
  /*METHOD JavaGraph.Arc */ /* Reverses the target and the source nodes of the arc. */
  public void reverse() {
   Node lcTempo = atSourceNode;

   setSourceNode(atTargetNode);
   setTargetNode(lcTempo);
  }
  //----------------------------------------------------------------------------------------ToString
  /*METHOD JavaGraph.Arc */ /* Returns a string that fully describes the state of the arc. */
  public String toString() {
   String lcString = "arc "+atKey+" = "+atName+" ; "+atSourceNode.key()+" , "+atTargetNode.key();

   return (lcString+" ; "+super.toString());
  }
  //--------------------------------------------------------------------------------------FromString
  /*METHOD JavaGraph.Arc */
  /* Changes the state of the arc according to the description provided by a given string. */
  public void fromString(String agString) throws Exception {
   String lcString;

   StringTokenizer lcTokenizer = new StringTokenizer(agString);

   lcString=lcTokenizer.nextToken();

   if (!lcString.equals("arc"))
    throw new Exception("Graph - Can't extract arc information from string.");

   lcTokenizer.nextToken();
   lcTokenizer.nextToken();
   lcString=lcTokenizer.nextToken();

   if (lcString.equals(";")) atName="";
   else {
    atName=lcString;
    lcTokenizer.nextToken();
   }

   setSourceNode(graph().node(Long.parseLong(lcTokenizer.nextToken())));
   lcTokenizer.nextToken();
   setTargetNode(graph().node(Long.parseLong(lcTokenizer.nextToken())));
   super.fromString(agString.substring(agString.lastIndexOf(" ; ")+3));
  }
 }

 // J a v a G r a p h . N o d e  Class //-----------------------------------------------------------
 /*CLASS JavaGraph.Node */
 /* Represents a node of a graph. Inner class of <CODE>JavaGraph</CODE>. */
 public static class Node extends ExtendableObject {
  //--------------------------------------------------------------------------------------Attributes
  protected JavaGraph atGraph; // Graph that contains the node.
  protected long      atKey;   // Key of the node.
  protected String    atName;  // Name of the node.

  protected TreeMap atIncomingX; // Set of the arcs incoming to this node.
  protected TreeMap atOutgoingX; // Set of the arcs outgoing from this node.
  //-------------------------------------------------------------------------------------Constructor
  protected Node(JavaGraph agGraph,long agKey,String agName) {
   atGraph=agGraph;
   atKey=agKey;
   atName=agName;
   atIncomingX=new TreeMap();
   atOutgoingX=new TreeMap();
  }
  //-------------------------------------------------------------------------------------------Graph
  /*METHOD JavaGraph.Node */ /* Returns the graph that contains the node. */
  public JavaGraph graph() { return (atGraph); }
  //---------------------------------------------------------------------------------------------Key
  /*METHOD JavaGraph.Node */ /* Returns the key of the node. */
  public long key() { return (atKey); }
  //--------------------------------------------------------------------------------------------Name
  /*METHOD JavaGraph.Node */ /* Returns the name of the node. */
  public String name() { return (atName); }
  //-----------------------------------------------------------------------------------------SetName
  /*METHOD JavaGraph.Node */ /* Sets the name of the node. */
  public void setName(String agName) { atName=agName; }
  //------------------------------------------------------------------------------------IncomingArcs
  /*METHOD JavaGraph.Node */ /* Returns a collection of the incoming arcs of the node. */
  public Collection incomingArcs() { return (atIncomingX.values()); }
  //------------------------------------------------------------------------------------OutgoingArcs
  /*METHOD JavaGraph.Node */ /* Returns a collection of the outgoing arcs of the node. */
  public Collection outgoingArcs() { return (atOutgoingX.values()); }
  //-------------------------------------------------------------------------------------IncomingArc
  /*METHOD JavaGraph.Node */ /* Returns the incoming arc associated with a given key. */
  public Arc incomingArc(long agKey) { return ((Arc)(atIncomingX.get(new Long(agKey)))); }
  //-------------------------------------------------------------------------------------OutgoingArc
  /*METHOD JavaGraph.Node */ /* Returns the outgoing arc associated with a given key. */
  public Arc outgoingArc(long agKey) { return ((Arc)(atOutgoingX.get(new Long(agKey)))); }
  //----------------------------------------------------------------------------------AddIncomingArc
  protected void addIncomingArc(Arc agArc) { atIncomingX.put(new Long(agArc.key()),agArc); }
  //----------------------------------------------------------------------------------AddOutgoingArc
  protected void addOutgoingArc(Arc agArc) { atOutgoingX.put(new Long(agArc.key()),agArc); }
  //-------------------------------------------------------------------------------RemoveIncomingArc
  protected void removeIncomingArc(Arc agArc) { atIncomingX.remove(new Long(agArc.key())); }
  //-------------------------------------------------------------------------------RemoveOutgoingArc
  protected void removeOutgoingArc(Arc agArc) { atOutgoingX.remove(new Long(agArc.key())); }
  //----------------------------------------------------------------------------------------ToString
  /*METHOD JavaGraph.Node */ /* Returns a string that fully describes the state of the node. */
  public String toString() { return ("node "+atKey+" = "+atName+" ; "+super.toString()); }
  //--------------------------------------------------------------------------------------FromString
  /*METHOD JavaGraph.Node */
  /* Changes the state of the node according to the description provided by a given string. */
  public void fromString(String agString) throws Exception {
   String lcString;

   StringTokenizer lcTokenizer = new StringTokenizer(agString);

   lcString=lcTokenizer.nextToken();

   if (!lcString.equals("node"))
    throw new Exception("Graph - Can't extract node information from string.");

   lcTokenizer.nextToken();
   lcTokenizer.nextToken();
   lcString=lcTokenizer.nextToken();
   atName=(lcString.equals(";") ? "" : lcString);
   super.fromString(agString.substring(agString.lastIndexOf(" ; ")+3));
  }
 }
}

// End //-------------------------------------------------------------------------------------------